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

View File

@@ -598,7 +598,12 @@ void git_blame_free(git_blame *blame);
typedef enum { ... } git_merge_tree_flag_t; 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 { typedef struct {
unsigned int version; unsigned int version;
@@ -609,5 +614,7 @@ typedef struct {
git_merge_file_favor_t file_favor; git_merge_file_favor_t file_favor;
} git_merge_options; } 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); 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);

View File

@@ -510,7 +510,7 @@ class Repository(_Repository):
# #
# Merging # Merging
# #
def merge_commits(self, ours, theirs): def merge_commits(self, ours, theirs, favor='normal'):
"""Merge two arbitrary commits """Merge two arbitrary commits
Arguments: Arguments:
@@ -519,16 +519,37 @@ class Repository(_Repository):
The commit to take as "ours" or base. The commit to take as "ours" or base.
theirs theirs
The commit which will be merged into "ours" 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. (string or Oid) of an object which peels to a commit.
Returns an index with the result of the merge 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 **') ours_ptr = ffi.new('git_commit **')
theirs_ptr = ffi.new('git_commit **') theirs_ptr = ffi.new('git_commit **')
opts = ffi.new('git_merge_options *')
cindex = ffi.new('git_index **') cindex = ffi.new('git_index **')
if is_string(ours) or isinstance(ours, Oid): if is_string(ours) or isinstance(ours, Oid):
@@ -539,10 +560,19 @@ class Repository(_Repository):
ours = ours.peel(Commit) ours = ours.peel(Commit)
theirs = theirs.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(ours_ptr)[:] = ours._pointer[:]
ffi.buffer(theirs_ptr)[:] = theirs._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) check_error(err)
return Index.from_c(self, cindex) return Index.from_c(self, cindex)

View File

@@ -158,3 +158,10 @@ class MergeCommitsTest(utils.RepoTestCaseForMerging):
merge_tree = index.write_tree() merge_tree = index.write_tree()
self.assertEqual(merge_tree, merge_commits_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')