Merge remote-tracking branch 'pks/bare-conflicts'

This commit is contained in:
J. David Ibáñez 2015-03-13 10:09:31 +01:00
commit f5485bb86f
3 changed files with 93 additions and 0 deletions

@ -657,8 +657,34 @@ typedef struct {
git_merge_file_favor_t file_favor;
} git_merge_options;
typedef struct {
unsigned int automergeable;
const char *path;
unsigned int mode;
const char *ptr;
size_t len;
} git_merge_file_result;
typedef enum {
GIT_MERGE_FILE_DEFAULT = 0,
GIT_MERGE_FILE_STYLE_MERGE = 1,
GIT_MERGE_FILE_STYLE_DIFF3 = 2,
GIT_MERGE_FILE_SIMPLIFY_ALNUM = 4,
} git_merge_file_flags_t;
typedef struct {
unsigned int version;
const char *ancestor_label;
const char *our_label;
const char *their_label;
git_merge_file_favor_t favor;
git_merge_file_flags_t flags;
} git_merge_file_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_trees(git_index **out, git_repository *repo, const git_tree *ancestor_tree, const git_tree *our_tree, const git_tree *their_tree, const git_merge_options *opts);
int git_merge_file_from_index(git_merge_file_result *out, git_repository *repo, const git_index_entry *ancestor, const git_index_entry *ours, const git_index_entry *theirs, const git_merge_file_options *opts);
void git_merge_file_result_free(git_merge_file_result *result);

@ -526,6 +526,40 @@ class Repository(_Repository):
return opts
def merge_file_from_index(self, ancestor, ours, theirs):
"""merge_file_from_index(ancestor, ours, theirs) -> str
Merge files from index.
Return a :py:class:`str` object with the merge result
containing possible conflicts.
ancestor
The index entry which will be used as a common
ancestor.
ours
The index entry to take as "ours" or base.
theirs
The index entry which will be merged into "ours"
"""
cmergeresult = ffi.new('git_merge_file_result *')
cancestor = ancestor._to_c()[0] if ancestor is not None else ffi.NULL
cours = ours._to_c()[0] if ours is not None else ffi.NULL
ctheirs = theirs._to_c()[0] if theirs is not None else ffi.NULL
err = C.git_merge_file_from_index(
cmergeresult, self._repo,
cancestor, cours, ctheirs,
ffi.NULL);
check_error(err)
ret = ffi.string(cmergeresult.ptr,
cmergeresult.len).decode()
C.git_merge_file_result_free(cmergeresult)
return ret
def merge_commits(self, ours, theirs, favor='normal'):
"""Merge two arbitrary commits

@ -198,6 +198,39 @@ class RepositoryTest(utils.BareRepoTestCase):
written_sha1 = self.repo.create_blob(data)
self.assertEqual(hashed_sha1, written_sha1)
def test_conflicts_in_bare_repository(self):
def create_conflict_file(repo, branch, content):
oid = repo.create_blob(content)
tb = repo.TreeBuilder()
tb.insert('conflict', oid, pygit2.GIT_FILEMODE_BLOB)
tree = tb.write()
sig = pygit2.Signature('Author', 'author@example.com')
commit = repo.create_commit(branch.name, sig, sig,
'Conflict', tree, [branch.target])
self.assertIsNotNone(commit)
return commit
b1 = self.repo.create_branch('b1', self.repo.head.peel())
c1 = create_conflict_file(self.repo, b1, 'Conflict 1')
b2 = self.repo.create_branch('b2', self.repo.head.peel())
c2 = create_conflict_file(self.repo, b2, 'Conflict 2')
index = self.repo.merge_commits(c1, c2)
self.assertIsNotNone(index.conflicts)
# ConflictCollection does not allow calling len(...) on it directly so
# we have to calculate length by iterating over its entries
self.assertEqual(sum(1 for _ in index.conflicts), 1)
(a, t, o) = index.conflicts['conflict']
diff = self.repo.merge_file_from_index(a, t, o)
self.assertEqual(diff, '''<<<<<<< conflict
Conflict 1
=======
Conflict 2
>>>>>>> conflict
''')
class RepositoryTest_II(utils.RepoTestCase):