--- a/hgext/evolve.py Wed Jun 20 15:28:51 2012 +0200
+++ b/hgext/evolve.py Wed Jun 20 15:57:28 2012 +0200
@@ -180,11 +180,17 @@
rebase.rebasenode(repo, orig.node(), dest.node(),
{node.nullrev: node.nullrev})
nodenew = rebase.concludenode(repo, orig.node(), dest.node(), node.nullid)
- phases.retractboundary(repo, destphase, [nodenew])
- repo.addobsolete(nodenew, nodesrc)
oldbookmarks = repo.nodebookmarks(nodesrc)
- for book in oldbookmarks:
- repo._bookmarks[book] = nodenew
+ if nodenew is not None:
+ phases.retractboundary(repo, destphase, [nodenew])
+ repo.addobsolete(nodenew, nodesrc)
+ for book in oldbookmarks:
+ repo._bookmarks[book] = nodenew
+ else:
+ repo.addobsolete(node.nullid, nodesrc)
+ # Behave like rebase, move bookmarks to dest
+ for book in oldbookmarks:
+ repo._bookmarks[book] = dest.node()
for book in destbookmarks: # restore bookmark that rebase move
repo._bookmarks[book] = dest.node()
if oldbookmarks or destbookmarks:
@@ -219,7 +225,7 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
-@command('^stabilize',
+@command('^stabilize|evolve',
[
('n', 'dry-run', False, 'Do nothing but printing what should be done'),
('A', 'any', False, 'Stabilize unstable change on any topological branch'),
@@ -341,7 +347,7 @@
return 1
-@command('^kill',
+@command('^kill|obsolete',
[
('n', 'new', [], _("New changeset that justify this one to be killed"))
],
--- a/hgext/obsolete.py Wed Jun 20 15:28:51 2012 +0200
+++ b/hgext/obsolete.py Wed Jun 20 15:57:28 2012 +0200
@@ -42,8 +42,11 @@
New commands
------------
-A ``debugobsolete`` command was added. It adds an obsolete relation between two
-nodes.
+Note that rebased changesets are not marked obsolete rather than being stripped
+In this experimental extensions, this is done forcing the --keep option. Trying
+to use the --keep option of rebase with this extensionn this experimental
+extension will cause such a call to abort. Until better releasen please use
+graft command to rebase and copy changesets.
Context object
--------------
@@ -97,6 +100,7 @@
from mercurial.node import hex, bin, short, nullid
from mercurial.lock import release
from mercurial import localrepo
+from mercurial import cmdutil
try:
from mercurial.localrepo import storecache
@@ -221,22 +225,72 @@
rebaseset = repo.revs('%ld - extinct()', rebaseset)
return orig(repo, dest, rebaseset, *ags, **kws)
+def defineparents(orig, repo, rev, target, state, *args, **kwargs):
+ rebasestate = getattr(repo, '_rebasestate', None)
+ if rebasestate is not None:
+ repo._rebasestate = dict(state)
+ repo._rebasetarget = target
+ return orig(repo, rev, target, state, *args, **kwargs)
-def concludenode(orig, repo, rev, *args, **kwargs):
+def concludenode(orig, repo, rev, p1, *args, **kwargs):
"""wrapper for rebase 's concludenode that set obsolete relation"""
- newrev = orig(repo, rev, *args, **kwargs)
- oldnode = repo[rev].node()
- newnode = repo[newrev].node()
- repo.addobsolete(newnode, oldnode)
+ newrev = orig(repo, rev, p1, *args, **kwargs)
+ rebasestate = getattr(repo, '_rebasestate', None)
+ if rebasestate is not None:
+ if newrev is not None:
+ nrev = repo[newrev].rev()
+ else:
+ nrev = p1
+ repo._rebasestate[rev] = nrev
return newrev
-def cmdrebase(orig, repo, ui, *args, **kwargs):
- oldkeep = kwargs.pop('keep', False)
- if oldkeep:
- ui.warn('WARNING --keep option ignored by experimental obsolete extension')
+def cmdrebase(orig, ui, repo, *args, **kwargs):
+ if kwargs.get('keep', False):
+ raise util.Abort(_('rebase --keep option is unsupported with obsolete '
+ 'extension'), hint=_("see 'hg help obsolete'"))
+ kwargs = dict(kwargs)
kwargs['keep'] = True
- return orig(repo, ui, *args, **kwargs)
+ # We want to mark rebased revision as obsolete and set their
+ # replacements if any. Doing it in concludenode() prevents
+ # aborting the rebase, and is not called with all relevant
+ # revisions in --collapse case. Instead, we try to track the
+ # rebase state structure by sampling/updating it in
+ # defineparents() and concludenode(). The obsolete markers are
+ # added from this state after a successful call.
+ repo._rebasestate = {}
+ repo._rebasetarget = None
+ maxrev = len(repo) - 1
+ try:
+ res = orig(ui, repo, *args, **kwargs)
+ if not res and not kwargs.get('abort') and repo._rebasetarget:
+ # We have to tell rewritten revisions from removed
+ # ones. When collapsing, removed revisions are considered
+ # to be collapsed onto the final one, while in the normal
+ # case their are marked obsolete without successor.
+ emptynode = nullid
+ if kwargs.get('collapse'):
+ emptynode = repo[max(repo._rebasestate.values())].node()
+ # Rebased revisions are assumed to be descendants of
+ # targetrev. If a source revision is mapped to targetrev
+ # or to another rebased revision, it must have been
+ # removed.
+ targetrev = repo[repo._rebasetarget].rev()
+ newrevs = set([targetrev])
+ for rev, newrev in sorted(repo._rebasestate.items()):
+ if newrev == -2: # nullmerge
+ continue
+ oldnode = repo[rev].node()
+ if newrev not in newrevs and newrev >= 0:
+ newnode = repo[newrev].node()
+ newrevs.add(newrev)
+ else:
+ newnode = emptynode
+ repo.addobsolete(newnode, oldnode)
+ return res
+ finally:
+ delattr(repo, '_rebasestate')
+ delattr(repo, '_rebasetarget')
def extsetup(ui):
@@ -253,6 +307,7 @@
rebase = extensions.find('rebase')
if rebase:
extensions.wrapfunction(rebase, 'buildstate', buildstate)
+ extensions.wrapfunction(rebase, 'defineparents', defineparents)
extensions.wrapfunction(rebase, 'concludenode', concludenode)
extensions.wrapcommand(rebase.cmdtable, "rebase", cmdrebase)
except KeyError:
@@ -385,11 +440,15 @@
### New commands
#############################
+cmdtable = {}
+command = cmdutil.command(cmdtable)
+@command('debugobsolete', [], _('SUBJECT OBJECT'))
def cmddebugobsolete(ui, repo, subject, object):
- """Add an obsolete relation between a too node
+ """add an obsolete relation between two nodes
- The subject is expected to be a newer version of the object"""
+ The subject is expected to be a newer version of the object.
+ """
lock = repo.lock()
try:
sub = repo[subject]
@@ -399,7 +458,9 @@
lock.release()
return 0
+@command('debugconvertobsolete', [], '')
def cmddebugconvertobsolete(ui, repo):
+ """import markers from an .hg/obsolete-relations file"""
cnt = 0
l = repo.lock()
try:
@@ -433,10 +494,25 @@
l.release()
ui.status('%i obsolete marker converted\n' % cnt)
+@command('debugsuccessors', [], '')
+def cmddebugsuccessors(ui, repo):
+ """dump obsolete changesets and their successors
-cmdtable = {'debugobsolete': (cmddebugobsolete, [], '<subject> <object>'),
- 'debugconvertobsolete': (cmddebugconvertobsolete, [], ''),
- }
+ Each line matches an existing marker, the first identifier is the
+ obsolete changeset identifier, followed by it successors.
+ """
+ lock = repo.lock()
+ try:
+ allsuccessors = repo.obsoletestore.objects
+ for old in sorted(allsuccessors):
+ successors = [sorted(m['subjects']) for m in allsuccessors[old]]
+ for i, group in enumerate(sorted(successors)):
+ ui.write('%s' % short(old))
+ for new in group:
+ ui.write(' %s' % short(new))
+ ui.write('\n')
+ finally:
+ lock.release()
### Altering existing command
#############################
--- a/tests/test-amend.t Wed Jun 20 15:28:51 2012 +0200
+++ b/tests/test-amend.t Wed Jun 20 15:57:28 2012 +0200
@@ -24,6 +24,10 @@
marked working directory as branch foo
(branches are permanent and global, did you want a bookmark?)
$ hg amend
+ $ hg debugsuccessors
+ 07f494440405 a34b93d251e4
+ 07f494440405 bd19cbe78fbf
+ bd19cbe78fbf a34b93d251e4
$ hg branch
foo
$ hg branches
@@ -59,6 +63,10 @@
$ hg amend --change 2
abort: no updates found
[255]
+ $ hg debugsuccessors
+ 07f494440405 a34b93d251e4
+ 07f494440405 bd19cbe78fbf
+ bd19cbe78fbf a34b93d251e4
$ hg phase 2
2: draft
$ glog
@@ -82,6 +90,11 @@
$ hg amend --change 2
abort: no updates found
[255]
+ $ hg debugsuccessors
+ 07f494440405 a34b93d251e4
+ 07f494440405 bd19cbe78fbf
+ 7384bbcba36f 000000000000
+ bd19cbe78fbf a34b93d251e4
$ glog
@ 6@foo(secret) amends a34b93d251e49c93d5685ebacad785c73a7e8605
|
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-obsolete-rebase.t Wed Jun 20 15:57:28 2012 +0200
@@ -0,0 +1,186 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [defaults]
+ > amend=-d "0 0"
+ > [extensions]
+ > hgext.rebase=
+ > hgext.graphlog=
+ > EOF
+ $ echo "obsolete=$(echo $(dirname $TESTDIR))/hgext/obsolete.py" >> $HGRCPATH
+
+ $ glog() {
+ > hg glog --template '{rev}:{node|short}@{branch}({phase}) {desc|firstline}\n'\
+ > "$@"
+ > }
+
+ $ hg init repo
+ $ cd repo
+ $ echo a > a
+ $ hg ci -Am adda
+ adding a
+ $ echo a >> a
+ $ hg ci -m changea
+
+Test regular rebase
+
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo b > b
+ $ hg ci -Am addb
+ adding b
+ created new head
+ $ echo e > e
+ $ hg ci -Am adde e
+ $ hg rebase -d 1 -r . --detach --keep
+ abort: rebase --keep option is unsupported with obsolete extension
+ (see 'hg help obsolete')
+ [255]
+ $ hg rebase -d 1 -r . --detach
+ $ glog --hidden
+ @ 4:9c5494949763@default(draft) adde
+ |
+ | o 3:98e4a024635e@default(secret) adde
+ | |
+ | o 2:102a90ea7b4a@default(draft) addb
+ | |
+ o | 1:540395c44225@default(draft) changea
+ |/
+ o 0:07f494440405@default(draft) adda
+
+ $ hg debugsuccessors
+ 98e4a024635e 9c5494949763
+
+Test rebase with deleted empty revision
+
+ $ hg up 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg branch foo
+ marked working directory as branch foo
+ (branches are permanent and global, did you want a bookmark?)
+ $ echo a >> a
+ $ hg ci -m changea
+ $ hg rebase -d 1
+ $ glog --hidden
+ o 5:4e322f7ce8e3@foo(secret) changea
+ |
+ | o 4:9c5494949763@default(draft) adde
+ | |
+ | | o 3:98e4a024635e@default(secret) adde
+ | | |
+ +---o 2:102a90ea7b4a@default(draft) addb
+ | |
+ | @ 1:540395c44225@default(draft) changea
+ |/
+ o 0:07f494440405@default(draft) adda
+
+ $ hg debugsuccessors
+ 4e322f7ce8e3 000000000000
+ 98e4a024635e 9c5494949763
+
+Test rebase --collapse
+
+ $ hg up 0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo c > c
+ $ hg ci -Am addc
+ adding c
+ created new head
+ $ echo c >> c
+ $ hg ci -m changec
+ $ hg rebase --collapse -d 1
+ merging c
+ $ glog --hidden
+ @ 8:a7773ffa7edc@default(draft) Collapsed revision
+ |
+ | o 7:03f31481307a@default(secret) changec
+ | |
+ | o 6:076e9b2ffbe1@default(secret) addc
+ | |
+ | | o 5:4e322f7ce8e3@foo(secret) changea
+ | |/
+ +---o 4:9c5494949763@default(draft) adde
+ | |
+ | | o 3:98e4a024635e@default(secret) adde
+ | | |
+ | | o 2:102a90ea7b4a@default(draft) addb
+ | |/
+ o | 1:540395c44225@default(draft) changea
+ |/
+ o 0:07f494440405@default(draft) adda
+
+ $ hg debugsuccessors
+ 03f31481307a a7773ffa7edc
+ 076e9b2ffbe1 a7773ffa7edc
+ 4e322f7ce8e3 000000000000
+ 98e4a024635e 9c5494949763
+
+Test rebase --abort
+
+ $ hg debugsuccessors > ../successors.old
+ $ hg up 0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo d > d
+ $ hg ci -Am addd d
+ created new head
+ $ echo b >> a
+ $ hg ci -m appendab
+ $ hg rebase -d 1
+ merging a
+ warning: conflicts during merge.
+ merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
+ abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
+ [255]
+ $ hg rebase --abort
+ saved backup bundle to $TESTTMP/repo/.hg/strip-backup/03f165c84ea8-backup.hg
+ rebase aborted
+ $ hg debugsuccessors > ../successors.new
+ $ diff -u ../successors.old ../successors.new
+
+Test rebase --continue
+
+ $ hg rebase -d 1
+ merging a
+ warning: conflicts during merge.
+ merging a incomplete! (edit conflicts, then use 'hg resolve --mark')
+ abort: unresolved conflicts (see hg resolve, then hg rebase --continue)
+ [255]
+ $ hg resolve --tool internal:other a
+ $ hg rebase --continue
+ $ glog --hidden
+ @ 12:1951ead97108@default(draft) appendab
+ |
+ o 11:03f165c84ea8@default(draft) addd
+ |
+ | o 10:4b9d80f48523@default(secret) appendab
+ | |
+ | o 9:a31943eabc43@default(secret) addd
+ | |
+ +---o 8:a7773ffa7edc@default(draft) Collapsed revision
+ | |
+ | | o 7:03f31481307a@default(secret) changec
+ | | |
+ | | o 6:076e9b2ffbe1@default(secret) addc
+ | |/
+ | | o 5:4e322f7ce8e3@foo(secret) changea
+ | |/
+ +---o 4:9c5494949763@default(draft) adde
+ | |
+ | | o 3:98e4a024635e@default(secret) adde
+ | | |
+ | | o 2:102a90ea7b4a@default(draft) addb
+ | |/
+ o | 1:540395c44225@default(draft) changea
+ |/
+ o 0:07f494440405@default(draft) adda
+
+ $ hg debugsuccessors > ../successors.new
+ $ diff -u ../successors.old ../successors.new
+ --- ../successors.old* (glob)
+ +++ ../successors.new* (glob)
+ @@ -1,4 +1,6 @@
+ 03f31481307a a7773ffa7edc
+ 076e9b2ffbe1 a7773ffa7edc
+ +4b9d80f48523 1951ead97108
+ 4e322f7ce8e3 000000000000
+ 98e4a024635e 9c5494949763
+ +a31943eabc43 03f165c84ea8
+ [1]
--- a/tests/test-obsolete.t Wed Jun 20 15:28:51 2012 +0200
+++ b/tests/test-obsolete.t Wed Jun 20 15:57:28 2012 +0200
@@ -453,3 +453,4 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
+ $ cd ..
--- a/tests/test-stabilize-order.t Wed Jun 20 15:28:51 2012 +0200
+++ b/tests/test-stabilize-order.t Wed Jun 20 15:57:28 2012 +0200
@@ -88,6 +88,7 @@
$ hg up 7
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg debugsuccessors > successors.old
$ hg stabilize -v
move:[3] addc
atop:[8] addb
@@ -97,6 +98,18 @@
resolving manifests
getting c
c
+ $ hg debugsuccessors > successors.new
+ $ diff -u successors.old successors.new
+ --- successors.old* (glob)
+ +++ successors.new* (glob)
+ @@ -1,5 +1,6 @@
+ 3a4a591493f8 f5ff10856e5a
+ 3ca0ded0dc50 ab8cbb6d87ff
+ +7a7552255fb5 5e819fbb0d27
+ 93418d2c0979 3a4a591493f8
+ 93418d2c0979 f5ff10856e5a
+ ab8cbb6d87ff 6bf44048e43f
+ [1]
$ glog
@ 9:5e819fbb0d27@default(draft) addc
|
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-stabilize-result.t Wed Jun 20 15:57:28 2012 +0200
@@ -0,0 +1,52 @@
+ $ cat >> $HGRCPATH <<EOF
+ > [defaults]
+ > amend=-d "0 0"
+ > [extensions]
+ > hgext.rebase=
+ > hgext.graphlog=
+ > EOF
+ $ echo "obsolete=$(echo $(dirname $TESTDIR))/hgext/obsolete.py" >> $HGRCPATH
+ $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH
+
+ $ glog() {
+ > hg glog --template \
+ > '{rev}:{node|short}@{branch}({phase}) bk:[{bookmarks}] {desc|firstline}\n' "$@"
+ > }
+
+Test stabilize removing the changeset being stabilized
+
+ $ hg init empty
+ $ cd empty
+ $ echo a > a
+ $ hg ci -Am adda a
+ $ echo b > b
+ $ hg ci -Am addb b
+ $ echo a >> a
+ $ hg ci -m changea
+ $ hg bookmark changea
+ $ hg up 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo a >> a
+ $ hg amend -m changea
+ 1 new unstables changesets
+ $ hg stabilize -v
+ move:[2] changea
+ atop:[4] changea
+ hg rebase -Dr cce2c55b8965 -d 1447e1c4828d
+ resolving manifests
+ $ glog --hidden
+ @ 4:1447e1c4828d@default(draft) bk:[changea] changea
+ |
+ | o 3:41ad4fe8c795@default(secret) bk:[] amends 102a90ea7b4a3361e4082ed620918c261189a36a
+ | |
+ | | o 2:cce2c55b8965@default(secret) bk:[] changea
+ | |/
+ | o 1:102a90ea7b4a@default(secret) bk:[] addb
+ |/
+ o 0:07f494440405@default(draft) bk:[] adda
+
+ $ hg debugsuccessors
+ 102a90ea7b4a 1447e1c4828d
+ 102a90ea7b4a 41ad4fe8c795
+ 41ad4fe8c795 1447e1c4828d
+ cce2c55b8965 000000000000