[Updated] D12119: narrow: allow merging non-conflicting change outside of the narrow spec

baymax (Baymax, Your Personal Patch-care Companion) phabricator at mercurial-scm.org
Thu Feb 3 16:56:32 UTC 2022


baymax added a comment.
baymax updated this revision to Diff 32053.


  ✅ refresh by Heptapod after a successful CI run (🐙 💚)

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D12119?vs=32015&id=32053

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D12119/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D12119

AFFECTED FILES
  mercurial/commit.py
  mercurial/merge.py
  tests/test-narrow-merge.t

CHANGE DETAILS

diff --git a/tests/test-narrow-merge.t b/tests/test-narrow-merge.t
--- a/tests/test-narrow-merge.t
+++ b/tests/test-narrow-merge.t
@@ -83,12 +83,67 @@
 TODO: Can merge non-conflicting changes outside narrow spec
 
   $ hg update -q 'desc("modify inside/f1")'
+
+#if flat
+
   $ hg merge 'desc("modify outside/f1")'
-  abort: merge affects file 'outside/f1' outside narrow, which is not yet supported (flat !)
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+
+status should be clean
+
+  $ hg status
+  ? inside/f1.orig
+
+file out of the spec should still not be in the dirstate at all
+
+  $ hg debugdirstate | grep outside/f1
+  [1]
+
+Commit that merge
+
+  $ hg ci -m 'merge from outside to inside'
+
+status should be clean
+
+  $ hg status
+  ? inside/f1.orig
+
+file out of the spec should not be in the mergestate anymore
+
+  $ hg debugmergestate | grep outside/f1
+  [1]
+
+file out of the spec should still not be in the dirstate at all
+
+  $ hg debugdirstate | grep outside/f1
+  [1]
+
+The filenode used should come from p2
+
+  $ hg manifest --debug --rev . | grep outside/f1
+  83cd11431a3b2aff8a3995e5f27bcf33cdb5be98 644   outside/f1
+  $ hg manifest --debug --rev 'p1(.)' | grep outside/f1
+  c6b956c48be2cd4fa94be16002aba311143806fa 644   outside/f1
+  $ hg manifest --debug --rev 'p2(.)' | grep outside/f1
+  83cd11431a3b2aff8a3995e5f27bcf33cdb5be98 644   outside/f1
+
+
+remove the commit to get in the previous situation again
+
+  $ hg debugstrip -r .
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  saved backup bundle to $TESTTMP/narrow/.hg/strip-backup/48eb25338b19-a1bb8350-backup.hg
+
+#else
+
+  $ hg merge 'desc("modify outside/f1")'
   abort: merge affects file 'outside/' outside narrow, which is not yet supported (tree !)
   (merging in the other direction may work)
   [255]
 
+#endif
+
   $ hg update -q 'desc("modify outside/f1")'
   $ hg merge 'desc("modify inside/f1")'
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -518,13 +518,20 @@
             mresult.removefile(f)  # just updating, ignore changes outside clone
         elif action[0].no_op:
             mresult.removefile(f)  # merge does not affect file
-        elif action[0].narrow_safe:  # TODO: handle these cases
-            msg = _(
-                b'merge affects file \'%s\' outside narrow, '
-                b'which is not yet supported'
-            )
-            hint = _(b'merging in the other direction may work')
-            raise error.Abort(msg % f, hint=hint)
+        elif action[0].narrow_safe:
+            if not f.endswith(b'/'):
+                mresult.removefile(f)  # merge won't affect on-disk files
+
+                mresult.addcommitinfo(
+                    f, b'outside-narrow-merge-action', action[0].changes
+                )
+            else:  # TODO: handle the tree case
+                msg = _(
+                    b'merge affects file \'%s\' outside narrow, '
+                    b'which is not yet supported'
+                )
+                hint = _(b'merging in the other direction may work')
+                raise error.Abort(msg % f, hint=hint)
         else:
             msg = _(b'conflict in file \'%s\' is outside narrow clone')
             raise error.StateError(msg % f)
diff --git a/mercurial/commit.py b/mercurial/commit.py
--- a/mercurial/commit.py
+++ b/mercurial/commit.py
@@ -134,7 +134,13 @@
     for s in salvaged:
         files.mark_salvaged(s)
 
-    if ctx.manifestnode():
+    narrow_files = {}
+    if not ctx.repo().narrowmatch().always():
+        for f, e in ms.allextras().items():
+            action = e.get(b'outside-narrow-merge-action')
+            if action is not None:
+                narrow_files[f] = action
+    if ctx.manifestnode() and not narrow_files:
         # reuse an existing manifest revision
         repo.ui.debug(b'reusing known manifest\n')
         mn = ctx.manifestnode()
@@ -142,11 +148,11 @@
         if writechangesetcopy:
             files.update_added(ctx.filesadded())
             files.update_removed(ctx.filesremoved())
-    elif not ctx.files():
+    elif not ctx.files() and not narrow_files:
         repo.ui.debug(b'reusing manifest from p1 (no file change)\n')
         mn = p1.manifestnode()
     else:
-        mn = _process_files(tr, ctx, ms, files, error=error)
+        mn = _process_files(tr, ctx, ms, files, narrow_files, error=error)
 
     if origctx and origctx.manifestnode() == mn:
         origfiles = origctx.files()
@@ -177,7 +183,7 @@
     return salvaged
 
 
-def _process_files(tr, ctx, ms, files, error=False):
+def _process_files(tr, ctx, ms, files, narrow_files=None, error=False):
     repo = ctx.repo()
     p1 = ctx.p1()
     p2 = ctx.p2()
@@ -198,8 +204,33 @@
     linkrev = len(repo)
     repo.ui.note(_(b"committing files:\n"))
     uipathfn = scmutil.getuipathfn(repo)
-    for f in sorted(ctx.modified() + ctx.added()):
+    all_files = ctx.modified() + ctx.added()
+    all_files.extend(narrow_files.keys())
+    all_files.sort()
+    for f in all_files:
         repo.ui.note(uipathfn(f) + b"\n")
+        if f in narrow_files:
+            narrow_action = narrow_files.get(f)
+            if narrow_action == mergestate.CHANGE_REMOVED:
+                files.mark_removed(f)
+                removed.append(f)
+            elif narrow_action == mergestate.CHANGE_REMOVED:
+                files.mark_added(f)
+                added.append(f)
+                m[f] = m2[f]
+                flags = m2ctx.find(f)[1] or b''
+                m.setflag(f, flags)
+            elif narrow_action == mergestate.CHANGE_MODIFIED:
+                files.mark_touched(f)
+                added.append(f)
+                m[f] = m2[f]
+                flags = m2ctx.find(f)[1] or b''
+                m.setflag(f, flags)
+            else:
+                msg = _(b"corrupted mergestate, unknown narrow action: %b")
+                hint = _(b"restart the merge")
+                raise error.Abort(msg, hint=hint)
+            continue
         try:
             fctx = ctx[f]
             if fctx is None:
@@ -239,7 +270,17 @@
             if not rf(f):
                 files.mark_removed(f)
 
-    mn = _commit_manifest(tr, linkrev, ctx, mctx, m, files.touched, added, drop)
+    mn = _commit_manifest(
+        tr,
+        linkrev,
+        ctx,
+        mctx,
+        m,
+        files.touched,
+        added,
+        drop,
+        bool(narrow_files),
+    )
 
     return mn
 
@@ -409,7 +450,17 @@
     return fnode, touched
 
 
-def _commit_manifest(tr, linkrev, ctx, mctx, manifest, files, added, drop):
+def _commit_manifest(
+    tr,
+    linkrev,
+    ctx,
+    mctx,
+    manifest,
+    files,
+    added,
+    drop,
+    has_some_narrow_action=False,
+):
     """make a new manifest entry (or reuse a new one)
 
     given an initialised manifest context and precomputed list of
@@ -451,6 +502,10 @@
         # at this point is merges, and we already error out in the
         # case where the merge has files outside of the narrowspec,
         # so this is safe.
+        if has_some_narrow_action:
+            match = None
+        else:
+            match = repo.narrowmatch()
         mn = mctx.write(
             tr,
             linkrev,
@@ -458,7 +513,7 @@
             p2.manifestnode(),
             added,
             drop,
-            match=repo.narrowmatch(),
+            match=match,
         )
     else:
         repo.ui.debug(



To: marmoute, durin42, #hg-reviewers, Alphare
Cc: Alphare, mercurial-patches
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mercurial-scm.org/pipermail/mercurial-patches/attachments/20220203/8427c387/attachment-0002.html>


More information about the Mercurial-patches mailing list