From: David KÃ¥gedal <davidk@xxxxxxxxxxxxxx> This only prepares for later simplifications. Signed-off-by: David KÃ¥gedal <davidk@xxxxxxxxxxxxxx> --- 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 - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html