threads / patch / 2798

patchmerge-recursive: leave unmerged entries in the index.

Subject: [PATCH] merge-recursive: leave unmerged entries in the index.

## tl;dr

3 messages between Dec 11, 2005 and Dec 11, 2005. Diffs are folded; open one to read it.

replies: 2people: 2as markdown or json

Junio C Hamano· Dec 11, 2005, 06:26 UTC · lore
This does two things.
 - When one branch renamed and the other branch did not, the
   resulting half-merged file in the working tree used to swap
   branches around and showed as if renaming side was "ours".
   This was confusing and inconsistent (even though the conflict
   markers were marked with branch names, it was not a good
   enough excuse).  This changes the order of arguments to
   mergeFile in such a case to make sure we always see "our"
   change between <<< and ===, and "their" change between ===
   and >>>.
 - When both branches renamed to the same path, and when one
   branch renamed and the other branch did not, we attempt
   mergeFile.  When this automerge conflicted, we used to
   collapse the index.  Now we use update-index --index-info
   to inject higher stage entries to leave the index in unmerged
   state for these two cases.

What this still does _not_ do is to inject unmerged state into the index when the structural changes conflict. I have not thought things through what to do in each case yet, but the cases this commit cover are the most common ones, so this would be a good start.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 * Aside from minor cleanups both in usage strings and
   documentation, many of which might still remain, I consider
   this the last remaining bit before we can go 1.0, and
   comments and corrections are very much appreciated.
 git-merge-recursive.py |   54 +++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 46 insertions(+), 8 deletions(-)
e5c23ede9ccc6ddd5f2cf13154f977bb1b687051
Show changes to git-merge-recursive.py +46 −8
diff --git a/git-merge-recursive.py b/git-merge-recursive.py
index b7fb096..767b13c 100755
--- a/git-merge-recursive.py
+++ b/git-merge-recursive.py
@@ -280,6 +280,22 @@ def updateFileExt(sha, mode, path, updat
         runProgram(['git-update-index', '--add', '--cacheinfo',
                     '0%o' % mode, sha, path])
 
+def setIndexStages(path,
+                   oSHA1, oMode,
+                   aSHA1, aMode,
+                   bSHA1, bMode):
+    prog = ['git-update-index', '-z', '--index-info']
+    proc = subprocess.Popen(prog, stdin=subprocess.PIPE)
+    pipe = proc.stdin
+    # Clear stages first.
+    pipe.write("0 " + ("0" * 40) + "\t" + path + "\0")
+    # Set stages
+    pipe.write("%o %s %d\t%s\0" % (oMode, oSHA1, 1, path))
+    pipe.write("%o %s %d\t%s\0" % (aMode, aSHA1, 2, path))
+    pipe.write("%o %s %d\t%s\0" % (bMode, bSHA1, 3, path))
+    pipe.close()
+    proc.wait()
+
 def removeFile(clean, path):
     updateCache = cacheOnly or clean
     updateWd = not cacheOnly
@@ -590,6 +606,8 @@ def processRenames(renamesA, renamesB, b
                 else:
                     dstName2 = ren1.dstName
 
+                # NEEDSWORK: place dstNameA at stage 2 and dstNameB at stage 3
+                # What about other stages???
                 updateFile(False, ren1.dstSha, ren1.dstMode, dstName1)
                 updateFile(False, ren2.dstSha, ren2.dstMode, dstName2)
             else:
@@ -611,8 +629,11 @@ def processRenames(renamesA, renamesB, b
                     cleanMerge = False
 
                     if not cacheOnly:
-                        updateFileExt(ren1.dstSha, ren1.dstMode, ren1.dstName,
-                                      updateCache=True, updateWd=False)
+                        setIndexStages(ren1.dstName,
+                                       ren1.srcSha, ren1.srcMode,
+                                       ren1.dstSha, ren1.dstMode,
+                                       ren2.dstSha, ren2.dstMode)
+
                 updateFile(clean, resSha, resMode, ren1.dstName)
         else:
             # Renamed in 1, maybe changed in 2
@@ -672,11 +693,24 @@ def processRenames(renamesA, renamesB, b
                 tryMerge = True
 
             if tryMerge:
+
+                oName, oSHA1, oMode = ren1.srcName, ren1.srcSha, ren1.srcMode
+                aName, bName = ren1.dstName, ren1.srcName
+                aSHA1, bSHA1 = ren1.dstSha, srcShaOtherBranch
+                aMode, bMode = ren1.dstMode, srcModeOtherBranch
+                aBranch, bBranch = branchName1, branchName2
+
+                if renamesA != renames1:
+                    aName, bName = bName, aName
+                    aSHA1, bSHA1 = bSHA1, aSHA1
+                    aMode, bMode = bMode, aMode
+                    aBranch, bBranch = bBranch, aBranch
+
                 [resSha, resMode, clean, merge] = \
-                         mergeFile(ren1.srcName, ren1.srcSha, ren1.srcMode,
-                                   ren1.dstName, ren1.dstSha, ren1.dstMode,
-                                   ren1.srcName, srcShaOtherBranch, srcModeOtherBranch,
-                                   branchName1, branchName2)
+                         mergeFile(oName, oSHA1, oMode,
+                                   aName, aSHA1, aMode,
+                                   bName, bSHA1, bMode,
+                                   aBranch, bBranch);
 
                 if merge or not clean:
                     output('Renaming', fmtRename(ren1.srcName, ren1.dstName))
@@ -690,8 +724,12 @@ def processRenames(renamesA, renamesB, b
                     cleanMerge = False
 
                     if not cacheOnly:
-                        updateFileExt(ren1.dstSha, ren1.dstMode, ren1.dstName,
-                                      updateCache=True, updateWd=False)
+                        # Stuff stage1/2/3
+                        setIndexStages(ren1.dstName,
+                                       oSHA1, oMode,
+                                       aSHA1, aMode,
+                                       bSHA1, bMode)
+
                 updateFile(clean, resSha, resMode, ren1.dstName)
 
     return cleanMerge
-- 
0.99.9.GIT
Fredrik Kuivinen· Dec 11, 2005, 09:25 UTC · re: Junio C Hamano · lore

Re: [PATCH] merge-recursive: leave unmerged entries in the index.

On Sat, Dec 10, 2005 at 10:26:30PM -0800, Junio C Hamano wrote:
Show 25 quoted lines
> This does two things.
> 
>  - When one branch renamed and the other branch did not, the
>    resulting half-merged file in the working tree used to swap
>    branches around and showed as if renaming side was "ours".
>    This was confusing and inconsistent (even though the conflict
>    markers were marked with branch names, it was not a good
>    enough excuse).  This changes the order of arguments to
>    mergeFile in such a case to make sure we always see "our"
>    change between <<< and ===, and "their" change between ===
>    and >>>.
> 
>  - When both branches renamed to the same path, and when one
>    branch renamed and the other branch did not, we attempt
>    mergeFile.  When this automerge conflicted, we used to
>    collapse the index.  Now we use update-index --index-info
>    to inject higher stage entries to leave the index in unmerged
>    state for these two cases.
> 
> What this still does _not_ do is to inject unmerged state into
> the index when the structural changes conflict.  I have not
> thought things through what to do in each case yet, but the
> cases this commit cover are the most common ones, so this would
> be a good start.
> 
Good work! I have one comment, see below.
Show 25 quoted lines
> e5c23ede9ccc6ddd5f2cf13154f977bb1b687051
> diff --git a/git-merge-recursive.py b/git-merge-recursive.py
> index b7fb096..767b13c 100755
> --- a/git-merge-recursive.py
> +++ b/git-merge-recursive.py
> @@ -280,6 +280,22 @@ def updateFileExt(sha, mode, path, updat
>          runProgram(['git-update-index', '--add', '--cacheinfo',
>                      '0%o' % mode, sha, path])
>  
> +def setIndexStages(path,
> +                   oSHA1, oMode,
> +                   aSHA1, aMode,
> +                   bSHA1, bMode):
> +    prog = ['git-update-index', '-z', '--index-info']
> +    proc = subprocess.Popen(prog, stdin=subprocess.PIPE)
> +    pipe = proc.stdin
> +    # Clear stages first.
> +    pipe.write("0 " + ("0" * 40) + "\t" + path + "\0")
> +    # Set stages
> +    pipe.write("%o %s %d\t%s\0" % (oMode, oSHA1, 1, path))
> +    pipe.write("%o %s %d\t%s\0" % (aMode, aSHA1, 2, path))
> +    pipe.write("%o %s %d\t%s\0" % (bMode, bSHA1, 3, path))
> +    pipe.close()
> +    proc.wait()
> +
It might be cleaner to use
runProgram(['git-update-index', '-z', '--index-info'],
           input="0 " + ("0" * 40) + "\t" + path + "\0" + \
                 "%o %s %d\t%s\0" % (oMode, oSHA1, 1, path) + \
                 "%o %s %d\t%s\0" % (aMode, aSHA1, 2, path) + \
                 "%o %s %d\t%s\0" % (bMode, bSHA1, 3, path))

here instead. With this code we will get an exception if git-update-index exits with an error code. It is also consistent with the rest of the code.

- Fredrik
Junio C Hamano· Dec 11, 2005, 09:42 UTC · re: Fredrik Kuivinen · lore

Re: [PATCH] merge-recursive: leave unmerged entries in the index.

Fredrik Kuivinen <freku045@student.liu.se> writes:
Show 11 quoted lines
> It might be cleaner to use
>
> runProgram(['git-update-index', '-z', '--index-info'],
>            input="0 " + ("0" * 40) + "\t" + path + "\0" + \
>                  "%o %s %d\t%s\0" % (oMode, oSHA1, 1, path) + \
>                  "%o %s %d\t%s\0" % (aMode, aSHA1, 2, path) + \
>                  "%o %s %d\t%s\0" % (bMode, bSHA1, 3, path))
>
> here instead. With this code we will get an exception if
> git-update-index exits with an error code. It is also consistent with
> the rest of the code.

Thanks. I did not know how to feed the string through runProgram (well, I did not look close enough).

← back to recent threads