Skip to content

Commit

Permalink
Merge pull request libgit2#466 from lhchavez/repository-create_commit…
Browse files Browse the repository at this point in the history
…_from_ids

Add support for CreateCommitFromIds
  • Loading branch information
carlosmn authored Jan 8, 2019
2 parents 2609f4c + 6d67bde commit 8766f9f
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 0 deletions.
70 changes: 70 additions & 0 deletions repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package git
/*
#include <git2.h>
#include <git2/sys/repository.h>
#include <git2/sys/commit.h>
#include <string.h>
*/
import "C"
import (
Expand Down Expand Up @@ -389,6 +391,74 @@ func (v *Repository) CreateCommit(
return oid, nil
}

func (v *Repository) CreateCommitFromIds(
refname string, author, committer *Signature,
message string, tree *Oid, parents ...*Oid) (*Oid, error) {

oid := new(Oid)

var cref *C.char
if refname == "" {
cref = nil
} else {
cref = C.CString(refname)
defer C.free(unsafe.Pointer(cref))
}

cmsg := C.CString(message)
defer C.free(unsafe.Pointer(cmsg))

var parentsarg **C.git_oid = nil

nparents := len(parents)
if nparents > 0 {
// All this awful pointer arithmetic is needed to avoid passing a Go
// pointer to Go pointer into C. Other methods (like CreateCommits) are
// fine without this workaround because they are just passing Go pointers
// to C pointers, but arrays-of-pointers-to-git_oid are a bit special since
// both the array and the objects are allocated from Go.
var emptyOidPtr *C.git_oid
sizeofOidPtr := unsafe.Sizeof(emptyOidPtr)
parentsarg = (**C.git_oid)(C.calloc(C.size_t(uintptr(nparents)), C.size_t(sizeofOidPtr)))
defer C.free(unsafe.Pointer(parentsarg))
parentsptr := uintptr(unsafe.Pointer(parentsarg))
for _, v := range parents {
*(**C.git_oid)(unsafe.Pointer(parentsptr)) = v.toC()
parentsptr += sizeofOidPtr
}
}

authorSig, err := author.toC()
if err != nil {
return nil, err
}
defer C.git_signature_free(authorSig)

committerSig, err := committer.toC()
if err != nil {
return nil, err
}
defer C.git_signature_free(committerSig)

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_commit_create_from_ids(
oid.toC(), v.ptr, cref,
authorSig, committerSig,
nil, cmsg, tree.toC(), C.size_t(nparents), parentsarg)

runtime.KeepAlive(v)
runtime.KeepAlive(oid)
runtime.KeepAlive(tree)
runtime.KeepAlive(parents)
if ret < 0 {
return nil, MakeGitError(ret)
}

return oid, nil
}

func (v *Odb) Free() {
runtime.SetFinalizer(v, nil)
C.git_odb_free(v.ptr)
Expand Down
42 changes: 42 additions & 0 deletions repository_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package git

import (
"testing"
"time"
)

func TestCreateCommitFromIds(t *testing.T) {
t.Parallel()
repo := createTestRepo(t)
defer cleanupTestRepo(t, repo)

loc, err := time.LoadLocation("Europe/Berlin")
checkFatal(t, err)
sig := &Signature{
Name: "Rand Om Hacker",
Email: "random@hacker.com",
When: time.Date(2013, 03, 06, 14, 30, 0, 0, loc),
}

idx, err := repo.Index()
checkFatal(t, err)
err = idx.AddByPath("README")
checkFatal(t, err)
err = idx.Write()
checkFatal(t, err)
treeId, err := idx.WriteTree()
checkFatal(t, err)

message := "This is a commit\n"
tree, err := repo.LookupTree(treeId)
checkFatal(t, err)
expectedCommitId, err := repo.CreateCommit("HEAD", sig, sig, message, tree)
checkFatal(t, err)

commitId, err := repo.CreateCommitFromIds("", sig, sig, message, treeId)
checkFatal(t, err)

if !expectedCommitId.Equal(commitId) {
t.Errorf("mismatched commit ids, expected %v, got %v", expectedCommitId.String(), commitId.String())
}
}

0 comments on commit 8766f9f

Please sign in to comment.