merge: save merge part labels for later reuse
authorSimon Farnsworth <simonfar@fb.com>
Sat, 19 Mar 2016 18:37:10 -0700
changeset 28634 3ceac01bc29f
parent 28633 e35d7f131483
child 28635 87f92d6f0bc3
merge: save merge part labels for later reuse We permit the caller of merge operations to supply labels for the merge parts ("local", "other", and optionally "base"). These labels are used in conflict markers to reduce confusion; however, the labels were not persistent, so 'hg resolve' would lose the labels. Store the labels in the mergestate.
mercurial/commands.py
mercurial/merge.py
tests/test-graft.t
tests/test-histedit-non-commute-abort.t
tests/test-merge-changedelete.t
tests/test-rebase-abort.t
--- a/mercurial/commands.py	Fri Mar 25 21:51:00 2016 +0000
+++ b/mercurial/commands.py	Sat Mar 19 18:37:10 2016 -0700
@@ -2896,6 +2896,14 @@
 
                 ui.write(('file extras: %s (%s)\n')
                          % (filename, ', '.join(extrastrings)))
+            elif rtype == 'l':
+                labels = record.split('\0', 2)
+                labels = [l for l in labels if len(l) > 0]
+                ui.write(('labels:\n'))
+                ui.write(('  local: %s\n' % labels[0]))
+                ui.write(('  other: %s\n' % labels[1]))
+                if len(labels) > 2:
+                    ui.write(('  base:  %s\n' % labels[2]))
             else:
                 ui.write(('unrecognized entry: %s\t%s\n')
                          % (rtype, record.replace('\0', '\t')))
@@ -2908,7 +2916,7 @@
     # sort so that reasonable information is on top
     v1records = ms._readrecordsv1()
     v2records = ms._readrecordsv2()
-    order = 'LOm'
+    order = 'LOml'
     def key(r):
         idx = order.find(r[0])
         if idx == -1:
--- a/mercurial/merge.py	Fri Mar 25 21:51:00 2016 +0000
+++ b/mercurial/merge.py	Sat Mar 19 18:37:10 2016 -0700
@@ -68,6 +68,7 @@
     f: a (filename, dictonary) tuple of optional values for a given file
     X: unsupported mandatory record type (used in tests)
     x: unsupported advisory record type (used in tests)
+    l: the labels for the parts of the merge.
 
     Merge driver run states (experimental):
     u: driver-resolved files unmarked -- needs to be run next time we're about
@@ -80,11 +81,11 @@
     statepathv2 = 'merge/state2'
 
     @staticmethod
-    def clean(repo, node=None, other=None):
+    def clean(repo, node=None, other=None, labels=None):
         """Initialize a brand new merge state, removing any existing state on
         disk."""
         ms = mergestate(repo)
-        ms.reset(node, other)
+        ms.reset(node, other, labels)
         return ms
 
     @staticmethod
@@ -100,12 +101,14 @@
         Do not use this directly! Instead call read() or clean()."""
         self._repo = repo
         self._dirty = False
+        self._labels = None
 
-    def reset(self, node=None, other=None):
+    def reset(self, node=None, other=None, labels=None):
         self._state = {}
         self._stateextras = {}
         self._local = None
         self._other = None
+        self._labels = labels
         for var in ('localctx', 'otherctx'):
             if var in vars(self):
                 delattr(self, var)
@@ -165,6 +168,9 @@
                     i += 2
 
                 self._stateextras[filename] = extras
+            elif rtype == 'l':
+                labels = record.split('\0', 2)
+                self._labels = [l for l in labels if len(l) > 0]
             elif not rtype.islower():
                 unsupported.add(rtype)
         self._results = {}
@@ -353,6 +359,9 @@
             rawextras = '\0'.join('%s\0%s' % (k, v) for k, v in
                                   extras.iteritems())
             records.append(('f', '%s\0%s' % (filename, rawextras)))
+        if self._labels is not None:
+            labels = '\0'.join(self._labels)
+            records.append(('l', labels))
         return records
 
     def _writerecords(self, records):
@@ -444,7 +453,7 @@
     def extras(self, filename):
         return self._stateextras.setdefault(filename, {})
 
-    def _resolve(self, preresolve, dfile, wctx, labels=None):
+    def _resolve(self, preresolve, dfile, wctx):
         """rerun merge process for file path `dfile`"""
         if self[dfile] in 'rd':
             return True, 0
@@ -481,11 +490,11 @@
                 self._repo.wvfs.unlinkpath(dfile, ignoremissing=True)
             complete, r, deleted = filemerge.premerge(self._repo, self._local,
                                                       lfile, fcd, fco, fca,
-                                                      labels=labels)
+                                                      labels=self._labels)
         else:
             complete, r, deleted = filemerge.filemerge(self._repo, self._local,
                                                        lfile, fcd, fco, fca,
-                                                       labels=labels)
+                                                       labels=self._labels)
         if r is None:
             # no real conflict
             del self._state[dfile]
@@ -523,17 +532,17 @@
         else:
             return ctx[f]
 
-    def preresolve(self, dfile, wctx, labels=None):
+    def preresolve(self, dfile, wctx):
         """run premerge process for dfile
 
         Returns whether the merge is complete, and the exit code."""
-        return self._resolve(True, dfile, wctx, labels=labels)
+        return self._resolve(True, dfile, wctx)
 
-    def resolve(self, dfile, wctx, labels=None):
+    def resolve(self, dfile, wctx):
         """run merge process (assuming premerge was run) for dfile
 
         Returns the exit code of the merge."""
-        return self._resolve(False, dfile, wctx, labels=labels)[1]
+        return self._resolve(False, dfile, wctx)[1]
 
     def counts(self):
         """return counts for updated, merged and removed files in this
@@ -1094,7 +1103,7 @@
     """
 
     updated, merged, removed = 0, 0, 0
-    ms = mergestate.clean(repo, wctx.p1().node(), mctx.node())
+    ms = mergestate.clean(repo, wctx.p1().node(), mctx.node(), labels)
     moves = []
     for m, l in actions.items():
         l.sort()
@@ -1247,7 +1256,7 @@
                              overwrite)
             continue
         audit(f)
-        complete, r = ms.preresolve(f, wctx, labels=labels)
+        complete, r = ms.preresolve(f, wctx)
         if not complete:
             numupdates += 1
             tocomplete.append((f, args, msg))
@@ -1257,7 +1266,7 @@
         repo.ui.debug(" %s: %s -> m (merge)\n" % (f, msg))
         z += 1
         progress(_updating, z, item=f, total=numupdates, unit=_files)
-        ms.resolve(f, wctx, labels=labels)
+        ms.resolve(f, wctx)
 
     ms.commit()
 
--- a/tests/test-graft.t	Fri Mar 25 21:51:00 2016 +0000
+++ b/tests/test-graft.t	Sat Mar 19 18:37:10 2016 -0700
@@ -452,7 +452,7 @@
   c
   =======
   b
-  >>>>>>> other: 5d205f8b35b6  - bar: 1
+  >>>>>>> graft: 5d205f8b35b6  - bar: 1
   $ echo b > a
   $ hg resolve -m a
   (no more unresolved files)
--- a/tests/test-histedit-non-commute-abort.t	Fri Mar 25 21:51:00 2016 +0000
+++ b/tests/test-histedit-non-commute-abort.t	Sat Mar 19 18:37:10 2016 -0700
@@ -80,6 +80,9 @@
   * version 2 records
   local: 8f7551c7e4a2f2efe0bc8c741baf7f227d65d758
   other: e860deea161a2f77de56603b340ebbb4536308ae
+  labels:
+    local: local
+    other: histedit
   unrecognized entry: x	advisory record
   file extras: e (ancestorlinknode = 0000000000000000000000000000000000000000)
   file: e (record type "F", state "u", hash 58e6b3a414a1e090dfc6029add0f3555ccba127f)
@@ -95,6 +98,9 @@
   * version 2 records
   local: 8f7551c7e4a2f2efe0bc8c741baf7f227d65d758
   other: e860deea161a2f77de56603b340ebbb4536308ae
+  labels:
+    local: local
+    other: histedit
   file extras: e (ancestorlinknode = 0000000000000000000000000000000000000000)
   file: e (record type "F", state "u", hash 58e6b3a414a1e090dfc6029add0f3555ccba127f)
     local path: e (flags "")
--- a/tests/test-merge-changedelete.t	Fri Mar 25 21:51:00 2016 +0000
+++ b/tests/test-merge-changedelete.t	Sat Mar 19 18:37:10 2016 -0700
@@ -736,6 +736,9 @@
   * version 2 records
   local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
   other: 10f9a0a634e82080907e62f075ab119cbc565ea6
+  labels:
+    local: working copy
+    other: destination
   file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
   file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
     local path: file1 (flags "")
@@ -776,6 +779,9 @@
   * version 2 records
   local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
   other: 10f9a0a634e82080907e62f075ab119cbc565ea6
+  labels:
+    local: working copy
+    other: destination
   file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
   file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
     local path: file1 (flags "")
@@ -814,6 +820,9 @@
   * version 2 records
   local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
   other: 10f9a0a634e82080907e62f075ab119cbc565ea6
+  labels:
+    local: working copy
+    other: destination
   file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
   file: file1 (record type "C", state "r", hash 60b27f004e454aca81b0480209cce5081ec52390)
     local path: file1 (flags "")
@@ -854,6 +863,9 @@
   * version 2 records
   local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
   other: 10f9a0a634e82080907e62f075ab119cbc565ea6
+  labels:
+    local: working copy
+    other: destination
   file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
   file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
     local path: file1 (flags "")
@@ -900,6 +912,9 @@
   * version 2 records
   local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
   other: 10f9a0a634e82080907e62f075ab119cbc565ea6
+  labels:
+    local: working copy
+    other: destination
   file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
   file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
     local path: file1 (flags "")
@@ -947,6 +962,9 @@
   * version 2 records
   local: ab57bf49aa276a22d35a473592d4c34b5abc3eff
   other: 10f9a0a634e82080907e62f075ab119cbc565ea6
+  labels:
+    local: working copy
+    other: destination
   file extras: file1 (ancestorlinknode = ab57bf49aa276a22d35a473592d4c34b5abc3eff)
   file: file1 (record type "C", state "u", hash 60b27f004e454aca81b0480209cce5081ec52390)
     local path: file1 (flags "")
--- a/tests/test-rebase-abort.t	Fri Mar 25 21:51:00 2016 +0000
+++ b/tests/test-rebase-abort.t	Sat Mar 19 18:37:10 2016 -0700
@@ -75,6 +75,9 @@
   * version 2 records
   local: 3e046f2ecedb793b97ed32108086edd1a162f8bc
   other: 46f0b057b5c061d276b91491c22151f78698abd2
+  labels:
+    local: dest
+    other: source
   unrecognized entry: x	advisory record
   file extras: common (ancestorlinknode = 3163e20567cc93074fbb7a53c8b93312e59dbf2c)
   file: common (record type "F", state "u", hash 94c8c21d08740f5da9eaa38d1f175c592692f0d1)
@@ -91,6 +94,9 @@
   * version 2 records
   local: 3e046f2ecedb793b97ed32108086edd1a162f8bc
   other: 46f0b057b5c061d276b91491c22151f78698abd2
+  labels:
+    local: dest
+    other: source
   file extras: common (ancestorlinknode = 3163e20567cc93074fbb7a53c8b93312e59dbf2c)
   file: common (record type "F", state "u", hash 94c8c21d08740f5da9eaa38d1f175c592692f0d1)
     local path: common (flags "")