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

Reply via email to