Skip to content

Commit 698ddfb

Browse files
authored
Support more MergeBase functions (#720)
This change adds support for MergeBaseMany, MergeBasesMany, and MergeBaseOctopus.
1 parent 10c6747 commit 698ddfb

File tree

2 files changed

+134
-3
lines changed

2 files changed

+134
-3
lines changed

merge.go

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ func (r *Repository) MergeBases(one, two *Oid) ([]*Oid, error) {
333333
runtime.KeepAlive(one)
334334
runtime.KeepAlive(two)
335335
if ret < 0 {
336-
return make([]*Oid, 0), MakeGitError(ret)
336+
return nil, MakeGitError(ret)
337337
}
338338

339339
oids := make([]*Oid, coids.count)
@@ -352,8 +352,78 @@ func (r *Repository) MergeBases(one, two *Oid) ([]*Oid, error) {
352352
return oids, nil
353353
}
354354

355-
//TODO: int git_merge_base_many(git_oid *out, git_repository *repo, size_t length, const git_oid input_array[]);
356-
//TODO: GIT_EXTERN(int) git_merge_base_octopus(git_oid *out,git_repository *repo,size_t length,const git_oid input_array[]);
355+
// MergeBaseMany finds a merge base given a list of commits.
356+
func (r *Repository) MergeBaseMany(oids []*Oid) (*Oid, error) {
357+
coids := make([]C.git_oid, len(oids))
358+
for i := 0; i < len(oids); i++ {
359+
coids[i] = *oids[i].toC()
360+
}
361+
362+
runtime.LockOSThread()
363+
defer runtime.UnlockOSThread()
364+
365+
var oid C.git_oid
366+
ret := C.git_merge_base_many(&oid, r.ptr, C.size_t(len(oids)), &coids[0])
367+
runtime.KeepAlive(r)
368+
runtime.KeepAlive(coids)
369+
if ret < 0 {
370+
return nil, MakeGitError(ret)
371+
}
372+
return newOidFromC(&oid), nil
373+
}
374+
375+
// MergeBasesMany finds all merge bases given a list of commits.
376+
func (r *Repository) MergeBasesMany(oids []*Oid) ([]*Oid, error) {
377+
inCoids := make([]C.git_oid, len(oids))
378+
for i := 0; i < len(oids); i++ {
379+
inCoids[i] = *oids[i].toC()
380+
}
381+
382+
runtime.LockOSThread()
383+
defer runtime.UnlockOSThread()
384+
385+
var outCoids C.git_oidarray
386+
ret := C.git_merge_bases_many(&outCoids, r.ptr, C.size_t(len(oids)), &inCoids[0])
387+
runtime.KeepAlive(r)
388+
runtime.KeepAlive(inCoids)
389+
if ret < 0 {
390+
return nil, MakeGitError(ret)
391+
}
392+
393+
outOids := make([]*Oid, outCoids.count)
394+
hdr := reflect.SliceHeader{
395+
Data: uintptr(unsafe.Pointer(outCoids.ids)),
396+
Len: int(outCoids.count),
397+
Cap: int(outCoids.count),
398+
}
399+
goSlice := *(*[]C.git_oid)(unsafe.Pointer(&hdr))
400+
401+
for i, cid := range goSlice {
402+
outOids[i] = newOidFromC(&cid)
403+
}
404+
405+
return outOids, nil
406+
}
407+
408+
// MergeBaseOctopus finds a merge base in preparation for an octopus merge.
409+
func (r *Repository) MergeBaseOctopus(oids []*Oid) (*Oid, error) {
410+
coids := make([]C.git_oid, len(oids))
411+
for i := 0; i < len(oids); i++ {
412+
coids[i] = *oids[i].toC()
413+
}
414+
415+
runtime.LockOSThread()
416+
defer runtime.UnlockOSThread()
417+
418+
var oid C.git_oid
419+
ret := C.git_merge_base_octopus(&oid, r.ptr, C.size_t(len(oids)), &coids[0])
420+
runtime.KeepAlive(r)
421+
runtime.KeepAlive(coids)
422+
if ret < 0 {
423+
return nil, MakeGitError(ret)
424+
}
425+
return newOidFromC(&oid), nil
426+
}
357427

358428
type MergeFileResult struct {
359429
Automergeable bool

merge_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,15 @@ func TestMergeBase(t *testing.T) {
163163
if mergeBase.Cmp(commitAId) != 0 {
164164
t.Fatalf("unexpected merge base")
165165
}
166+
}
167+
168+
func TestMergeBases(t *testing.T) {
169+
t.Parallel()
170+
repo := createTestRepo(t)
171+
defer cleanupTestRepo(t, repo)
172+
173+
commitAId, _ := seedTestRepo(t, repo)
174+
commitBId, _ := appendCommit(t, repo)
166175

167176
mergeBases, err := repo.MergeBases(commitAId, commitBId)
168177
checkFatal(t, err)
@@ -176,6 +185,58 @@ func TestMergeBase(t *testing.T) {
176185
}
177186
}
178187

188+
func TestMergeBaseMany(t *testing.T) {
189+
t.Parallel()
190+
repo := createTestRepo(t)
191+
defer cleanupTestRepo(t, repo)
192+
193+
commitAId, _ := seedTestRepo(t, repo)
194+
commitBId, _ := appendCommit(t, repo)
195+
196+
mergeBase, err := repo.MergeBaseMany([]*Oid{commitAId, commitBId})
197+
checkFatal(t, err)
198+
199+
if mergeBase.Cmp(commitAId) != 0 {
200+
t.Fatalf("unexpected merge base")
201+
}
202+
}
203+
204+
func TestMergeBasesMany(t *testing.T) {
205+
t.Parallel()
206+
repo := createTestRepo(t)
207+
defer cleanupTestRepo(t, repo)
208+
209+
commitAId, _ := seedTestRepo(t, repo)
210+
commitBId, _ := appendCommit(t, repo)
211+
212+
mergeBases, err := repo.MergeBasesMany([]*Oid{commitAId, commitBId})
213+
checkFatal(t, err)
214+
215+
if len(mergeBases) != 1 {
216+
t.Fatalf("expected merge bases len to be 1, got %v", len(mergeBases))
217+
}
218+
219+
if mergeBases[0].Cmp(commitAId) != 0 {
220+
t.Fatalf("unexpected merge base")
221+
}
222+
}
223+
224+
func TestMergeBaseOctopus(t *testing.T) {
225+
t.Parallel()
226+
repo := createTestRepo(t)
227+
defer cleanupTestRepo(t, repo)
228+
229+
commitAId, _ := seedTestRepo(t, repo)
230+
commitBId, _ := appendCommit(t, repo)
231+
232+
mergeBase, err := repo.MergeBaseOctopus([]*Oid{commitAId, commitBId})
233+
checkFatal(t, err)
234+
235+
if mergeBase.Cmp(commitAId) != 0 {
236+
t.Fatalf("unexpected merge base")
237+
}
238+
}
239+
179240
func compareBytes(t *testing.T, expected, actual []byte) {
180241
for i, v := range expected {
181242
if actual[i] != v {

0 commit comments

Comments
 (0)