# HG changeset patch # User Pierre-Yves David # Date 1399796222 25200 # Node ID 306f67906a6c002dc4a360b2148977957dc6b408 # Parent be39695cbfdab911e24dc2eb1a8a2b9e2589a359# Parent 154510dc431875863ea64421fad63b495f1fe3d9 merge with all other change to 3.3 diff -r be39695cbfda -r 306f67906a6c .hgtags --- a/.hgtags Sun May 11 01:14:34 2014 -0700 +++ b/.hgtags Sun May 11 01:17:02 2014 -0700 @@ -19,3 +19,5 @@ 862b6b71a35836e81f090ba7229c2888e8ed2f9f 3.0.0 cdb52bbbe5b8770d5e68943b7e73bee4ba136ecc 3.1.0 c3ba8a965a7a173e388d84819e936ea9bae9797f 3.2.0 +83882f2fbecba0b7e7f7e5d490b57db93bd7fa22 3.3.0 +fc04758ea9f549684989ee673b04d9724756dc85 3.3.1 diff -r be39695cbfda -r 306f67906a6c README --- a/README Sun May 11 01:14:34 2014 -0700 +++ b/README Sun May 11 01:17:02 2014 -0700 @@ -29,7 +29,12 @@ ========== The simplest way to contribute is to issue a pull request on Bitbucket -(https://bitbucket.org/marmoute/mutable-history). +(https://bitbucket.org/marmoute/mutable-history). Please don't forget +to update and run the tests when you fix a bug or add a feature. To +run the tests: + + cd tests + python run-tests.py --with-hg=/path/to/hg However, some cutting-edge changes may be found in a mutable repository hosted by logilab before they are published. @@ -42,9 +47,24 @@ Changelog ========= -3.3.0 -- +3.3.2 -- + +- fix a bug where evolve were creating changeset with 2 parents on windows + (fix issues #16, #35 and #42) + +3.3.1 -- 2014-04-23 + +- various language fix +- active bookmark now move when using prev/next (#37) +- fix some preservation of rename information on evolve (#33) +- abort when evolve tries to move a node on top of itself (will helps on the #35 front) +- fold: enable --date and --user options + +3.3.0 -- 2014-03-04 - raise Mercurial's minimal requirement to 2.7 +- drop `latercomer` and `conflicting` compatibility. Those old alias are + deprecated for a long time now. - add verbose hint about how to handle corner case by hand. This should help people until evolve is able to to it itself. - removed the qsync extension. The only user I knew about (logilab) is not diff -r be39695cbfda -r 306f67906a6c hgext/evolve.py --- a/hgext/evolve.py Sun May 11 01:14:34 2014 -0700 +++ b/hgext/evolve.py Sun May 11 01:17:02 2014 -0700 @@ -6,7 +6,7 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -'''Extends Mercurial feature related to Changeset Evolution +'''extends Mercurial feature related to Changeset Evolution This extension provides several commands to mutate history and deal with issues it may raise. @@ -19,7 +19,7 @@ - improves some aspect of the early implementation in 2.3 ''' -testedwith = '2.7 2.7.1 2.7.2 2.8 2.8.1' +testedwith = '2.7 2.7.1 2.7.2 2.8 2.8.1 2.8.2 2.9 2.9.1 2.9.2 3.0' buglink = 'https://bitbucket.org/marmoute/mutable-history/issues' import sys @@ -326,34 +326,6 @@ getrevs = obsolete.getrevs ##################################################################### -### Complete troubles computation logic ### -##################################################################### - - -### Cache computation -latediff = 1 # flag to prevent taking late comer fix into account - -### changectx method - -@eh.addattr(context.changectx, 'latecomer') -def latecomer(ctx): - """is the changeset bumped (Try to succeed to public change)""" - return ctx.bumped() - -@eh.addattr(context.changectx, 'conflicting') -def conflicting(ctx): - """is the changeset divergent (Try to succeed to public change)""" - return ctx.divergent() - -### revset symbol - -eh.revset('latecomer')(revset.symbols['bumped']) -eh.revset('conflicting')(revset.symbols['divergent']) - - - - -##################################################################### ### Additional Utilities ### ##################################################################### @@ -766,6 +738,12 @@ def relocate(repo, orig, dest): """rewrite on dest""" try: + if orig.rev() == dest.rev(): + raise util.Abort(_('tried to relocade a node on top of itself'), + hint=_("This shouldn't happen. If you still " + "need to move changesets, please do so " + "manually with nothing to rebase - working directory parent is also destination")) + rebase = extensions.find('rebase') # dummy state to trick rebase node if not orig.p2().rev() == node.nullrev: @@ -773,15 +751,18 @@ 'no support for evolution merge changesets yet', hint="Redo the merge a use `hg prune` to obsolete the old one") destbookmarks = repo.nodebookmarks(dest.node()) - cmdutil.duplicatecopies(repo, orig.node(), dest.node()) nodesrc = orig.node() destphase = repo[nodesrc].phase() + wlock = lock = None try: + wlock = repo.wlock() + lock = repo.lock() r = rebase.rebasenode(repo, orig.node(), dest.node(), {node.nullrev: node.nullrev}, False) if r[-1]: #some conflict raise util.Abort( 'unresolved merge conflicts (see hg help resolve)') + cmdutil.duplicatecopies(repo, orig.node(), dest.node()) nodenew = rebase.concludenode(repo, orig.node(), dest.node(), node.nullid) except util.Abort, exc: @@ -789,6 +770,8 @@ pass exc.__class__ = LocalMergeFailure raise + finally: + lockmod.release(lock, wlock) oldbookmarks = repo.nodebookmarks(nodesrc) if nodenew is not None: phases.retractboundary(repo, destphase, [nodenew]) @@ -842,7 +825,7 @@ @command('^evolve|stabilize|solve', - [('n', 'dry-run', False, 'do not perform actions, print what to be done'), + [('n', 'dry-run', False, 'do not perform actions, just print what would be done'), ('A', 'any', False, 'evolve any troubled changeset'), ('a', 'all', False, 'evolve all troubled changesets'), ('c', 'continue', False, 'continue an interrupted evolution'), ], @@ -850,13 +833,13 @@ def evolve(ui, repo, **opts): """Solve trouble in your repository - - rebase unstable changeset to make it stable again, - - create proper diff from bumped changeset, - - merge divergent changesets. + - rebase unstable changesets to make them stable again, + - create proper diffs from bumped changesets, + - merge divergent changesets, - update to a successor if the working directory parent is obsolete - By default, take the first trouble changeset that looks relevant. + By default, takes the first troubled changeset that looks relevant. (The logic is still a bit fuzzy) @@ -866,7 +849,7 @@ - For divergent, this means taking "." if applicable. - With --any, evolve picks any troubled changeset to solve. + With --any, evolve picks any troubled changeset to repair. The working directory is updated to the newly created revision. """ @@ -1154,7 +1137,7 @@ else: phases.retractboundary(repo, bumped.phase(), [newid]) createmarkers(repo, [(tmpctx, (repo[newid],))], - flag=latediff) + flag=obsolete.bumpedfix) bmupdate(newid) tr.close() repo.ui.status(_('commited as %s\n') % node.short(newid)) @@ -1305,7 +1288,12 @@ displayer = cmdutil.show_changeset(ui, repo, {'template': shorttemplate}) if len(parents) == 1: p = parents[0] - hg.update(repo, p.rev()) + bm = bookmarks.readcurrent(repo) + shouldmove = bm is not None and bookmarks.iscurrent(repo, bm) + ret = hg.update(repo, p.rev()) + if not ret and shouldmove: + repo._bookmarks[bm] = p.node() + repo._bookmarks.write() displayer.show(p) return 0 else: @@ -1331,7 +1319,12 @@ return 1 if len(children) == 1: c = children[0] - hg.update(repo, c.rev()) + bm = bookmarks.readcurrent(repo) + shouldmove = bm is not None and bookmarks.iscurrent(repo, bm) + ret = hg.update(repo, c.rev()) + if not ret and shouldmove: + repo._bookmarks[bm] = c.node() + repo._bookmarks.write() displayer.show(c) return 0 else: @@ -1393,22 +1386,22 @@ _('[OPTION] [-r] REV...')) # -U --noupdate option to prevent wc update and or bookmarks update ? def cmdprune(ui, repo, *revs, **opts): - """get rid of changesets by marking them obsolete + """hide changesets by marking them obsolete Obsolete changesets becomes invisible to all commands. - Non-pruned descendant of pruned changesets becomes "unstable". Use the + Unpruned descendants of pruned changesets becomes "unstable". Use the :hg:`evolve` to handle such situation. - When the working directory parent is pruned the repository is updated to a - non obsolete parents. + When the working directory parent is pruned, the repository is updated to a + non-obsolete parent. - You can use the ``--succ`` option to informs mercurial that a newer version + You can use the ``--succ`` option to inform mercurial that a newer version of the pruned changeset exists. You can use the ``--biject`` option to specify a 1-1 (bijection) between revisions to prune and successor changesets. This option may be removed in - a future release (with the functionality absored automatically). + a future release (with the functionality absorbed automatically). """ revs = set(scmutil.revrange(repo, list(revs) + opts.get('rev'))) @@ -1436,7 +1429,7 @@ for p in sortedrevs(revs): cp = repo[p] if not cp.mutable(): - # note: create marker would had raise something anyway + # note: createmarkers() would have raised something anyway raise util.Abort('cannot prune immutable changeset: %s' % cp, hint='see "hg help phases" for details') precs.append(cp) @@ -1606,13 +1599,13 @@ def uncommit(ui, repo, *pats, **opts): """move changes from parent revision to working directory - Changes to selected files in parent revision appear again as + Changes to selected files in the checked out revision appear again as uncommitted changed in the working directory. A new revision - without selected changes is created, becomes the new parent and - obsoletes the previous one. + without the selected changes is created, becomes the checked out + revision, and obsoletes the previous one. - The --include option specify pattern to uncommit - The --exclude option specify pattern to keep in the commit + The --include option specifies patterns to uncommit. + The --exclude option specifies patterns to keep in the commit. Return 0 if changed files are uncommitted. """ @@ -1648,7 +1641,7 @@ updatebookmarks(newid) if not repo[newid].files(): ui.warn(_("new changeset is empty\n")) - ui.status(_('(use "hg kill ." to remove it)\n')) + ui.status(_('(use "hg prune ." to remove it)\n')) finally: wlock.release() finally: @@ -1690,7 +1683,7 @@ # allow to choose the seed ? _('[-r] revs')) def touch(ui, repo, *revs, **opts): - """Create successors with exact same property but hash + """Create successors that are identical to their predecessors except for the changeset ID This is used to "resurrect" changesets """ @@ -1740,16 +1733,16 @@ @command('^fold', [('r', 'rev', [], _("explicitly specify the full set of revision to fold")), - ], + ] + commitopts2, # allow to choose the seed ? _('rev')) def fold(ui, repo, *revs, **opts): """Fold multiple revisions into a single one - Revision from your current working directory to the specified one are fold - as a new one replacing the other + The revisions from your current working directory to the given one are folded + into a single successor revision. - you can alternatively use --rev to explicitly specify revision to be fold + you can alternatively use --rev to explicitly specify revisions to be folded, ignoring the current working directory parent. """ revs = list(revs) @@ -1781,12 +1774,13 @@ lock = repo.lock() tr = repo.transaction('touch') try: + commitopts = opts.copy() allctx = [repo[r] for r in revs] targetphase = max(c.phase() for c in allctx) msgs = ["HG: This is a fold of %d changesets." % len(allctx)] msgs += ["HG: Commit message of changeset %s.\n\n%s\n" % (c.rev(), c.description()) for c in allctx] - commitopts = {'message': "\n".join(msgs)} + commitopts['message'] = "\n".join(msgs) commitopts['edit'] = True newid, _ = rewrite(repo, root, allctx, head, [root.p1().node(), root.p2().node()], diff -r be39695cbfda -r 306f67906a6c setup.py --- a/setup.py Sun May 11 01:14:34 2014 -0700 +++ b/setup.py Sun May 11 01:17:02 2014 -0700 @@ -5,10 +5,10 @@ setup( name='hg-evolve', - version='3.2.0', + version='3.3.1', author='Pierre-Yves David', maintainer='Pierre-Yves David', - maintainer_email='pierre-yves.david@logilab.fr', + maintainer_email='pierre-yves.david@ens-lyon.org', url='https://bitbucket.org/marmoute/mutable-history', description='Flexible evolution of Mercurial history.', long_description=open('README').read(), diff -r be39695cbfda -r 306f67906a6c tests/run-tests.py diff -r be39695cbfda -r 306f67906a6c tests/test-evolve.t --- a/tests/test-evolve.t Sun May 11 01:14:34 2014 -0700 +++ b/tests/test-evolve.t Sun May 11 01:17:02 2014 -0700 @@ -1,6 +1,7 @@ $ cat >> $HGRCPATH < [defaults] > amend=-d "0 0" + > fold=-d "0 0" > [web] > push_ssl = false > allow_push = * @@ -593,7 +594,7 @@ 2 changesets folded 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ glog - @ 11:*@default(draft) add 1 (glob) + @ 11:dd4682c1a481@default(draft) add 1 | o 5:0b9e50c35132@default(draft) add 3 | @@ -615,16 +616,20 @@ $ hg up 4 0 files updated, 0 files merged, 2 files removed, 0 files unresolved - $ hg fold --rev 4::11 + $ hg fold --rev 4::11 --user victor 3 changesets folded 2 files updated, 0 files merged, 0 files removed, 0 files unresolved $ glog - @ 12:*@default(draft) add 4 (glob) + @ 12:d26d339c513f@default(draft) add 4 | | o 1:73d38bb17fd7@default(draft) add 1 |/ o 0:8685c6d34325@default(draft) add 0 + $ hg log --template '{rev}: {author}\n' + 12: victor + 1: test + 0: test $ hg log -r 12 --template '{desc}\n' add 4 @@ -645,3 +650,28 @@ 4 : add 4 - test 5 : add 3 - test 11 : add 1 - test + + +Test evolving renames + + $ hg up null + 0 files updated, 0 files merged, 4 files removed, 0 files unresolved + $ echo a > a + $ hg ci -Am a + adding a + created new head + $ echo b > b + $ hg ci -Am b + adding b + $ hg mv a c + $ hg ci -m c + $ hg kill .^ + 1 changesets pruned + 1 new unstable changesets + $ hg stab --any + move:[15] c + atop:[13] a + $ hg st -C --change=tip + A c + a + R a diff -r be39695cbfda -r 306f67906a6c tests/test-obsolete.t --- a/tests/test-obsolete.t Sun May 11 01:14:34 2014 -0700 +++ b/tests/test-obsolete.t Sun May 11 01:17:02 2014 -0700 @@ -637,7 +637,7 @@ #no produced by 2.3 33d458d86621f3186c40bfccd77652f4a122743e 3734a65252e69ddcced85901647a4f335d40de1e 0 {'date': '* *', 'user': 'test'} (glob) -Check conflict detection +Check divergence detection $ hg up 9468a5f5d8b2 # add obsol_d'' 1 files updated, 0 files merged, 1 files removed, 0 files unresolved @@ -650,7 +650,7 @@ update: (2|9|11) new changesets, (3|9|10) branch heads \(merge\) (re) bumped: 1 changesets $ hg debugobsolete `getid a7a6f2b5d8a5` `getid 50f11e5e3a63` - $ hg log -r 'conflicting()' + $ hg log -r 'divergent()' changeset: 12:6db5e282cb91 parent: 10:2033b4e49474 user: test diff -r be39695cbfda -r 306f67906a6c tests/test-prev-next.t --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-prev-next.t Sun May 11 01:17:02 2014 -0700 @@ -0,0 +1,62 @@ + $ cat >> $HGRCPATH < [extensions] + > hgext.rebase= + > hgext.graphlog= + > EOF + $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH + +hg prev should move active bookmark + $ hg init + $ touch a + $ hg add a + $ hg commit -m 'added a' + $ touch b + $ hg add b + $ hg commit -m 'added b' + $ hg bookmark mark + $ hg bookmarks + * mark 1:6e742c9127b3 + $ hg prev + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + [0] added a + $ hg bookmarks + * mark 0:a154386e50d1 + +hg next should move active bookmark + $ hg next + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + [1] added b + $ hg bookmarks + * mark 1:6e742c9127b3 + +hg next/prev should not interfere with inactive bookmarks + $ touch c + $ hg add c + $ hg commit -m 'added c' + $ hg bookmark -r2 no-move + $ hg prev + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + [1] added b + $ hg bookmarks + * mark 1:6e742c9127b3 + no-move 2:4e26ef31f919 + $ hg next + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + [2] added c + $ hg bookmarks + * mark 2:4e26ef31f919 + no-move 2:4e26ef31f919 + $ hg up 1 + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ hg next + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + [2] added c + $ hg bookmarks + mark 2:4e26ef31f919 + no-move 2:4e26ef31f919 + $ hg prev + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + [1] added b + $ hg bookmarks + mark 2:4e26ef31f919 + no-move 2:4e26ef31f919 diff -r be39695cbfda -r 306f67906a6c tests/test-prune.t --- a/tests/test-prune.t Sun May 11 01:14:34 2014 -0700 +++ b/tests/test-prune.t Sun May 11 01:17:02 2014 -0700 @@ -236,6 +236,7 @@ bookmark 'nostrip' deleted abort: nothing to prune [255] + $ hg tag --remove --local a $ hg prune -B todelete 1 changesets pruned 0 files updated, 0 files merged, 0 files removed, 0 files unresolved @@ -252,6 +253,7 @@ $ hg prune -B delete 3 changesets pruned bookmark 'delete' deleted + $ hg tag --remove --local c $ hg id -ir 6:2702dd0c91e7 abort: unknown revision '2702dd0c91e7'! [255] diff -r be39695cbfda -r 306f67906a6c tests/test-stabilize-result.t --- a/tests/test-stabilize-result.t Sun May 11 01:14:34 2014 -0700 +++ b/tests/test-stabilize-result.t Sun May 11 01:17:02 2014 -0700 @@ -171,7 +171,7 @@ o 0:07f494440405@default(public) bk:[] adda -Stabilize conflicting changesets with same parent +Stabilize divergenent changesets with same parent ================================================= $ rm a.orig @@ -291,7 +291,7 @@ +conflict +babar -Check conflicting during conflicting resolution +Check conflict during divergence resolution ------------------------------------------------- $ hg up --hidden 15 diff -r be39695cbfda -r 306f67906a6c tests/test-tutorial.t --- a/tests/test-tutorial.t Sun May 11 01:14:34 2014 -0700 +++ b/tests/test-tutorial.t Sun May 11 01:17:02 2014 -0700 @@ -436,12 +436,13 @@ move changes from parent revision to working directory - Changes to selected files in parent revision appear again as uncommitted - changed in the working directory. A new revision without selected changes - is created, becomes the new parent and obsoletes the previous one. + Changes to selected files in the checked out revision appear again as + uncommitted changed in the working directory. A new revision without the + selected changes is created, becomes the checked out revision, and + obsoletes the previous one. - The --include option specify pattern to uncommit The --exclude option - specify pattern to keep in the commit + The --include option specifies patterns to uncommit. The --exclude option + specifies patterns to keep in the commit. Return 0 if changed files are uncommitted. @@ -469,15 +470,17 @@ Fold multiple revisions into a single one - Revision from your current working directory to the specified one are fold - as a new one replacing the other + The revisions from your current working directory to the given one are + folded into a single successor revision. - you can alternatively use --rev to explicitly specify revision to be fold - ignoring the current working directory parent. + you can alternatively use --rev to explicitly specify revisions to be + folded, ignoring the current working directory parent. options: -r --rev VALUE [+] explicitly specify the full set of revision to fold + -d --date DATE record the specified date as commit date + -u --user USER record the specified user as committer [+] marked option can be specified multiple times @@ -826,7 +829,7 @@ Handling Divergent amend ---------------------------------------------- -We can detect that multiple diverging/conflicting amendments have been made. +We can detect that multiple diverging amendments have been made. The `evolve` command can solve this situation. But all corner case are not handled now. diff -r be39695cbfda -r 306f67906a6c tests/test-uncommit.t --- a/tests/test-uncommit.t Sun May 11 01:14:34 2014 -0700 +++ b/tests/test-uncommit.t Sun May 11 01:17:02 2014 -0700 @@ -316,7 +316,7 @@ $ hg uncommit e new changeset is empty - (use "hg kill ." to remove it) + (use "hg prune ." to remove it) $ hg debugobsolete 5eb72dbe0cb409d094e3b4ae8eaa30071c1b8730 e8db4aa611f6d5706374288e6898e498f5c44098 0 {'date': '* *', 'user': 'test'} (glob) 5eb72dbe0cb409d094e3b4ae8eaa30071c1b8730 c706fe2c12f83ba5010cb60ea6af3bd1f0c2d6d3 0 {'date': '* *', 'user': 'test'} (glob)