indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers.
REVISION SUMMARY Now that we have a config option for enabling local-only obsolescence, it is time to do something with it. This commit teaches cleanupnodes() - which is called after rewrite operations - to handle local only obsolescence mode. In this mode, we create a backup bundle of the obsoleted changesets - just like what happens if obsolescence is disabled. But we don't strip the repo: we keep the original changesets around in a non-visible state. The new code verifies that no unstable changesets are introduced in local-only obsolescence mode. The new code hackily only runs if the action is "amend." The intent is to make this conditional only on the feature option. However, doing that would have significant test fallout. So we limit to "amend" for now. TODO: - Better test coverage (I think the "(testcase !)" syntax might be subtly wrong by flagging output as optional and not required). - Delete obsolescence markers when we pull and unbundle from the bundle. - Support pulling locally-hidden heads. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2681 AFFECTED FILES mercurial/scmutil.py tests/test-amend.t CHANGE DETAILS 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 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) To: indygreg, #hg-reviewers Cc: mercurial-devel _______________________________________________ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel