summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--diff.go56
-rw-r--r--diff_test.go47
-rw-r--r--remote.go1
-rw-r--r--repository.go12
-rw-r--r--wrapper.c21
5 files changed, 132 insertions, 5 deletions
diff --git a/diff.go b/diff.go
index 5e03175..de56374 100644
--- a/diff.go
+++ b/diff.go
@@ -5,6 +5,7 @@ package git
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 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);
*/
import "C"
import (
@@ -94,7 +95,7 @@ type DiffHunk struct {
Header string
}
-func diffHunkFromC(delta *C.git_diff_delta, hunk *C.git_diff_hunk) DiffHunk {
+func diffHunkFromC(hunk *C.git_diff_hunk) DiffHunk {
return DiffHunk{
OldStart: int(hunk.old_start),
OldLines: int(hunk.old_lines),
@@ -112,7 +113,7 @@ type DiffLine struct {
Content string
}
-func diffLineFromC(delta *C.git_diff_delta, hunk *C.git_diff_hunk, line *C.git_diff_line) DiffLine {
+func diffLineFromC(line *C.git_diff_line) DiffLine {
return DiffLine{
Origin: DiffLineType(line.origin),
OldLineno: int(line.old_lineno),
@@ -309,7 +310,7 @@ func diffForEachHunkCb(delta *C.git_diff_delta, hunk *C.git_diff_hunk, handle un
data.LineCallback = nil
if data.HunkCallback != nil {
- cb, err := data.HunkCallback(diffHunkFromC(delta, hunk))
+ cb, err := data.HunkCallback(diffHunkFromC(hunk))
if err != nil {
data.Error = err
return -1
@@ -330,7 +331,7 @@ func diffForEachLineCb(delta *C.git_diff_delta, hunk *C.git_diff_hunk, line *C.g
panic("could not retrieve data for handle")
}
- err := data.LineCallback(diffLineFromC(delta, hunk, line))
+ err := data.LineCallback(diffLineFromC(line))
if err != nil {
data.Error = err
return -1
@@ -670,3 +671,50 @@ func (v *Repository) DiffIndexToWorkdir(index *Index, opts *DiffOptions) (*Diff,
}
return newDiffFromC(diffPtr), nil
}
+
+// DiffBlobs performs a diff between two arbitrary blobs. You can pass
+// whatever file names you'd like for them to appear as in the diff.
+func DiffBlobs(oldBlob *Blob, oldAsPath string, newBlob *Blob, newAsPath string, opts *DiffOptions, fileCallback DiffForEachFileCallback, detail DiffDetail) error {
+ data := &diffForEachData{
+ FileCallback: fileCallback,
+ }
+
+ intHunks := C.int(0)
+ if detail >= DiffDetailHunks {
+ intHunks = C.int(1)
+ }
+
+ intLines := C.int(0)
+ if detail >= DiffDetailLines {
+ intLines = C.int(1)
+ }
+
+ handle := pointerHandles.Track(data)
+ defer pointerHandles.Untrack(handle)
+
+ var oldBlobPtr, newBlobPtr *C.git_blob
+ if oldBlob != nil {
+ oldBlobPtr = oldBlob.cast_ptr
+ }
+ if newBlob != nil {
+ newBlobPtr = newBlob.cast_ptr
+ }
+
+ oldBlobPath := C.CString(oldAsPath)
+ defer C.free(unsafe.Pointer(oldBlobPath))
+ newBlobPath := C.CString(newAsPath)
+ defer C.free(unsafe.Pointer(newBlobPath))
+
+ copts, _ := diffOptionsToC(opts)
+ defer freeDiffOptions(copts)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C._go_git_diff_blobs(oldBlobPtr, oldBlobPath, newBlobPtr, newBlobPath, copts, 1, intHunks, intLines, handle)
+ if ecode < 0 {
+ return MakeGitError(ecode)
+ }
+
+ return nil
+}
diff --git a/diff_test.go b/diff_test.go
index 464fae6..850ed8e 100644
--- a/diff_test.go
+++ b/diff_test.go
@@ -187,3 +187,50 @@ func createTestTrees(t *testing.T, repo *Repository) (originalTree *Tree, newTre
return originalTree, newTree
}
+
+func TestDiffBlobs(t *testing.T) {
+ repo := createTestRepo(t)
+ defer cleanupTestRepo(t, repo)
+
+ odb, err := repo.Odb()
+ checkFatal(t, err)
+
+ id1, err := odb.Write([]byte("hello\nhello\n"), ObjectBlob)
+ checkFatal(t, err)
+
+ id2, err := odb.Write([]byte("hallo\nhallo\n"), ObjectBlob)
+ checkFatal(t, err)
+
+ blob1, err := repo.LookupBlob(id1)
+ checkFatal(t, err)
+
+ blob2, err := repo.LookupBlob(id2)
+ checkFatal(t, err)
+
+ var files, hunks, lines int
+ err = DiffBlobs(blob1, "hi", blob2, "hi", nil,
+ func(delta DiffDelta, progress float64) (DiffForEachHunkCallback, error) {
+ files++
+ return func(hunk DiffHunk) (DiffForEachLineCallback, error) {
+ hunks++
+ return func(line DiffLine) error {
+ lines++
+ return nil
+ }, nil
+ }, nil
+ },
+ DiffDetailLines)
+
+ if files != 1 {
+ t.Fatal("Bad number of files iterated")
+ }
+
+ if hunks != 1 {
+ t.Fatal("Bad number of hunks iterated")
+ }
+
+ // two removals, two additions
+ if lines != 4 {
+ t.Fatalf("Bad number of lines iterated")
+ }
+}
diff --git a/remote.go b/remote.go
index c221713..6f3c9ea 100644
--- a/remote.go
+++ b/remote.go
@@ -596,7 +596,6 @@ func populateFetchOptions(options *C.git_fetch_options, opts *FetchOptions) {
// the configuration; msg specifies what to use for the reflog
// entries. Leave "" to use defaults.
func (o *Remote) Fetch(refspecs []string, opts *FetchOptions, msg string) error {
-
var cmsg *C.char = nil
if msg != "" {
cmsg = C.CString(msg)
diff --git a/repository.go b/repository.go
index 2e2e897..44509af 100644
--- a/repository.go
+++ b/repository.go
@@ -234,6 +234,18 @@ func (v *Repository) SetHeadDetached(id *Oid) error {
return nil
}
+func (v *Repository) IsHeadDetached() (bool, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_repository_head_detached(v.ptr)
+ if ret < 0 {
+ return false, MakeGitError(ret)
+ }
+
+ return ret != 0, nil
+}
+
func (v *Repository) Walk() (*RevWalk, error) {
var walkPtr *C.git_revwalk
diff --git a/wrapper.c b/wrapper.c
index 4f2de60..75cc03c 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -62,6 +62,27 @@ int _go_git_diff_foreach(git_diff *diff, int eachFile, int eachHunk, int eachLin
return git_diff_foreach(diff, fcb, NULL, hcb, lcb, payload);
}
+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)
+{
+ git_diff_file_cb fcb = NULL;
+ git_diff_hunk_cb hcb = NULL;
+ git_diff_line_cb lcb = NULL;
+
+ if (eachFile) {
+ fcb = (git_diff_file_cb)&diffForEachFileCb;
+ }
+
+ if (eachHunk) {
+ hcb = (git_diff_hunk_cb)&diffForEachHunkCb;
+ }
+
+ if (eachLine) {
+ lcb = (git_diff_line_cb)&diffForEachLineCb;
+ }
+
+ return git_diff_blobs(old, old_path, new, new_path, opts, fcb, NULL, hcb, lcb, payload);
+}
+
void _go_git_setup_diff_notify_callbacks(git_diff_options *opts) {
opts->notify_cb = (git_diff_notify_cb)diffNotifyCb;
}