# HG changeset patch # User Yuya Nishihara # Date 1591179618 -32400 # Node ID 61719b9658b156548634c216ffb2b9188266293b # Parent f330d6117a5b52b0d16960370b8648f3587ed81b# Parent 2dc5ae953c4a8265578acbe7d3e26c93ec8a08fb merge with stable diff -r f330d6117a5b -r 61719b9658b1 mercurial/commands.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(), diff -r f330d6117a5b -r 61719b9658b1 mercurial/context.py --- 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: diff -r f330d6117a5b -r 61719b9658b1 mercurial/copies.py --- 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 diff -r f330d6117a5b -r 61719b9658b1 mercurial/simplemerge.py --- 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 diff -r f330d6117a5b -r 61719b9658b1 tests/test-graft.t --- 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: diff -r f330d6117a5b -r 61719b9658b1 tests/test-merge-exec.t --- /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 ..