-
- 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 %s -- %s %s' % (base, head1, head2))
- except GitException:
- 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?)'
-
- # 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:
- 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)
-
- # 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 status(files = None, modified = False, new = False, deleted = False,
- conflict = False, unknown = False, noexclude = False):
- """Show the tree status
- """
- if not files:
- files = []
-
- cache_files = __tree_status(files, unknown = True, noexclude = noexclude)
- all = not (modified or new or deleted or conflict or unknown)
-
- if not all:
- filestat = []
- if modified:
- filestat.append('M')
- if new:
- filestat.append('A')
- filestat.append('N')
- if deleted:
- filestat.append('D')
- if conflict:
- filestat.append('C')
- if unknown:
- filestat.append('?')
- cache_files = [x for x in cache_files if x[0] in filestat]
-
- for fs in cache_files:
- if all:
- print '%s %s' % (fs[0], fs[1])
- else:
- print '%s' % fs[1]
-
-def diff(files = None, rev1 = 'HEAD', rev2 = None, out_fd = None):
+ p = GRun('merge-recursive', base, '--', head1, head2).env(
+ { 'GITHEAD_%s' % base: 'ancestor',
+ 'GITHEAD_%s' % head1: 'current',
+ 'GITHEAD_%s' % head2: 'patched'}).returns([0, 1])
+ output = p.output_lines()
+ if p.exitcode:
+ # There were conflicts
+ conflicts = [l.strip() for l in output if l.startswith('CONFLICT')]
+ out.info(*conflicts)
+
+ # try the interactive merge or stage checkout (if enabled)
+ for filename in get_conflicts():
+ if (gitmergeonefile.merge(filename)):
+ # interactive merge succeeded
+ resolved([filename])
+
+ # any conflicts left unsolved?
+ cn = len(get_conflicts())
+ if cn:
+ raise GitException, "%d conflict(s)" % cn
+
+def diff(files = None, rev1 = 'HEAD', rev2 = None, diff_flags = [],
+ binary = True):