Patchwork [6,of,7,V2,stable] merge: add "other" file node in the merge state file

login
register
mail settings
Submitter Pierre-Yves David
Date Feb. 27, 2014, 11:25 p.m.
Message ID <219c3064c7763c1adb56.1393543522@marginatus.alto.octopoid.net>
Download mbox | patch
Permalink /patch/3795/
State Accepted
Commit 3678707e4017ef3c62cc35ab4a5f166896cd840e
Headers show

Comments

Pierre-Yves David - Feb. 27, 2014, 11:25 p.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@fb.com>
# Date 1393383287 28800
#      Tue Feb 25 18:54:47 2014 -0800
# Branch stable
# Node ID 219c3064c7763c1adb56e82a946fd9ab776a8a1d
# Parent  45a3436571efbbf33d4d5ed0c4a31af8950ece4c
merge: add "other" file node in the merge state file

This data is mostly redundant with the "other" changeset node (+ other changeset
file path). However, more data never hurt.

The old format do not store it so this require some dancing to add and remove it
on demand.

Patch

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -14,10 +14,16 @@  import error, util, filemerge, copies, s
 import errno, os, shutil
 
 _pack = struct.pack
 _unpack = struct.unpack
 
+def _droponode(data):
+    # used for compatibility for v1
+    bits = data.split("\0")
+    bits = bits[:-2] + bits[-1:]
+    return "\0".join(bits)
+
 class mergestate(object):
     '''track 3-way merge state of individual files
 
     it is stored on disk when needed. Two file are used, one with an old
     format, one with a new format. Both contains similar data, but the new
@@ -68,18 +74,30 @@  class mergestate(object):
                                    % rtype))
         self._dirty = False
     def _readrecords(self):
         v1records = self._readrecordsv1()
         v2records = self._readrecordsv2()
-        allv2 = set(v2records)
-        for rev in v1records:
-            if rev not in allv2:
+        oldv2 = set() # old format version of v2 record
+        for rec in v2records:
+            if rec[0] == 'L':
+                oldv2.add(rec)
+            elif rec[0] == 'F':
+                # drop the onode data (not contained in v1)
+                oldv2.add(('F', _droponode(rec[1])))
+        for rec in v1records:
+            if rec not in oldv2:
                 # v1 file is newer than v2 file, use it
                 # we have to infer the "other" changeset of the merge
                 # we cannot do better than that with v1 of the format
                 mctx = self._repo[None].parents()[-1]
                 v1records.append(('O', mctx.hex()))
+                # add "other" file node information
+                for idx, r in enumerate(v1records):
+                    if r[0] == 'F':
+                        bits = r[1].split("\0")
+                        bits.insert(-2, mctx[bits[-2]])
+                        v1records[idx] = (r[0], "\0".join(bits))
                 return v1records
         else:
             return v2records
     def _readrecordsv1(self):
         records = []
@@ -133,11 +151,11 @@  class mergestate(object):
         lrecords = irecords.next()
         assert lrecords[0] == 'L'
         f.write(hex(self._local) + "\n")
         for rtype, data in irecords:
             if rtype == "F":
-                f.write("%s\n" % data)
+                f.write("%s\n" % _droponode(data))
         f.close()
     def _writerecordsv2(self, records):
         f = self._repo.opener(self.statepathv2, "w")
         for key, data in records:
             assert len(key) == 1
@@ -145,12 +163,14 @@  class mergestate(object):
             f.write(_pack(format, key, len(data), data))
         f.close()
     def add(self, fcl, fco, fca, fd):
         hash = util.sha1(fcl.path()).hexdigest()
         self._repo.opener.write("merge/" + hash, fcl.data())
-        self._state[fd] = ['u', hash, fcl.path(), fca.path(),
-                           hex(fca.filenode()), fco.path(), fcl.flags()]
+        self._state[fd] = ['u', hash, fcl.path(),
+                           fca.path(), hex(fca.filenode()),
+                           fco.path(), hex(fco.filenode()),
+                           fcl.flags()]
         self._dirty = True
     def __contains__(self, dfile):
         return dfile in self._state
     def __getitem__(self, dfile):
         return self._state[dfile][0]
@@ -165,11 +185,12 @@  class mergestate(object):
         self._state[dfile][0] = state
         self._dirty = True
     def resolve(self, dfile, wctx, octx):
         if self[dfile] == 'r':
             return 0
-        state, hash, lfile, afile, anode, ofile, flags = self._state[dfile]
+        stateentry = self._state[dfile]
+        state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
         fcd = wctx[dfile]
         fco = octx[ofile]
         fca = self._repo.filectx(afile, fileid=anode)
         # "premerge" x flags
         flo = fco.flags()