# HG changeset patch # User Pierre-Yves David # Date 1340200648 -7200 # Node ID d3f20770b86a31dba56ae7b252089e12b34702da # Parent a68b763505c2466dd61dc6e1485448c4deaf316f# Parent 691cb55358b05323db7000edefd1f59b688b8bcd Merge with Patrick improvement diff -r a68b763505c2 -r d3f20770b86a hgext/evolve.py --- 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")) ], diff -r a68b763505c2 -r d3f20770b86a hgext/obsolete.py --- 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, [], ' '), - '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 ############################# diff -r a68b763505c2 -r d3f20770b86a tests/test-amend.t --- 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 | diff -r a68b763505c2 -r d3f20770b86a tests/test-obsolete-rebase.t --- /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 < [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] diff -r a68b763505c2 -r d3f20770b86a tests/test-obsolete.t --- 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 .. diff -r a68b763505c2 -r d3f20770b86a tests/test-stabilize-order.t --- 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 | diff -r a68b763505c2 -r d3f20770b86a tests/test-stabilize-result.t --- /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 < [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