git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[StGit PATCH 1/6] Split git.merge into two functions

From
David Kågedal <davidk@lysator.liu.se>
Date
Aug 20, 2007, 08:11 UTC
Message-ID
<1187597523433-git-send-email-davidk@lysator.liu.se>
In-Reply-To
<11875975232619-git-send-email-davidk@lysator.liu.se>
From: David KÃ¥gedal <davidk@lysator.liu.se>
This only prepares for later simplifications.
Signed-off-by: David KÃ¥gedal <davidk@lysator.liu.se>
---
 stgit/commands/pick.py |    2 +-
 stgit/git.py           |   86 ++++++++++++++++++++++++++++++++++++++----------
 stgit/stack.py         |    2 +-
 3 files changed, 70 insertions(+), 20 deletions(-)
diff --git a/stgit/commands/pick.py b/stgit/commands/pick.py
index 27fdf9c..9913e63 100644
--- a/stgit/commands/pick.py
+++ b/stgit/commands/pick.py
@@ -98,7 +98,7 @@ def func(parser, options, args):
 
         # try a direct git-apply first
         if not git.apply_diff(bottom, top):
-            git.merge(bottom, git.get_head(), top, recursive = True)
+            git.merge_recursive(bottom, git.get_head(), top)
 
         out.done()
     elif options.update:
diff --git a/stgit/git.py b/stgit/git.py
index 72bf889..9d8da5d 100644
--- a/stgit/git.py
+++ b/stgit/git.py
@@ -667,33 +667,83 @@ def apply_diff(rev1, rev2, check_index = True, files = None):
 
     return True
 
-def merge(base, head1, head2, recursive = False):
+stages_re = re.compile('^([0-7]+) ([0-9a-f]{40}) ([1-3])\t(.*)$', re.S)
+
+def merge_recursive(base, head1, head2):
     """Perform a 3-way merge between base, head1 and head2 into the
     local tree
     """
     refresh_index()
 
     err_output = None
-    if recursive:
-        # this operation tracks renames but it is slower (used in
-        # general when pushing or picking patches)
-        try:
-            # use _output() to mask the verbose prints of the tool
-            _output(['git-merge-recursive', base, '--', head1, head2])
-        except GitException, ex:
-            err_output = str(ex)
-            pass
-    else:
-        # the fast case where we don't track renames (used when the
-        # distance between base and heads is small, i.e. folding or
-        # synchronising patches)
-        if __run('git-read-tree -u -m --aggressive',
-                 [base, head1, head2]) != 0:
-            raise GitException, 'git-read-tree failed (local changes maybe?)'
+    # this operation tracks renames but it is slower (used in
+    # general when pushing or picking patches)
+    try:
+        # use _output() to mask the verbose prints of the tool
+        _output(['git-merge-recursive', base, '--', head1, head2])
+    except GitException, ex:
+        err_output = str(ex)
+        pass
+
+    # check the index for unmerged entries
+    files = {}
+
+    for line in _output(['git-ls-files', '--unmerged', '--stage', '-z']).split('\0'):
+        if not line:
+            continue
+
+        mode, hash, stage, path = stages_re.findall(line)[0]
+
+        if not path in files:
+            files[path] = {}
+            files[path]['1'] = ('', '')
+            files[path]['2'] = ('', '')
+            files[path]['3'] = ('', '')
+
+        files[path][stage] = (mode, hash)
+
+    if err_output and not files:
+        # if no unmerged files, there was probably a different type of
+        # error and we have to abort the merge
+        raise GitException, err_output
+
+    # merge the unmerged files
+    errors = False
+    for path in files:
+        # remove additional files that might be generated for some
+        # newer versions of GIT
+        for suffix in [base, head1, head2]:
+            if not suffix:
+                continue
+            fname = path + '~' + suffix
+            if os.path.exists(fname):
+                os.remove(fname)
+
+        stages = files[path]
+        if gitmergeonefile.merge(stages['1'][1], stages['2'][1],
+                                 stages['3'][1], path, stages['1'][0],
+                                 stages['2'][0], stages['3'][0]) != 0:
+            errors = True
+
+    if errors:
+        raise GitException, 'GIT index merging failed (possible conflicts)'
+
+def merge(base, head1, head2):
+    """Perform a 3-way merge between base, head1 and head2 into the
+    local tree
+    """
+    refresh_index()
+
+    err_output = None
+    # the fast case where we don't track renames (used when the
+    # distance between base and heads is small, i.e. folding or
+    # synchronising patches)
+    if __run('git-read-tree -u -m --aggressive',
+             [base, head1, head2]) != 0:
+        raise GitException, 'git-read-tree failed (local changes maybe?)'
 
     # check the index for unmerged entries
     files = {}
-    stages_re = re.compile('^([0-7]+) ([0-9a-f]{40}) ([1-3])\t(.*)$', re.S)
 
     for line in _output(['git-ls-files', '--unmerged', '--stage', '-z']).split('\0'):
         if not line:
diff --git a/stgit/stack.py b/stgit/stack.py
index dbd7ea4..8b77943 100644
--- a/stgit/stack.py
+++ b/stgit/stack.py
@@ -1061,7 +1061,7 @@ class Series(PatchSet):
 
                 # merge can fail but the patch needs to be pushed
                 try:
-                    git.merge(bottom, head, top, recursive = True)
+                    git.merge_recursive(bottom, head, top)
                 except git.GitException, ex:
                     out.error('The merge failed during "push".',
                               'Use "refresh" after fixing the conflicts or'
-- 
1.5.3.rc3.119.g1812
Previous: David KågedalNext: David Kågedal
Message 2 of 18 in “Use git conflict handling on push”
  1. 0/6 Use git conflict handling on pushDavid Kågedal, Aug 20, 2007
  2. 1/6 Split git.merge into two functionsDavid Kågedal, Aug 20, 2007
  3. 2/6 Don't try to merge files that merge-recursive already mergedDavid Kågedal, Aug 20, 2007
  4. 3/6 Don't touch state after conflict in pushDavid Kågedal, Aug 20, 2007
  5. 4/6 Added a test case to check what happens when push finds a conflictDavid Kågedal, Aug 20, 2007
  6. 5/6 Simplify merge_recursiveDavid Kågedal, Aug 20, 2007
  7. 6/6 Use the output from merge-recursive to list conflictsDavid Kågedal, Aug 20, 2007
  8. Karl HasselströmAug 22, 2007
  9. David KågedalAug 22, 2007
  10. Karl HasselströmAug 22, 2007
  11. Karl HasselströmAug 22, 2007
  12. Leave working dir and index alone after failed (conflicting) pushKarl Hasselström, Aug 22, 2007
  13. David KågedalAug 20, 2007
  14. Junio C HamanoAug 20, 2007
  15. Uwe Kleine-KönigAug 21, 2007
  16. Junio C HamanoAug 22, 2007
  17. Karl HasselströmAug 22, 2007
  18. Catalin MarinasAug 23, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.