This PR adds
- The ability to apply a Diff object to the repo
- Support for git_apply_hunk_cb and git_apply_delta_cb callbacks in options for applying the diffs
- The ability to import a diff from a raw buffer (for example, one exported by ToBuf) into a Diff object associated with the repo
- Tests for the above
(cherry picked from commit 7883ec85de
)
This commit is contained in:
parent
0430fd700c
commit
4d69027787
174
diff.go
174
diff.go
|
@ -3,6 +3,7 @@ package git
|
||||||
/*
|
/*
|
||||||
#include <git2.h>
|
#include <git2.h>
|
||||||
|
|
||||||
|
extern void _go_git_populate_apply_cb(git_apply_options *options);
|
||||||
extern int _go_git_diff_foreach(git_diff *diff, int eachFile, int eachHunk, int eachLine, void *payload);
|
extern int _go_git_diff_foreach(git_diff *diff, int eachFile, int eachHunk, int eachLine, void *payload);
|
||||||
extern void _go_git_setup_diff_notify_callbacks(git_diff_options* opts);
|
extern void _go_git_setup_diff_notify_callbacks(git_diff_options* opts);
|
||||||
extern int _go_git_diff_blobs(git_blob *old, const char *old_path, git_blob *new, const char *new_path, git_diff_options *opts, int eachFile, int eachHunk, int eachLine, void *payload);
|
extern int _go_git_diff_blobs(git_blob *old, const char *old_path, git_blob *new, const char *new_path, git_diff_options *opts, int eachFile, int eachHunk, int eachLine, void *payload);
|
||||||
|
@ -550,7 +551,7 @@ const (
|
||||||
DiffFindRemoveUnmodified DiffFindOptionsFlag = C.GIT_DIFF_FIND_REMOVE_UNMODIFIED
|
DiffFindRemoveUnmodified DiffFindOptionsFlag = C.GIT_DIFF_FIND_REMOVE_UNMODIFIED
|
||||||
)
|
)
|
||||||
|
|
||||||
//TODO implement git_diff_similarity_metric
|
// TODO implement git_diff_similarity_metric
|
||||||
type DiffFindOptions struct {
|
type DiffFindOptions struct {
|
||||||
Flags DiffFindOptionsFlag
|
Flags DiffFindOptionsFlag
|
||||||
RenameThreshold uint16
|
RenameThreshold uint16
|
||||||
|
@ -847,3 +848,174 @@ func DiffBlobs(oldBlob *Blob, oldAsPath string, newBlob *Blob, newAsPath string,
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ApplyHunkCallback is a callback that will be made per delta (file) when applying a patch.
|
||||||
|
type ApplyHunkCallback func(*DiffHunk) (apply bool, err error)
|
||||||
|
|
||||||
|
// ApplyDeltaCallback is a callback that will be made per hunk when applying a patch.
|
||||||
|
type ApplyDeltaCallback func(*DiffDelta) (apply bool, err error)
|
||||||
|
|
||||||
|
// ApplyOptions has 2 callbacks that are called for hunks or deltas
|
||||||
|
// If these functions return an error, abort the apply process immediately.
|
||||||
|
// If the first return value is true, the delta/hunk will be applied. If it is false, the delta/hunk will not be applied. In either case, the rest of the apply process will continue.
|
||||||
|
type ApplyOptions struct {
|
||||||
|
ApplyHunkCallback ApplyHunkCallback
|
||||||
|
ApplyDeltaCallback ApplyDeltaCallback
|
||||||
|
Flags uint
|
||||||
|
}
|
||||||
|
|
||||||
|
//export hunkApplyCallback
|
||||||
|
func hunkApplyCallback(_hunk *C.git_diff_hunk, _payload unsafe.Pointer) C.int {
|
||||||
|
opts, ok := pointerHandles.Get(_payload).(*ApplyOptions)
|
||||||
|
if !ok {
|
||||||
|
panic("invalid apply options payload")
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.ApplyHunkCallback == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
hunk := diffHunkFromC(_hunk)
|
||||||
|
|
||||||
|
apply, err := opts.ApplyHunkCallback(&hunk)
|
||||||
|
if err != nil {
|
||||||
|
if gitError, ok := err.(*GitError); ok {
|
||||||
|
return C.int(gitError.Code)
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
} else if apply {
|
||||||
|
return 0
|
||||||
|
} else {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export deltaApplyCallback
|
||||||
|
func deltaApplyCallback(_delta *C.git_diff_delta, _payload unsafe.Pointer) C.int {
|
||||||
|
opts, ok := pointerHandles.Get(_payload).(*ApplyOptions)
|
||||||
|
if !ok {
|
||||||
|
panic("invalid apply options payload")
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.ApplyDeltaCallback == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
delta := diffDeltaFromC(_delta)
|
||||||
|
|
||||||
|
apply, err := opts.ApplyDeltaCallback(&delta)
|
||||||
|
if err != nil {
|
||||||
|
if gitError, ok := err.(*GitError); ok {
|
||||||
|
return C.int(gitError.Code)
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
} else if apply {
|
||||||
|
return 0
|
||||||
|
} else {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultApplyOptions returns default options for applying diffs or patches.
|
||||||
|
func DefaultApplyOptions() (*ApplyOptions, error) {
|
||||||
|
opts := C.git_apply_options{}
|
||||||
|
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
ecode := C.git_apply_options_init(&opts, C.GIT_APPLY_OPTIONS_VERSION)
|
||||||
|
if int(ecode) != 0 {
|
||||||
|
|
||||||
|
return nil, MakeGitError(ecode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return applyOptionsFromC(&opts), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ApplyOptions) toC() *C.git_apply_options {
|
||||||
|
if a == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := &C.git_apply_options{
|
||||||
|
version: C.GIT_APPLY_OPTIONS_VERSION,
|
||||||
|
flags: C.uint(a.Flags),
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.ApplyDeltaCallback != nil || a.ApplyHunkCallback != nil {
|
||||||
|
C._go_git_populate_apply_cb(opts)
|
||||||
|
opts.payload = pointerHandles.Track(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
return opts
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyOptionsFromC(opts *C.git_apply_options) *ApplyOptions {
|
||||||
|
return &ApplyOptions{
|
||||||
|
Flags: uint(opts.flags),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyLocation represents the possible application locations for applying
|
||||||
|
// diffs.
|
||||||
|
type ApplyLocation int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ApplyLocationWorkdir applies the patch to the workdir, leaving the
|
||||||
|
// index untouched. This is the equivalent of `git apply` with no location
|
||||||
|
// argument.
|
||||||
|
ApplyLocationWorkdir ApplyLocation = C.GIT_APPLY_LOCATION_WORKDIR
|
||||||
|
// ApplyLocationIndex applies the patch to the index, leaving the working
|
||||||
|
// directory untouched. This is the equivalent of `git apply --cached`.
|
||||||
|
ApplyLocationIndex ApplyLocation = C.GIT_APPLY_LOCATION_INDEX
|
||||||
|
// ApplyLocationBoth applies the patch to both the working directory and
|
||||||
|
// the index. This is the equivalent of `git apply --index`.
|
||||||
|
ApplyLocationBoth ApplyLocation = C.GIT_APPLY_LOCATION_BOTH
|
||||||
|
)
|
||||||
|
|
||||||
|
// ApplyDiff appllies a Diff to the given repository, making changes directly
|
||||||
|
// in the working directory, the index, or both.
|
||||||
|
func (v *Repository) ApplyDiff(diff *Diff, location ApplyLocation, opts *ApplyOptions) error {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
cOpts := opts.toC()
|
||||||
|
ecode := C.git_apply(v.ptr, diff.ptr, C.git_apply_location_t(location), cOpts)
|
||||||
|
runtime.KeepAlive(v)
|
||||||
|
runtime.KeepAlive(diff)
|
||||||
|
runtime.KeepAlive(cOpts)
|
||||||
|
if ecode < 0 {
|
||||||
|
return MakeGitError(ecode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiffFromBuffer reads the contents of a git patch file into a Diff object.
|
||||||
|
//
|
||||||
|
// The diff object produced is similar to the one that would be produced if you
|
||||||
|
// actually produced it computationally by comparing two trees, however there
|
||||||
|
// may be subtle differences. For example, a patch file likely contains
|
||||||
|
// abbreviated object IDs, so the object IDs in a git_diff_delta produced by
|
||||||
|
// this function will also be abbreviated.
|
||||||
|
//
|
||||||
|
// This function will only read patch files created by a git implementation, it
|
||||||
|
// will not read unified diffs produced by the diff program, nor any other
|
||||||
|
// types of patch files.
|
||||||
|
func DiffFromBuffer(buffer []byte, repo *Repository) (*Diff, error) {
|
||||||
|
var diff *C.git_diff
|
||||||
|
|
||||||
|
cBuffer := C.CBytes(buffer)
|
||||||
|
defer C.free(unsafe.Pointer(cBuffer))
|
||||||
|
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
ecode := C.git_diff_from_buffer(&diff, (*C.char)(cBuffer), C.size_t(len(buffer)))
|
||||||
|
if ecode < 0 {
|
||||||
|
return nil, MakeGitError(ecode)
|
||||||
|
}
|
||||||
|
runtime.KeepAlive(diff)
|
||||||
|
|
||||||
|
return newDiffFromC(diff, repo), nil
|
||||||
|
}
|
||||||
|
|
307
diff_test.go
307
diff_test.go
|
@ -2,6 +2,9 @@ package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -236,3 +239,307 @@ func TestDiffBlobs(t *testing.T) {
|
||||||
t.Fatalf("Bad number of lines iterated")
|
t.Fatalf("Bad number of lines iterated")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestApplyDiffAddfile(t *testing.T) {
|
||||||
|
repo := createTestRepo(t)
|
||||||
|
defer cleanupTestRepo(t, repo)
|
||||||
|
|
||||||
|
seedTestRepo(t, repo)
|
||||||
|
|
||||||
|
addFirstFileCommit, addFileTree := addAndGetTree(t, repo, "file1", `hello`)
|
||||||
|
addSecondFileCommit, addSecondFileTree := addAndGetTree(t, repo, "file2", `hello2`)
|
||||||
|
|
||||||
|
diff, err := repo.DiffTreeToTree(addFileTree, addSecondFileTree, nil)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
t.Run("check does not apply to current tree because file exists", func(t *testing.T) {
|
||||||
|
err = repo.ResetToCommit(addSecondFileCommit, ResetHard, &CheckoutOpts{})
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
err = repo.ApplyDiff(diff, ApplyLocationBoth, nil)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expecting applying patch to current repo to fail")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("check apply to correct commit", func(t *testing.T) {
|
||||||
|
err = repo.ResetToCommit(addFirstFileCommit, ResetHard, &CheckoutOpts{})
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
err = repo.ApplyDiff(diff, ApplyLocationBoth, nil)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
t.Run("Check that diff only changed one file", func(t *testing.T) {
|
||||||
|
checkSecondFileStaged(t, repo)
|
||||||
|
|
||||||
|
index, err := repo.Index()
|
||||||
|
checkFatal(t, err)
|
||||||
|
defer index.Free()
|
||||||
|
|
||||||
|
newTreeOID, err := index.WriteTreeTo(repo)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
newTree, err := repo.LookupTree(newTreeOID)
|
||||||
|
checkFatal(t, err)
|
||||||
|
defer newTree.Free()
|
||||||
|
|
||||||
|
_, err = repo.CreateCommit("HEAD", signature(), signature(), fmt.Sprintf("patch apply"), newTree, addFirstFileCommit)
|
||||||
|
checkFatal(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("test applying patch produced the same diff", func(t *testing.T) {
|
||||||
|
head, err := repo.Head()
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
commit, err := repo.LookupCommit(head.Target())
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
tree, err := commit.Tree()
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
newDiff, err := repo.DiffTreeToTree(addFileTree, tree, nil)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
raw1b, err := diff.ToBuf(DiffFormatPatch)
|
||||||
|
checkFatal(t, err)
|
||||||
|
raw2b, err := newDiff.ToBuf(DiffFormatPatch)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
raw1 := string(raw1b)
|
||||||
|
raw2 := string(raw2b)
|
||||||
|
|
||||||
|
if raw1 != raw2 {
|
||||||
|
t.Error("diffs should be the same")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("check convert to raw buffer and apply", func(t *testing.T) {
|
||||||
|
err = repo.ResetToCommit(addFirstFileCommit, ResetHard, &CheckoutOpts{})
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
raw, err := diff.ToBuf(DiffFormatPatch)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
if len(raw) == 0 {
|
||||||
|
t.Error("empty diff created")
|
||||||
|
}
|
||||||
|
|
||||||
|
diff2, err := DiffFromBuffer(raw, repo)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
err = repo.ApplyDiff(diff2, ApplyLocationBoth, nil)
|
||||||
|
checkFatal(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("check apply callbacks work", func(t *testing.T) {
|
||||||
|
// reset the state and get new default options for test
|
||||||
|
resetAndGetOpts := func(t *testing.T) *ApplyOptions {
|
||||||
|
err = repo.ResetToCommit(addFirstFileCommit, ResetHard, &CheckoutOpts{})
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
opts, err := DefaultApplyOptions()
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
return opts
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Check hunk callback working applies patch", func(t *testing.T) {
|
||||||
|
opts := resetAndGetOpts(t)
|
||||||
|
|
||||||
|
called := false
|
||||||
|
opts.ApplyHunkCallback = func(hunk *DiffHunk) (apply bool, err error) {
|
||||||
|
called = true
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = repo.ApplyDiff(diff, ApplyLocationBoth, opts)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
if called == false {
|
||||||
|
t.Error("apply hunk callback was not called")
|
||||||
|
}
|
||||||
|
|
||||||
|
checkSecondFileStaged(t, repo)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Check delta callback working applies patch", func(t *testing.T) {
|
||||||
|
opts := resetAndGetOpts(t)
|
||||||
|
|
||||||
|
called := false
|
||||||
|
opts.ApplyDeltaCallback = func(hunk *DiffDelta) (apply bool, err error) {
|
||||||
|
if hunk.NewFile.Path != "file2" {
|
||||||
|
t.Error("Unexpected delta in diff application")
|
||||||
|
}
|
||||||
|
called = true
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = repo.ApplyDiff(diff, ApplyLocationBoth, opts)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
if called == false {
|
||||||
|
t.Error("apply hunk callback was not called")
|
||||||
|
}
|
||||||
|
|
||||||
|
checkSecondFileStaged(t, repo)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Check delta callback returning false does not apply patch", func(t *testing.T) {
|
||||||
|
opts := resetAndGetOpts(t)
|
||||||
|
|
||||||
|
called := false
|
||||||
|
opts.ApplyDeltaCallback = func(hunk *DiffDelta) (apply bool, err error) {
|
||||||
|
if hunk.NewFile.Path != "file2" {
|
||||||
|
t.Error("Unexpected hunk in diff application")
|
||||||
|
}
|
||||||
|
called = true
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = repo.ApplyDiff(diff, ApplyLocationBoth, opts)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
if called == false {
|
||||||
|
t.Error("apply hunk callback was not called")
|
||||||
|
}
|
||||||
|
|
||||||
|
checkNoFilesStaged(t, repo)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Check hunk callback returning causes application to fail", func(t *testing.T) {
|
||||||
|
opts := resetAndGetOpts(t)
|
||||||
|
|
||||||
|
called := false
|
||||||
|
opts.ApplyHunkCallback = func(hunk *DiffHunk) (apply bool, err error) {
|
||||||
|
called = true
|
||||||
|
return false, errors.New("something happened")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = repo.ApplyDiff(diff, ApplyLocationBoth, opts)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected an error after trying to apply")
|
||||||
|
}
|
||||||
|
|
||||||
|
if called == false {
|
||||||
|
t.Error("apply hunk callback was not called")
|
||||||
|
}
|
||||||
|
|
||||||
|
checkNoFilesStaged(t, repo)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Check delta callback returning causes application to fail", func(t *testing.T) {
|
||||||
|
opts := resetAndGetOpts(t)
|
||||||
|
|
||||||
|
called := false
|
||||||
|
opts.ApplyDeltaCallback = func(hunk *DiffDelta) (apply bool, err error) {
|
||||||
|
if hunk.NewFile.Path != "file2" {
|
||||||
|
t.Error("Unexpected delta in diff application")
|
||||||
|
}
|
||||||
|
called = true
|
||||||
|
return false, errors.New("something happened")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = repo.ApplyDiff(diff, ApplyLocationBoth, opts)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected an error after trying to apply")
|
||||||
|
}
|
||||||
|
|
||||||
|
if called == false {
|
||||||
|
t.Error("apply hunk callback was not called")
|
||||||
|
}
|
||||||
|
|
||||||
|
checkNoFilesStaged(t, repo)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkSecondFileStaged checks that there is a single file called "file2" uncommitted in the repo
|
||||||
|
func checkSecondFileStaged(t *testing.T, repo *Repository) {
|
||||||
|
opts := StatusOptions{
|
||||||
|
Show: StatusShowIndexAndWorkdir,
|
||||||
|
Flags: StatusOptIncludeUntracked,
|
||||||
|
}
|
||||||
|
|
||||||
|
statuses, err := repo.StatusList(&opts)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
count, err := statuses.EntryCount()
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
if count != 1 {
|
||||||
|
t.Error("diff should affect exactly one file")
|
||||||
|
}
|
||||||
|
if count == 0 {
|
||||||
|
t.Fatal("no statuses, cannot continue test")
|
||||||
|
}
|
||||||
|
|
||||||
|
entry, err := statuses.ByIndex(0)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
if entry.Status != StatusIndexNew {
|
||||||
|
t.Error("status should be 'new' as file has been added between commits")
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry.HeadToIndex.NewFile.Path != "file2" {
|
||||||
|
t.Error("new file should be 'file2")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkNoFilesStaged checks that there is a single file called "file2" uncommitted in the repo
|
||||||
|
func checkNoFilesStaged(t *testing.T, repo *Repository) {
|
||||||
|
opts := StatusOptions{
|
||||||
|
Show: StatusShowIndexAndWorkdir,
|
||||||
|
Flags: StatusOptIncludeUntracked,
|
||||||
|
}
|
||||||
|
|
||||||
|
statuses, err := repo.StatusList(&opts)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
count, err := statuses.EntryCount()
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
if count != 0 {
|
||||||
|
t.Error("files changed unexpectedly")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// addAndGetTree creates a file and commits it, returning the commit and tree
|
||||||
|
func addAndGetTree(t *testing.T, repo *Repository, filename string, content string) (*Commit, *Tree) {
|
||||||
|
headCommit, err := headCommit(repo)
|
||||||
|
checkFatal(t, err)
|
||||||
|
defer headCommit.Free()
|
||||||
|
|
||||||
|
p := repo.Path()
|
||||||
|
p = strings.TrimSuffix(p, ".git")
|
||||||
|
p = strings.TrimSuffix(p, ".git/")
|
||||||
|
|
||||||
|
err = ioutil.WriteFile(path.Join(p, filename), []byte((content)), 0777)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
index, err := repo.Index()
|
||||||
|
checkFatal(t, err)
|
||||||
|
defer index.Free()
|
||||||
|
|
||||||
|
err = index.AddByPath(filename)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
newTreeOID, err := index.WriteTreeTo(repo)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
newTree, err := repo.LookupTree(newTreeOID)
|
||||||
|
checkFatal(t, err)
|
||||||
|
defer newTree.Free()
|
||||||
|
|
||||||
|
commitId, err := repo.CreateCommit("HEAD", signature(), signature(), fmt.Sprintf("add %s", filename), newTree, headCommit)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
commit, err := repo.LookupCommit(commitId)
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
tree, err := commit.Tree()
|
||||||
|
checkFatal(t, err)
|
||||||
|
|
||||||
|
return commit, tree
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,12 @@
|
||||||
|
|
||||||
typedef int (*gogit_submodule_cbk)(git_submodule *sm, const char *name, void *payload);
|
typedef int (*gogit_submodule_cbk)(git_submodule *sm, const char *name, void *payload);
|
||||||
|
|
||||||
|
void _go_git_populate_apply_cb(git_apply_options *options)
|
||||||
|
{
|
||||||
|
options->delta_cb = (git_apply_delta_cb)deltaApplyCallback;
|
||||||
|
options->hunk_cb = (git_apply_hunk_cb)hunkApplyCallback;
|
||||||
|
}
|
||||||
|
|
||||||
void _go_git_populate_remote_cb(git_clone_options *opts)
|
void _go_git_populate_remote_cb(git_clone_options *opts)
|
||||||
{
|
{
|
||||||
opts->remote_cb = (git_remote_create_cb)remoteCreateCallback;
|
opts->remote_cb = (git_remote_create_cb)remoteCreateCallback;
|
||||||
|
|
Loading…
Reference in New Issue