From bc8b29b4f3ae498a6c4093989d6842df2129271e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 30 Oct 2014 16:21:22 +0100 Subject: [PATCH] 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. --- pygit2/decl.h | 9 ++++++++- pygit2/repository.py | 36 +++++++++++++++++++++++++++++++++--- test/test_merge.py | 7 +++++++ 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/pygit2/decl.h b/pygit2/decl.h index b389be9..5c4d9a6 100644 --- a/pygit2/decl.h +++ b/pygit2/decl.h @@ -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); diff --git a/pygit2/repository.py b/pygit2/repository.py index a50720b..239af12 100644 --- a/pygit2/repository.py +++ b/pygit2/repository.py @@ -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) diff --git a/test/test_merge.py b/test/test_merge.py index 230ac49..10d1c54 100644 --- a/test/test_merge.py +++ b/test/test_merge.py @@ -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')