Repository: allow passing a favor option to merge_commits

I've gone with taking a string and converting it because the depth of
the namespacing in the libgit2 name is rather large and we don't care
about the global namespace that C has; and this also lets us pass the
same as the '-X' option to git-merge.
This commit is contained in:
Carlos Martín Nieto 2014-10-30 16:21:22 +01:00
parent 3b27e16d08
commit bc8b29b4f3
3 changed files with 48 additions and 4 deletions

@ -598,7 +598,12 @@ void git_blame_free(git_blame *blame);
typedef enum { ... } git_merge_tree_flag_t;
typedef enum { ... } git_merge_file_favor_t;
typedef enum {
GIT_MERGE_FILE_FAVOR_NORMAL = 0,
GIT_MERGE_FILE_FAVOR_OURS = 1,
GIT_MERGE_FILE_FAVOR_THEIRS = 2,
GIT_MERGE_FILE_FAVOR_UNION = 3,
} git_merge_file_favor_t;
typedef struct {
unsigned int version;
@ -609,5 +614,7 @@ typedef struct {
git_merge_file_favor_t file_favor;
} git_merge_options;
#define GIT_MERGE_OPTIONS_VERSION ...
int git_merge_init_options(git_merge_options *opts, unsigned int version);
int git_merge_commits(git_index **out, git_repository *repo, const git_commit *our_commit, const git_commit *their_commit, const git_merge_options *opts);

@ -510,7 +510,7 @@ class Repository(_Repository):
#
# Merging
#
def merge_commits(self, ours, theirs):
def merge_commits(self, ours, theirs, favor='normal'):
"""Merge two arbitrary commits
Arguments:
@ -519,16 +519,37 @@ class Repository(_Repository):
The commit to take as "ours" or base.
theirs
The commit which will be merged into "ours"
favor
How to deal with file-level conflicts. Can be one of
Both can be any object which peels to a commit or the id
* normal (default). Conflicts will be preserved.
* ours. The "ours" side of the conflict region is used.
* theirs. The "theirs" side of the conflict region is used.
* union. Unique lines from each side will be used.
for all but NORMAL, the index will not record a conflict.
Both "ours" and "theirs" can be any object which peels to a commit or the id
(string or Oid) of an object which peels to a commit.
Returns an index with the result of the merge
"""
def favor_to_enum(favor):
if favor == 'normal':
return C.GIT_MERGE_FILE_FAVOR_NORMAL
elif favor == 'ours':
return C.GIT_MERGE_FILE_FAVOR_OURS
elif favor == 'theirs':
return C.GIT_MERGE_FILE_FAVOR_THEIRS
elif favor == 'union':
return C.GIT_MERGE_FILE_FAVOR_UNION
else:
return None
ours_ptr = ffi.new('git_commit **')
theirs_ptr = ffi.new('git_commit **')
opts = ffi.new('git_merge_options *')
cindex = ffi.new('git_index **')
if is_string(ours) or isinstance(ours, Oid):
@ -539,10 +560,19 @@ class Repository(_Repository):
ours = ours.peel(Commit)
theirs = theirs.peel(Commit)
err = C.git_merge_init_options(opts, C.GIT_MERGE_OPTIONS_VERSION)
check_error(err)
favor_val = favor_to_enum(favor)
if favor_val is None:
raise ValueError("unkown favor value %s" % favor)
opts.file_favor = favor_val
ffi.buffer(ours_ptr)[:] = ours._pointer[:]
ffi.buffer(theirs_ptr)[:] = theirs._pointer[:]
err = C.git_merge_commits(cindex, self._repo, ours_ptr[0], theirs_ptr[0], ffi.NULL)
err = C.git_merge_commits(cindex, self._repo, ours_ptr[0], theirs_ptr[0], opts)
check_error(err)
return Index.from_c(self, cindex)

@ -158,3 +158,10 @@ class MergeCommitsTest(utils.RepoTestCaseForMerging):
merge_tree = index.write_tree()
self.assertEqual(merge_tree, merge_commits_tree)
def test_merge_commits_favor(self):
branch_head_hex = '1b2bae55ac95a4be3f8983b86cd579226d0eb247'
merge_index = self.repo.merge_commits(self.repo.head.target, branch_head_hex, favor='ours')
self.assertTrue(merge_index.conflicts is None)
self.assertRaises(ValueError, self.repo.merge_commits, self.repo.head.target, branch_head_hex, favor='foo')