Skip to content

Commit 2a14d90

Browse files
Support more MergeBase functions (#720) (#721)
This change adds support for MergeBaseMany, MergeBasesMany, and MergeBaseOctopus. (cherry picked from commit 698ddfb) Co-authored-by: lhchavez <[email protected]>
1 parent f9b9359 commit 2a14d90

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
@@ -334,7 +334,7 @@ func (r *Repository) MergeBases(one, two *Oid) ([]*Oid, error) {
334334
runtime.KeepAlive(one)
335335
runtime.KeepAlive(two)
336336
if ret < 0 {
337-
return make([]*Oid, 0), MakeGitError(ret)
337+
return nil, MakeGitError(ret)
338338
}
339339

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

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

359429
type MergeFileResult struct {
360430
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)