Skip to content

Commit f5485bb

Browse files
committed
Merge remote-tracking branch 'pks/bare-conflicts'
2 parents 318c6a8 + 367084e commit f5485bb

3 files changed

Lines changed: 93 additions & 0 deletions

File tree

pygit2/decl.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,8 +657,34 @@ typedef struct {
657657
git_merge_file_favor_t file_favor;
658658
} git_merge_options;
659659

660+
typedef struct {
661+
unsigned int automergeable;
662+
const char *path;
663+
unsigned int mode;
664+
const char *ptr;
665+
size_t len;
666+
} git_merge_file_result;
667+
668+
typedef enum {
669+
GIT_MERGE_FILE_DEFAULT = 0,
670+
GIT_MERGE_FILE_STYLE_MERGE = 1,
671+
GIT_MERGE_FILE_STYLE_DIFF3 = 2,
672+
GIT_MERGE_FILE_SIMPLIFY_ALNUM = 4,
673+
} git_merge_file_flags_t;
674+
675+
typedef struct {
676+
unsigned int version;
677+
const char *ancestor_label;
678+
const char *our_label;
679+
const char *their_label;
680+
git_merge_file_favor_t favor;
681+
git_merge_file_flags_t flags;
682+
} git_merge_file_options;
683+
660684
#define GIT_MERGE_OPTIONS_VERSION ...
661685

662686
int git_merge_init_options(git_merge_options *opts, unsigned int version);
663687
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);
664688
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);
689+
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);
690+
void git_merge_file_result_free(git_merge_file_result *result);

pygit2/repository.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,40 @@ def favor_to_enum(favor):
526526

527527
return opts
528528

529+
def merge_file_from_index(self, ancestor, ours, theirs):
530+
"""merge_file_from_index(ancestor, ours, theirs) -> str
531+
532+
Merge files from index.
533+
534+
Return a :py:class:`str` object with the merge result
535+
containing possible conflicts.
536+
537+
ancestor
538+
The index entry which will be used as a common
539+
ancestor.
540+
ours
541+
The index entry to take as "ours" or base.
542+
theirs
543+
The index entry which will be merged into "ours"
544+
"""
545+
cmergeresult = ffi.new('git_merge_file_result *')
546+
547+
cancestor = ancestor._to_c()[0] if ancestor is not None else ffi.NULL
548+
cours = ours._to_c()[0] if ours is not None else ffi.NULL
549+
ctheirs = theirs._to_c()[0] if theirs is not None else ffi.NULL
550+
551+
err = C.git_merge_file_from_index(
552+
cmergeresult, self._repo,
553+
cancestor, cours, ctheirs,
554+
ffi.NULL);
555+
check_error(err)
556+
557+
ret = ffi.string(cmergeresult.ptr,
558+
cmergeresult.len).decode()
559+
C.git_merge_file_result_free(cmergeresult)
560+
561+
return ret
562+
529563
def merge_commits(self, ours, theirs, favor='normal'):
530564
"""Merge two arbitrary commits
531565

test/test_repository.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,39 @@ def test_hashfile(self):
198198
written_sha1 = self.repo.create_blob(data)
199199
self.assertEqual(hashed_sha1, written_sha1)
200200

201+
def test_conflicts_in_bare_repository(self):
202+
def create_conflict_file(repo, branch, content):
203+
oid = repo.create_blob(content)
204+
tb = repo.TreeBuilder()
205+
tb.insert('conflict', oid, pygit2.GIT_FILEMODE_BLOB)
206+
tree = tb.write()
207+
208+
sig = pygit2.Signature('Author', 'author@example.com')
209+
commit = repo.create_commit(branch.name, sig, sig,
210+
'Conflict', tree, [branch.target])
211+
self.assertIsNotNone(commit)
212+
return commit
213+
214+
b1 = self.repo.create_branch('b1', self.repo.head.peel())
215+
c1 = create_conflict_file(self.repo, b1, 'Conflict 1')
216+
b2 = self.repo.create_branch('b2', self.repo.head.peel())
217+
c2 = create_conflict_file(self.repo, b2, 'Conflict 2')
218+
219+
index = self.repo.merge_commits(c1, c2)
220+
self.assertIsNotNone(index.conflicts)
221+
222+
# ConflictCollection does not allow calling len(...) on it directly so
223+
# we have to calculate length by iterating over its entries
224+
self.assertEqual(sum(1 for _ in index.conflicts), 1)
225+
226+
(a, t, o) = index.conflicts['conflict']
227+
diff = self.repo.merge_file_from_index(a, t, o)
228+
self.assertEqual(diff, '''<<<<<<< conflict
229+
Conflict 1
230+
=======
231+
Conflict 2
232+
>>>>>>> conflict
233+
''')
201234

202235
class RepositoryTest_II(utils.RepoTestCase):
203236

0 commit comments

Comments
 (0)