merge with stable
authorYuya Nishihara <yuya@tcha.org>
Wed, 03 Jun 2020 19:20:18 +0900
changeset 44916 61719b9658b1
parent 44905 f330d6117a5b (current diff)
parent 44915 2dc5ae953c4a (diff)
child 44925 ce8fe77102f4
merge with stable
mercurial/commands.py
mercurial/context.py
mercurial/copies.py
--- a/mercurial/commands.py	Sat May 30 12:36:00 2020 -0400
+++ b/mercurial/commands.py	Wed Jun 03 19:20:18 2020 +0900
@@ -2971,9 +2971,6 @@
 
     revs = list(revs)
     revs.extend(opts.get(b'rev'))
-    basectx = None
-    if opts.get(b'base'):
-        basectx = scmutil.revsingle(repo, opts[b'base'], None)
     # a dict of data to be stored in state file
     statedata = {}
     # list of new nodes created by ongoing graft
@@ -3063,6 +3060,8 @@
                 opts[b'log'] = True
             if statedata.get(b'no_commit'):
                 opts[b'no_commit'] = statedata.get(b'no_commit')
+            if statedata.get(b'base'):
+                opts[b'base'] = statedata.get(b'base')
             nodes = statedata[b'nodes']
             revs = [repo[node].rev() for node in nodes]
         else:
@@ -3075,6 +3074,9 @@
         revs = scmutil.revrange(repo, revs)
 
     skipped = set()
+    basectx = None
+    if opts.get(b'base'):
+        basectx = scmutil.revsingle(repo, opts[b'base'], None)
     if basectx is None:
         # check for merges
         for rev in repo.revs(b'%ld and merge()', revs):
@@ -3167,6 +3169,8 @@
 
     if opts.get(b'no_commit'):
         statedata[b'no_commit'] = True
+    if opts.get(b'base'):
+        statedata[b'base'] = opts[b'base']
     for pos, ctx in enumerate(repo.set(b"%ld", revs)):
         desc = b'%d:%s "%s"' % (
             ctx.rev(),
--- a/mercurial/context.py	Sat May 30 12:36:00 2020 -0400
+++ b/mercurial/context.py	Wed Jun 03 19:20:18 2020 +0900
@@ -1465,6 +1465,18 @@
     def children(self):
         return []
 
+    def flags(self, path):
+        if '_manifest' in self.__dict__:
+            try:
+                return self._manifest.flags(path)
+            except KeyError:
+                return b''
+
+        try:
+            return self._flagfunc(path)
+        except OSError:
+            return b''
+
     def ancestor(self, c2):
         """return the "best" ancestor context of self and c2"""
         return self._parents[0].ancestor(c2)  # punt on two parents for now
@@ -1601,12 +1613,6 @@
         return self._repo.dirstate.flagfunc(self._buildflagfunc)
 
     def flags(self, path):
-        if '_manifest' in self.__dict__:
-            try:
-                return self._manifest.flags(path)
-            except KeyError:
-                return b''
-
         try:
             return self._flagfunc(path)
         except OSError:
--- a/mercurial/copies.py	Sat May 30 12:36:00 2020 -0400
+++ b/mercurial/copies.py	Wed Jun 03 19:20:18 2020 +0900
@@ -604,9 +604,9 @@
         # thing in pathcopies(): pathcopies(x, y) can return a copy where the
         # destination doesn't exist in y.
         pass
-    elif m2[src] != mb[src]:
-        if not _related(c2[src], base[src]):
-            return
+    elif mb[src] != m2[src] and not _related(c2[src], base[src]):
+        return
+    elif mb[src] != m2[src] or mb.flags(src) != m2.flags(src):
         # modified on side 2
         for dst in dsts1:
             copy[dst] = src
--- a/mercurial/simplemerge.py	Sat May 30 12:36:00 2020 -0400
+++ b/mercurial/simplemerge.py	Wed Jun 03 19:20:18 2020 +0900
@@ -22,7 +22,9 @@
 from . import (
     error,
     mdiff,
+    node as nodemod,
     pycompat,
+    util,
 )
 from .utils import stringutil
 
@@ -449,6 +451,17 @@
     return result
 
 
+def _bytes_to_set(b):
+    """turns a multiple bytes (usually flags) into a set of individual byte"""
+    return set(b[x : x + 1] for x in range(len(b)))
+
+
+def is_null(ctx):
+    if not util.safehasattr(ctx, "node"):
+        return False
+    return ctx.node() != nodemod.nullid
+
+
 def simplemerge(ui, localctx, basectx, otherctx, **opts):
     """Performs the simplemerge algorithm.
 
@@ -503,8 +516,20 @@
         else:
             mergedtext += line
 
+    # merge flags if necessary
+    flags = localctx.flags()
+    localflags = _bytes_to_set(flags)
+    otherflags = _bytes_to_set(otherctx.flags())
+    if is_null(basectx) and localflags != otherflags:
+        baseflags = _bytes_to_set(basectx.flags())
+        flags = localflags & otherflags
+        for f in localflags.symmetric_difference(otherflags):
+            if f not in baseflags:
+                flags.add(f)
+        flags = b''.join(sorted(flags))
+
     if not opts.get(b'print'):
-        localctx.write(mergedtext, localctx.flags())
+        localctx.write(mergedtext, flags)
 
     if m3.conflicts and not mode == b'union':
         return 1
--- a/tests/test-graft.t	Sat May 30 12:36:00 2020 -0400
+++ b/tests/test-graft.t	Wed Jun 03 19:20:18 2020 +0900
@@ -853,6 +853,26 @@
   $ cat a
   abc
 
+graft --continue after --base with conflits
+
+  $ echo base > d
+  $ hg ci -m _
+  $ hg graft -r 6
+  skipping ungraftable merge revision 6
+  [255]
+  $ hg graft -r 6 --base 5
+  grafting 6:25a2b029d3ae "6"
+  merging d
+  merging e
+  warning: conflicts while merging d! (edit, then use 'hg resolve --mark')
+  abort: unresolved conflicts, can't continue
+  (use 'hg resolve' and 'hg graft --continue')
+  [1]
+  $ echo a > d && hg resolve -qm
+  continue: hg graft --continue
+  $ hg graft --continue
+  grafting 6:25a2b029d3ae "6"
+
 Continue testing same origin policy, using revision numbers from test above
 but do some destructive editing of the repo:
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-merge-exec.t	Wed Jun 03 19:20:18 2020 +0900
@@ -0,0 +1,434 @@
+===============================================
+Testing merge involving change to the exec flag
+===============================================
+
+#require execbit
+
+
+Initial setup
+==============
+
+
+  $ hg init base-repo
+  $ cd base-repo
+  $ cat << EOF > a
+  > 1
+  > 2
+  > 3
+  > 4
+  > 5
+  > 6
+  > 7
+  > 8
+  > 9
+  > EOF
+  $ touch b
+  $ hg add a b
+  $ hg commit -m "initial commit"
+  $ cd ..
+
+  $ hg init base-exec
+  $ cd base-exec
+  $ cat << EOF > a
+  > 1
+  > 2
+  > 3
+  > 4
+  > 5
+  > 6
+  > 7
+  > 8
+  > 9
+  > EOF
+  $ chmod +x a
+  $ touch b
+  $ hg add a b
+  $ hg commit -m "initial commit"
+  $ cd ..
+
+Testing merging mode change
+===========================
+
+Adding the flag
+---------------
+
+setup
+
+Change on one side, executable bit on the other
+
+  $ hg clone base-repo simple-merge-repo
+  updating to branch default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd simple-merge-repo
+  $ chmod +x a
+  $ hg ci -m "make a executable, no change"
+  $ [ -x a ] || echo "executable bit not recorded"
+  $ hg up ".^"
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cat << EOF > a
+  > 1
+  > 2
+  > 3
+  > 4
+  > 5
+  > 6
+  > 7
+  > x
+  > 9
+  > EOF
+  $ hg commit -m "edit end of file"
+  created new head
+
+merge them (from the update side)
+
+  $ hg merge 'desc("make a executable, no change")'
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg st
+  M a
+  $ [ -x a ] || echo "executable bit lost"
+
+merge them (from the chmod side)
+
+  $ hg up -C 'desc("make a executable, no change")'
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg merge 'desc("edit end of file")'
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg st
+  M a
+  $ [ -x a ] || echo "executable bit lost"
+
+
+  $ cd ..
+
+
+Removing the flag
+-----------------
+
+Change on one side, executable bit on the other
+
+  $ hg clone base-exec simple-merge-repo-removal
+  updating to branch default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd simple-merge-repo-removal
+  $ chmod -x a
+  $ hg ci -m "make a non-executable, no change"
+  $ [ -x a ] && echo "executable bit not removed"
+  [1]
+  $ hg up ".^"
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cat << EOF > a
+  > 1
+  > 2
+  > 3
+  > 4
+  > 5
+  > 6
+  > 7
+  > x
+  > 9
+  > EOF
+  $ hg commit -m "edit end of file"
+  created new head
+
+merge them (from the update side)
+
+  $ hg merge 'desc("make a non-executable, no change")'
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg st
+  M a
+  $ [ -x a ] && echo "executable bit not removed"
+  [1]
+
+merge them (from the chmod side)
+
+  $ hg up -C 'desc("make a non-executable, no change")'
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg merge 'desc("edit end of file")'
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg st
+  M a
+  $ [ -x a ] && echo "executable bit not removed"
+  [1]
+
+
+  $ cd ..
+
+Testing merging mode change with rename
+=======================================
+
+Adding the flag
+---------------
+
+  $ hg clone base-repo rename-merge-repo
+  updating to branch default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd rename-merge-repo
+
+make "a" executable on one side
+
+  $ chmod +x a
+  $ hg status
+  M a
+  $ hg ci -m "make a executable"
+  $ [ -x a ] || echo "executable bit not recorded"
+  $ hg up ".^"
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+make "a" renamed on the other side
+
+  $ hg mv a z
+  $ hg st --copies
+  A z
+    a
+  R a
+  $ hg ci -m "rename a to z"
+  created new head
+
+merge them (from the rename side)
+
+  $ hg merge 'desc("make a executable")'
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg st --copies
+  M z
+    a
+  $ [ -x z ] || echo "executable bit lost"
+
+merge them (from the chmod side)
+
+  $ hg up -C 'desc("make a executable")'
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg merge 'desc("rename a to z")'
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg st --copies
+  M z
+    a
+  R a
+  $ [ -x z ] || echo "executable bit lost"
+
+
+  $ cd ..
+
+Removing the flag
+-----------------
+
+  $ hg clone base-exec rename-merge-repo-removal
+  updating to branch default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd rename-merge-repo-removal
+
+make "a" non-executable on one side
+
+  $ chmod -x a
+  $ hg status
+  M a
+  $ hg ci -m "make a non-executable"
+  $ [ -x a ] && echo "executable bit not removed"
+  [1]
+  $ hg up ".^"
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+make "a" renamed on the other side
+
+  $ hg mv a z
+  $ hg st --copies
+  A z
+    a
+  R a
+  $ hg ci -m "rename a to z"
+  created new head
+
+merge them (from the rename side)
+
+  $ hg merge 'desc("make a non-executable")'
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg st --copies
+  M z
+    a
+  $ [ -x z ] && echo "executable bit not removed"
+  [1]
+
+merge them (from the chmod side)
+
+  $ hg up -C 'desc("make a non-executable")'
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg merge 'desc("rename a to z")'
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg st --copies
+  M z
+    a
+  R a
+  $ [ -x z ] && echo "executable bit not removed"
+  [1]
+
+
+  $ cd ..
+
+
+Testing merging mode change with rename + modification on both side
+===================================================================
+
+
+Adding the flag
+---------------
+
+  $ hg clone base-repo rename+mod-merge-repo
+  updating to branch default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd rename+mod-merge-repo
+
+make "a" executable on one side
+
+  $ chmod +x a
+  $ cat << EOF > a
+  > 1
+  > x
+  > 3
+  > 4
+  > 5
+  > 6
+  > 7
+  > 8
+  > 9
+  > EOF
+  $ hg status
+  M a
+  $ hg ci -m "make a executable, and change start"
+  $ [ -x a ] || echo "executable bit not recorded"
+  $ hg up ".^"
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+make "a" renamed on the other side
+
+  $ hg mv a z
+  $ hg st --copies
+  A z
+    a
+  R a
+  $ cat << EOF > z
+  > 1
+  > 2
+  > 3
+  > 4
+  > 5
+  > 6
+  > 7
+  > x
+  > 9
+  > EOF
+  $ hg ci -m "rename a to z, and change end"
+  created new head
+
+merge them (from the rename side)
+
+  $ hg merge 'desc("make a executable")'
+  merging z and a to z
+  0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg st --copies
+  M z
+    a
+  $ [ -x z ] || echo "executable bit lost"
+
+merge them (from the chmod side)
+
+  $ hg up -C 'desc("make a executable")'
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg merge 'desc("rename a to z")'
+  merging a and z to z
+  0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg st --copies
+  M z
+    a
+  R a
+  $ [ -x z ] || echo "executable bit lost"
+
+  $ cd ..
+
+Removing the flag
+-----------------
+
+  $ hg clone base-exec rename+mod-merge-repo-removal
+  updating to branch default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd rename+mod-merge-repo-removal
+
+make "a" non-executable on one side
+
+  $ chmod -x a
+  $ cat << EOF > a
+  > 1
+  > x
+  > 3
+  > 4
+  > 5
+  > 6
+  > 7
+  > 8
+  > 9
+  > EOF
+  $ hg status
+  M a
+  $ hg ci -m "make a non-executable, and change start"
+  $ [ -x z ] && echo "executable bit not removed"
+  [1]
+  $ hg up ".^"
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+make "a" renamed on the other side
+
+  $ hg mv a z
+  $ hg st --copies
+  A z
+    a
+  R a
+  $ cat << EOF > z
+  > 1
+  > 2
+  > 3
+  > 4
+  > 5
+  > 6
+  > 7
+  > x
+  > 9
+  > EOF
+  $ hg ci -m "rename a to z, and change end"
+  created new head
+
+merge them (from the rename side)
+
+  $ hg merge 'desc("make a non-executable")'
+  merging z and a to z
+  0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg st --copies
+  M z
+    a
+  $ [ -x z ] && echo "executable bit not removed"
+  [1]
+
+merge them (from the chmod side)
+
+  $ hg up -C 'desc("make a non-executable")'
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg merge 'desc("rename a to z")'
+  merging a and z to z
+  0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ hg st --copies
+  M z
+    a
+  R a
+  $ [ -x z ] && echo "executable bit not removed"
+  [1]
+
+  $ cd ..