diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -702,8 +702,13 @@ if bmarkchanges: bmarks.applychanges(repo, tr, bmarkchanges) - # Obsolete or strip nodes - if obsolete.isenabled(repo, obsolete.createmarkersopt): + # We either create obsolescence markers or strip. + # If we create markers and we're in local only mode, we create a backup + # bundle. + obsopts = obsolete.getoptions(repo) + + if (obsopts[obsolete.createmarkersopt] or + obsopts[obsolete.localonlymodeopt]): # If a node is already obsoleted, and we want to obsolete it # without a successor, skip that obssolete request since it's # unnecessary. That's the "if s or not isobs(n)" check below. @@ -717,8 +722,36 @@ for n, s in sorted(replacements.items(), key=sortfunc) if s or not isobs(n)] if rels: + # For now, explicitly limit which operations opt in to this + # behavior. Also, we need to run this code before markers are + # created, otherwise visibility changes would impact operation. + if operation == 'amend' and obsopts[obsolete.localonlymodeopt]: + from . import repair # avoid import cycle + + # We should not be creating unstable changesets in + # local only mode. Verify that. + oldrevs = set(torev(n) for n in replacements) + tobundle = set(repo.revs('%ld::', oldrevs)) + + if len(tobundle) > len(oldrevs): + raise error.Abort(_('cannot create unstable changesets ' + 'in local-only obsolescence mode')) + + roots = set(ctx.node() + for ctx in repo.set('roots(%ld)', oldrevs)) + heads = set(ctx.node() + for ctx in repo.set('heads(%ld)', oldrevs)) + + backupfile = repair.backupbundle( + repo, roots, heads, repo[min(roots)].node(), operation) + repo.ui.status(_('saved backup bundle to %s\n') % + repo.vfs.join(backupfile)) + repo.ui.log('backupbundle', 'saved backup bundle to %s\n', + repo.vfs.join(backupfile)) + obsolete.createmarkers(repo, rels, operation=operation, metadata=metadata) + else: from . import repair # avoid import cycle tostrip = list(replacements) diff --git a/tests/test-amend.t b/tests/test-amend.t --- a/tests/test-amend.t +++ b/tests/test-amend.t @@ -1,4 +1,4 @@ -#testcases obsstore-off obsstore-on +#testcases obsstore-off obsstore-on evolution-on $ cat << EOF >> $HGRCPATH > [extensions] @@ -8,10 +8,17 @@ > git=1 > EOF -#if obsstore-on +#if obsstore-off + $ cat << EOF >> $HGRCPATH + > [ui] + > localobsolescence = false + > EOF +#endif + +#if evolution-on $ cat << EOF >> $HGRCPATH > [experimental] - > evolution.createmarkers=True + > evolution.createmarkers = true > EOF #endif @@ -49,6 +56,8 @@ +A \ No newline at end of file + $ hg debugobsolete + #else $ hg log -p -G --hidden -T '{rev} {node|short} {desc}\n' @ 2 be169c7e8dbe B @@ -77,6 +86,95 @@ +A \ No newline at end of file + + $ hg debugobsolete + 112478962961147124edd43549aedd1a335e44bf be169c7e8dbe21cd10b3d79691cbe7f241e3c21c 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'} + +#endif + +Unbundling from backup bundle restores visibility + +#if obsstore-on + + $ cd .. + $ cp -r repo1 repo1-unbundle-backup + $ cd repo1-unbundle-backup + + $ hg unbundle .hg/strip-backup/112478962961-7e959a55-amend.hg + adding changesets + adding manifests + adding file changes + added 0 changesets with 0 changes to 1 files + (run 'hg update' to get a working copy) + +TODO obsmarker should be deleted, both versions should be visible + + $ hg debugobsolete + 112478962961147124edd43549aedd1a335e44bf be169c7e8dbe21cd10b3d79691cbe7f241e3c21c 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'} + + $ hg log -G + @ changeset: 2:be169c7e8dbe + | tag: tip + | parent: 0:426bada5c675 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: B + | + | x changeset: 1:112478962961 + |/ tag: B + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | obsolete: rewritten using amend as 2:be169c7e8dbe + | summary: B + | + o changeset: 0:426bada5c675 + tag: A + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: A + + + $ cd .. + +Pulling from a backup bundle restores visibility + + $ cp -r repo1 repo1-pull-backup + $ cd repo1-pull-backup + + $ hg pull .hg/strip-backup/112478962961-7e959a55-amend.hg + pulling from .hg/strip-backup/112478962961-7e959a55-amend.hg + searching for changes + no changes found + +TODO obsmarker should be deleted, both versions should be visible + + $ hg debugobsolete + 112478962961147124edd43549aedd1a335e44bf be169c7e8dbe21cd10b3d79691cbe7f241e3c21c 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'} + + $ hg log -G + @ changeset: 2:be169c7e8dbe + | tag: tip + | parent: 0:426bada5c675 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: B + | + | x changeset: 1:112478962961 + |/ tag: B + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | obsolete: rewritten using amend as 2:be169c7e8dbe + | summary: B + | + o changeset: 0:426bada5c675 + tag: A + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: A + + + $ cd ../repo1 + #endif Nothing changed @@ -174,7 +272,7 @@ abort: cannot amend changeset with children [255] -#if obsstore-on +#if evolution-on With allowunstable, amend could work in the middle of a stack