--- 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 ..