Patchwork [4,of,4] obsolete: allow cycles

login
register
mail settings
Submitter Jun Wu
Date March 13, 2017, 9:34 a.m.
Message ID <5cf846db23cddc36b01a.1489397659@localhost.localdomain>
Download mbox | patch
Permalink /patch/19278/
State Superseded
Headers show

Comments

Jun Wu - March 13, 2017, 9:34 a.m.
# HG changeset patch
# User Jun Wu <quark@fb.com>
# Date 1489395002 25200
#      Mon Mar 13 01:50:02 2017 -0700
# Node ID 5cf846db23cddc36b01acf0211d52f8d50f36dcd
# Parent  83288095bc38cef4b9e8bb9c69914b981115aaab
# Available At https://bitbucket.org/quark-zju/hg-draft
#              hg pull https://bitbucket.org/quark-zju/hg-draft -r 5cf846db23cd
obsolete: allow cycles

Now we can handle cycles nicely, allow them to be created. Some practical
examples:

  - To revive X, just create a marker X -> X, with a newer date.
  - To prune X again, just create a marker X -> (), with a newer date.
  - The above two could be repeated.

  - To unamend A -> B, just create a marker B -> A, with a newer date.

It's now possible for "touch" and "unamend" to reuse hashes (therefore more
user-friendly). And it's no longer necessary to write "*_source" in commit
metadata to workarounds obs cycles. The hacky inhibit extension also becomes
unnecessary.

Finally. I have been wanting all these for a long time.
Jun Wu - March 13, 2017, 9:44 a.m.
Excerpts from Jun Wu's message of 2017-03-13 02:34:19 -0700:
> # HG changeset patch
> # User Jun Wu <quark@fb.com>
> # Date 1489395002 25200
> #      Mon Mar 13 01:50:02 2017 -0700
> # Node ID 5cf846db23cddc36b01acf0211d52f8d50f36dcd
> # Parent  83288095bc38cef4b9e8bb9c69914b981115aaab
> # Available At https://bitbucket.org/quark-zju/hg-draft 
> #              hg pull https://bitbucket.org/quark-zju/hg-draft  -r 5cf846db23cd
> obsolete: allow cycles
> 
> Now we can handle cycles nicely, allow them to be created. Some practical
> examples:
> 
>   - To revive X, just create a marker X -> X, with a newer date.
>   - To prune X again, just create a marker X -> (), with a newer date.
>   - The above two could be repeated.
> 
>   - To unamend A -> B, just create a marker B -> A, with a newer date.
> 
> It's now possible for "touch" and "unamend" to reuse hashes (therefore more
> user-friendly). And it's no longer necessary to write "*_source" in commit
> metadata to workarounds obs cycles. The hacky inhibit extension also becomes
> unnecessary.
> 
> Finally. I have been wanting all these for a long time.
> 
> diff --git a/mercurial/obsolete.py b/mercurial/obsolete.py
> --- a/mercurial/obsolete.py
> +++ b/mercurial/obsolete.py
> @@ -638,6 +638,4 @@ class obsstore(object):
>              if len(succ) != 20:
>                  raise ValueError(succ)
> -        if prec in succs:
> -            raise ValueError(_('in-marker cycle with %s') % node.hex(prec))
>  
>          metadata = tuple(sorted(metadata.iteritems()))
> @@ -1296,7 +1294,4 @@ def createmarkers(repo, relations, flag=
>              if not nsucs:
>                  npare = tuple(p.node() for p in prec.parents())
> -            if nprec in nsucs:
> -                raise error.Abort(_("changeset %s cannot obsolete itself")
> -                                  % prec)
>  
>              # Creating the marker causes the hidden cache to become invalid,
> diff --git a/tests/test-obsolete-cycle.t b/tests/test-obsolete-cycle.t
> new file mode 100644
> --- /dev/null
> +++ b/tests/test-obsolete-cycle.t
> @@ -0,0 +1,153 @@
> +  $ cat >> $HGRCPATH << EOF
> +  > [ui]
> +  > logtemplate="{rev} {desc}\n"
> +  > [phases]
> +  > publish=false
> +  > [experimental]
> +  > evolution=createmarkers
> +  > [extensions]
> +  > drawdag=$TESTDIR/drawdag.py
> +  > EOF
> +
> +  $ getid() {
> +  >    hg log -T "{node}\n" --hidden -r "desc('$1')"
> +  > }
> +  $ assignnames() {
> +  >   for i in "$@"; do
> +  >       eval $i=`getid $i`
> +  >       # remove local tags created by drawdag
> +  >       hg tag --remove -l $i
> +  >   done
> +  > }
> +
> +Cycle of 2 changesets
> +
> +  $ hg init repo1
> +  $ cd repo1
> +
> +  $ hg debugdrawdag << EOF
> +  >   B C
> +  >   |/
> +  >   A
> +  > EOF
> +
> +  $ assignnames A B C
> +
> +  $ hg debugobsolete -d '0 0' $B $C
> +  $ hg log -G
> +  o  2 C
> +  |
> +  o  0 A
> +  
> +
> +  $ hg debugobsolete -d '1 0' $C $B
> +  $ hg log -G
> +  o  1 B
> +  |
> +  o  0 A
> +  
> +
> +  $ hg debugobsolete -d '2 0' $B $C
> +  $ hg log -G
> +  o  2 C
> +  |
> +  o  0 A
> +  
> +
> +  $ hg debugobsolete -d '3 0' $B $B
> +  $ hg log -G
> +  o  2 C
> +  |
> +  | o  1 B
> +  |/
> +  o  0 A
> +  
> +
> +  $ hg debugobsolete -d '4 0' $B
> +  $ hg debugobsolete -d '6 0' $C
> +  $ hg log -G
> +  o  0 A
> +  
> +
> +  $ hg debugobsolete -d '7 0' $B $B
> +  $ hg debugobsolete -d '5 0' $C $C
> +  $ hg log -G
> +  o  1 B
> +  |
> +  o  0 A
> +  
> +
> +  $ hg debugobsolete -d '8 0' $C $C
> +  $ hg log -G
> +  o  2 C
> +  |
> +  | o  1 B
> +  |/
> +  o  0 A
> +  
> +
> +  $ cd ..
> +
> +Cycle of 3 changesets
> +  $ hg init repo2
> +  $ cd repo2
> +
> +  $ hg debugdrawdag << EOF
> +  > D B C
> +  >  \|/
> +  >   A
> +  > EOF
> +
> +  $ assignnames A B C D
> +
> +  $ hg debugobsolete -d '2 0' $C $D
> +  $ hg debugobsolete -d '3 0' $D $C
> +  $ hg debugobsolete -d '1 0' $B $C
> +
> +  $ hg log -G
> +  o  2 C
> +  |
> +  o  0 A
> +  
> +
> +  $ hg debugobsolete -d '4 0' $D $D
> +  $ hg log -G
> +  o  3 D
> +  |
> +  | o  2 C
> +  |/
> +  o  0 A
> +  
> +
> +  $ hg debugobsolete -d '5 0' $B $B
> +  $ hg log -G
> +  o  3 D
> +  |
> +  | o  2 C
> +  |/
> +  | o  1 B
> +  |/
> +  o  0 A
> +  
> +
> +  $ hg debugobsolete -d '6 0' $D $B
> +  $ hg log -G
> +  o  2 C
> +  |
> +  | o  1 B
> +  |/
> +  o  0 A
> +  
> +  $ hg debugobsolete -d '9 0' $C
> +  $ hg log -G
> +  o  1 B
> +  |
> +  o  0 A
> +  
> +
> +  $ hg debugobsolete -d '8 0' $B $C
> +  $ hg log -G
> +  o  0 A
> +  
> +
> +  $ cd ..
> diff --git a/tests/test-obsolete.t b/tests/test-obsolete.t
> --- a/tests/test-obsolete.t
> +++ b/tests/test-obsolete.t
> @@ -30,10 +30,4 @@
>    $ mkcommit kill_me
>  
> -Checking that the feature is properly disabled
> -
> -  $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
> -  abort: creating obsolete markers is not enabled on this repo
> -  [255]
> -
>  Enabling it

This seems to be a mistake. I'll resend a V2.

>  
> @@ -62,11 +56,4 @@ Killing a single changeset without repla
>    $ hg up --hidden tip --quiet
>  
> -Killing a single changeset with itself should fail
> -(simple local safeguard)
> -
> -  $ hg debugobsolete `getid kill_me` `getid kill_me`
> -  abort: bad obsmarker input: in-marker cycle with 97b7c2d76b1845ed3eb988cd612611e72406cef0
> -  [255]
> -
>    $ cd ..
>

Patch

diff --git a/mercurial/obsolete.py b/mercurial/obsolete.py
--- a/mercurial/obsolete.py
+++ b/mercurial/obsolete.py
@@ -638,6 +638,4 @@  class obsstore(object):
             if len(succ) != 20:
                 raise ValueError(succ)
-        if prec in succs:
-            raise ValueError(_('in-marker cycle with %s') % node.hex(prec))
 
         metadata = tuple(sorted(metadata.iteritems()))
@@ -1296,7 +1294,4 @@  def createmarkers(repo, relations, flag=
             if not nsucs:
                 npare = tuple(p.node() for p in prec.parents())
-            if nprec in nsucs:
-                raise error.Abort(_("changeset %s cannot obsolete itself")
-                                  % prec)
 
             # Creating the marker causes the hidden cache to become invalid,
diff --git a/tests/test-obsolete-cycle.t b/tests/test-obsolete-cycle.t
new file mode 100644
--- /dev/null
+++ b/tests/test-obsolete-cycle.t
@@ -0,0 +1,153 @@ 
+  $ cat >> $HGRCPATH << EOF
+  > [ui]
+  > logtemplate="{rev} {desc}\n"
+  > [phases]
+  > publish=false
+  > [experimental]
+  > evolution=createmarkers
+  > [extensions]
+  > drawdag=$TESTDIR/drawdag.py
+  > EOF
+
+  $ getid() {
+  >    hg log -T "{node}\n" --hidden -r "desc('$1')"
+  > }
+  $ assignnames() {
+  >   for i in "$@"; do
+  >       eval $i=`getid $i`
+  >       # remove local tags created by drawdag
+  >       hg tag --remove -l $i
+  >   done
+  > }
+
+Cycle of 2 changesets
+
+  $ hg init repo1
+  $ cd repo1
+
+  $ hg debugdrawdag << EOF
+  >   B C
+  >   |/
+  >   A
+  > EOF
+
+  $ assignnames A B C
+
+  $ hg debugobsolete -d '0 0' $B $C
+  $ hg log -G
+  o  2 C
+  |
+  o  0 A
+  
+
+  $ hg debugobsolete -d '1 0' $C $B
+  $ hg log -G
+  o  1 B
+  |
+  o  0 A
+  
+
+  $ hg debugobsolete -d '2 0' $B $C
+  $ hg log -G
+  o  2 C
+  |
+  o  0 A
+  
+
+  $ hg debugobsolete -d '3 0' $B $B
+  $ hg log -G
+  o  2 C
+  |
+  | o  1 B
+  |/
+  o  0 A
+  
+
+  $ hg debugobsolete -d '4 0' $B
+  $ hg debugobsolete -d '6 0' $C
+  $ hg log -G
+  o  0 A
+  
+
+  $ hg debugobsolete -d '7 0' $B $B
+  $ hg debugobsolete -d '5 0' $C $C
+  $ hg log -G
+  o  1 B
+  |
+  o  0 A
+  
+
+  $ hg debugobsolete -d '8 0' $C $C
+  $ hg log -G
+  o  2 C
+  |
+  | o  1 B
+  |/
+  o  0 A
+  
+
+  $ cd ..
+
+Cycle of 3 changesets
+  $ hg init repo2
+  $ cd repo2
+
+  $ hg debugdrawdag << EOF
+  > D B C
+  >  \|/
+  >   A
+  > EOF
+
+  $ assignnames A B C D
+
+  $ hg debugobsolete -d '2 0' $C $D
+  $ hg debugobsolete -d '3 0' $D $C
+  $ hg debugobsolete -d '1 0' $B $C
+
+  $ hg log -G
+  o  2 C
+  |
+  o  0 A
+  
+
+  $ hg debugobsolete -d '4 0' $D $D
+  $ hg log -G
+  o  3 D
+  |
+  | o  2 C
+  |/
+  o  0 A
+  
+
+  $ hg debugobsolete -d '5 0' $B $B
+  $ hg log -G
+  o  3 D
+  |
+  | o  2 C
+  |/
+  | o  1 B
+  |/
+  o  0 A
+  
+
+  $ hg debugobsolete -d '6 0' $D $B
+  $ hg log -G
+  o  2 C
+  |
+  | o  1 B
+  |/
+  o  0 A
+  
+  $ hg debugobsolete -d '9 0' $C
+  $ hg log -G
+  o  1 B
+  |
+  o  0 A
+  
+
+  $ hg debugobsolete -d '8 0' $B $C
+  $ hg log -G
+  o  0 A
+  
+
+  $ cd ..
diff --git a/tests/test-obsolete.t b/tests/test-obsolete.t
--- a/tests/test-obsolete.t
+++ b/tests/test-obsolete.t
@@ -30,10 +30,4 @@ 
   $ mkcommit kill_me
 
-Checking that the feature is properly disabled
-
-  $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
-  abort: creating obsolete markers is not enabled on this repo
-  [255]
-
 Enabling it
 
@@ -62,11 +56,4 @@  Killing a single changeset without repla
   $ hg up --hidden tip --quiet
 
-Killing a single changeset with itself should fail
-(simple local safeguard)
-
-  $ hg debugobsolete `getid kill_me` `getid kill_me`
-  abort: bad obsmarker input: in-marker cycle with 97b7c2d76b1845ed3eb988cd612611e72406cef0
-  [255]
-
   $ cd ..