summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md7
-rw-r--r--diff.go87
-rw-r--r--diff_test.go73
-rw-r--r--git.go9
-rw-r--r--merge.go56
-rw-r--r--merge_test.go8
-rw-r--r--remote.go18
m---------vendor/libgit20
8 files changed, 209 insertions, 49 deletions
diff --git a/README.md b/README.md
index d10c46e..9995707 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
git2go
======
-[![GoDoc](https://godoc.org/github.com/libgit2/git2go?status.svg)](http://godoc.org/github.com/libgit2/git2go)
+[![GoDoc](https://godoc.org/github.com/libgit2/git2go?status.svg)](http://godoc.org/github.com/libgit2/git2go) [![Build Status](https://travis-ci.org/libgit2/git2go.svg?branch=master)](https://travis-ci.org/libgit2/git2go)
Go bindings for [libgit2](http://libgit2.github.com/). The master branch follows the latest libgit2 release.
@@ -17,6 +17,11 @@ Run `go get -d github.com/libgit2/git2go` to download the code and go to your `$
will compile libgit2 and run `go install` such that it's statically linked to the git2go package.
+Paralellism and network operations
+----------------------------------
+
+libgit2 uses OpenSSL and LibSSH2 for performing encrypted network connections. For now, git2go asks libgit2 to set locking for OpenSSL. This makes HTTPS connections thread-safe, but it is fragile and will likely stop doing it soon. This may also make SSH connections thread-safe if your copy of libssh2 is linked against OpenSSL. Check libgit2's `THREADSAFE.md` for more information.
+
Running the tests
-----------------
diff --git a/diff.go b/diff.go
index f762a56..9ce275c 100644
--- a/diff.go
+++ b/diff.go
@@ -164,6 +164,29 @@ func (diff *Diff) Free() error {
return nil
}
+func (diff *Diff) FindSimilar(opts *DiffFindOptions) error {
+
+ var copts *C.git_diff_find_options
+ if opts != nil {
+ copts = &C.git_diff_find_options{
+ version: C.GIT_DIFF_FIND_OPTIONS_VERSION,
+ flags: C.uint32_t(opts.Flags),
+ rename_threshold: C.uint16_t(opts.RenameThreshold),
+ copy_threshold: C.uint16_t(opts.CopyThreshold),
+ rename_from_rewrite_threshold: C.uint16_t(opts.RenameFromRewriteThreshold),
+ break_rewrite_threshold: C.uint16_t(opts.BreakRewriteThreshold),
+ rename_limit: C.size_t(opts.RenameLimit),
+ }
+ }
+
+ ecode := C.git_diff_find_similar(diff.ptr, copts)
+ if ecode < 0 {
+ return MakeGitError(ecode)
+ }
+
+ return nil
+}
+
type diffForEachData struct {
FileCallback DiffForEachFileCallback
HunkCallback DiffForEachHunkCallback
@@ -313,8 +336,8 @@ type DiffOptions struct {
Pathspec []string
NotifyCallback DiffNotifyCallback
- ContextLines uint16
- InterhunkLines uint16
+ ContextLines uint32
+ InterhunkLines uint32
IdAbbrev uint16
MaxSize int
@@ -334,13 +357,61 @@ func DefaultDiffOptions() (DiffOptions, error) {
Flags: DiffOptionsFlag(opts.flags),
IgnoreSubmodules: SubmoduleIgnore(opts.ignore_submodules),
Pathspec: makeStringsFromCStrings(opts.pathspec.strings, int(opts.pathspec.count)),
- ContextLines: uint16(opts.context_lines),
- InterhunkLines: uint16(opts.interhunk_lines),
+ ContextLines: uint32(opts.context_lines),
+ InterhunkLines: uint32(opts.interhunk_lines),
IdAbbrev: uint16(opts.id_abbrev),
MaxSize: int(opts.max_size),
}, nil
}
+type DiffFindOptionsFlag int
+
+const (
+ DiffFindByConfig DiffFindOptionsFlag = C.GIT_DIFF_FIND_BY_CONFIG
+ DiffFindRenames DiffFindOptionsFlag = C.GIT_DIFF_FIND_RENAMES
+ DiffFindRenamesFromRewrites DiffFindOptionsFlag = C.GIT_DIFF_FIND_RENAMES_FROM_REWRITES
+ DiffFindCopies DiffFindOptionsFlag = C.GIT_DIFF_FIND_COPIES
+ DiffFindCopiesFromUnmodified DiffFindOptionsFlag = C.GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED
+ DiffFindRewrites DiffFindOptionsFlag = C.GIT_DIFF_FIND_REWRITES
+ DiffFindBreakRewrites DiffFindOptionsFlag = C.GIT_DIFF_BREAK_REWRITES
+ DiffFindAndBreakRewrites DiffFindOptionsFlag = C.GIT_DIFF_FIND_AND_BREAK_REWRITES
+ DiffFindForUntracked DiffFindOptionsFlag = C.GIT_DIFF_FIND_FOR_UNTRACKED
+ DiffFindAll DiffFindOptionsFlag = C.GIT_DIFF_FIND_ALL
+ DiffFindIgnoreLeadingWhitespace DiffFindOptionsFlag = C.GIT_DIFF_FIND_IGNORE_LEADING_WHITESPACE
+ DiffFindIgnoreWhitespace DiffFindOptionsFlag = C.GIT_DIFF_FIND_IGNORE_WHITESPACE
+ DiffFindDontIgnoreWhitespace DiffFindOptionsFlag = C.GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE
+ DiffFindExactMatchOnly DiffFindOptionsFlag = C.GIT_DIFF_FIND_EXACT_MATCH_ONLY
+ DiffFindBreakRewritesForRenamesOnly DiffFindOptionsFlag = C.GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY
+ DiffFindRemoveUnmodified DiffFindOptionsFlag = C.GIT_DIFF_FIND_REMOVE_UNMODIFIED
+)
+
+//TODO implement git_diff_similarity_metric
+type DiffFindOptions struct {
+ Flags DiffFindOptionsFlag
+ RenameThreshold uint16
+ CopyThreshold uint16
+ RenameFromRewriteThreshold uint16
+ BreakRewriteThreshold uint16
+ RenameLimit uint
+}
+
+func DefaultDiffFindOptions() (DiffFindOptions, error) {
+ opts := C.git_diff_find_options{}
+ ecode := C.git_diff_find_init_options(&opts, C.GIT_DIFF_FIND_OPTIONS_VERSION)
+ if ecode < 0 {
+ return DiffFindOptions{}, MakeGitError(ecode)
+ }
+
+ return DiffFindOptions{
+ Flags: DiffFindOptionsFlag(opts.flags),
+ RenameThreshold: uint16(opts.rename_threshold),
+ CopyThreshold: uint16(opts.copy_threshold),
+ RenameFromRewriteThreshold: uint16(opts.rename_from_rewrite_threshold),
+ BreakRewriteThreshold: uint16(opts.break_rewrite_threshold),
+ RenameLimit: uint(opts.rename_limit),
+ }, nil
+}
+
var (
ErrDeltaSkip = errors.New("Skip delta")
)
@@ -404,8 +475,8 @@ func (v *Repository) DiffTreeToTree(oldTree, newTree *Tree, opts *DiffOptions) (
flags: C.uint32_t(opts.Flags),
ignore_submodules: C.git_submodule_ignore_t(opts.IgnoreSubmodules),
pathspec: cpathspec,
- context_lines: C.uint16_t(opts.ContextLines),
- interhunk_lines: C.uint16_t(opts.InterhunkLines),
+ context_lines: C.uint32_t(opts.ContextLines),
+ interhunk_lines: C.uint32_t(opts.InterhunkLines),
id_abbrev: C.uint16_t(opts.IdAbbrev),
max_size: C.git_off_t(opts.MaxSize),
}
@@ -453,8 +524,8 @@ func (v *Repository) DiffTreeToWorkdir(oldTree *Tree, opts *DiffOptions) (*Diff,
flags: C.uint32_t(opts.Flags),
ignore_submodules: C.git_submodule_ignore_t(opts.IgnoreSubmodules),
pathspec: cpathspec,
- context_lines: C.uint16_t(opts.ContextLines),
- interhunk_lines: C.uint16_t(opts.InterhunkLines),
+ context_lines: C.uint32_t(opts.ContextLines),
+ interhunk_lines: C.uint32_t(opts.InterhunkLines),
id_abbrev: C.uint16_t(opts.IdAbbrev),
max_size: C.git_off_t(opts.MaxSize),
}
diff --git a/diff_test.go b/diff_test.go
index b688294..84d72db 100644
--- a/diff_test.go
+++ b/diff_test.go
@@ -6,21 +6,69 @@ import (
"testing"
)
-func TestDiffTreeToTree(t *testing.T) {
+func TestFindSimilar(t *testing.T) {
repo := createTestRepo(t)
defer repo.Free()
defer os.RemoveAll(repo.Workdir())
- _, originalTreeId := seedTestRepo(t, repo)
- originalTree, err := repo.LookupTree(originalTreeId)
+ originalTree, newTree := createTestTrees(t, repo)
+
+ diffOpt, _ := DefaultDiffOptions()
+ diff, err := repo.DiffTreeToTree(originalTree, newTree, &diffOpt)
checkFatal(t, err)
+ if diff == nil {
+ t.Fatal("no diff returned")
+ }
- _, newTreeId := updateReadme(t, repo, "file changed\n")
+ findOpts, err := DefaultDiffFindOptions()
+ checkFatal(t, err)
+ findOpts.Flags = DiffFindBreakRewrites
- newTree, err := repo.LookupTree(newTreeId)
+ err = diff.FindSimilar(&findOpts)
checkFatal(t, err)
+ numDiffs := 0
+ numAdded := 0
+ numDeleted := 0
+
+ err = diff.ForEach(func(file DiffDelta, progress float64) (DiffForEachHunkCallback, error) {
+ numDiffs++
+
+ switch file.Status {
+ case DeltaAdded:
+ numAdded++
+ case DeltaDeleted:
+ numDeleted++
+ }
+
+ return func(hunk DiffHunk) (DiffForEachLineCallback, error) {
+ return func(line DiffLine) error {
+ return nil
+ }, nil
+ }, nil
+ }, DiffDetailLines)
+
+ if numDiffs != 2 {
+ t.Fatal("Incorrect number of files in diff")
+ }
+ if numAdded != 1 {
+ t.Fatal("Incorrect number of new files in diff")
+ }
+ if numDeleted != 1 {
+ t.Fatal("Incorrect number of deleted files in diff")
+ }
+
+}
+
+func TestDiffTreeToTree(t *testing.T) {
+
+ repo := createTestRepo(t)
+ defer repo.Free()
+ defer os.RemoveAll(repo.Workdir())
+
+ originalTree, newTree := createTestTrees(t, repo)
+
callbackInvoked := false
opts := DiffOptions{
NotifyCallback: func(diffSoFar *Diff, delta DiffDelta, matchedPathSpec string) error {
@@ -94,3 +142,18 @@ func TestDiffTreeToTree(t *testing.T) {
}
}
+
+func createTestTrees(t *testing.T, repo *Repository) (originalTree *Tree, newTree *Tree) {
+ var err error
+ _, originalTreeId := seedTestRepo(t, repo)
+ originalTree, err = repo.LookupTree(originalTreeId)
+
+ checkFatal(t, err)
+
+ _, newTreeId := updateReadme(t, repo, "file changed\n")
+
+ newTree, err = repo.LookupTree(newTreeId)
+ checkFatal(t, err)
+
+ return originalTree, newTree
+}
diff --git a/git.go b/git.go
index adfa3b0..72d8d03 100644
--- a/git.go
+++ b/git.go
@@ -93,7 +93,14 @@ var (
)
func init() {
- C.git_threads_init()
+ C.git_libgit2_init()
+
+ // This is not something we should be doing, as we may be
+ // stomping all over someone else's setup. The user should do
+ // this themselves or use some binding/wrapper which does it
+ // in such a way that they can be sure they're the only ones
+ // setting it up.
+ C.git_openssl_set_locking()
}
// Oid represents the id for a Git object.
diff --git a/merge.go b/merge.go
index 93ac71b..83a682c 100644
--- a/merge.go
+++ b/merge.go
@@ -4,9 +4,9 @@ package git
#include <git2.h>
#include <git2/errors.h>
-extern git_merge_head** _go_git_make_merge_head_array(size_t len);
-extern void _go_git_merge_head_array_set(git_merge_head** array, git_merge_head* ptr, size_t n);
-extern git_merge_head* _go_git_merge_head_array_get(git_merge_head** array, size_t n);
+extern git_annotated_commit** _go_git_make_merge_head_array(size_t len);
+extern void _go_git_annotated_commit_array_set(git_annotated_commit** array, git_annotated_commit* ptr, size_t n);
+extern git_annotated_commit* _go_git_annotated_commit_array_get(git_annotated_commit** array, size_t n);
*/
import "C"
@@ -15,23 +15,23 @@ import (
"unsafe"
)
-type MergeHead struct {
- ptr *C.git_merge_head
+type AnnotatedCommit struct {
+ ptr *C.git_annotated_commit
}
-func newMergeHeadFromC(c *C.git_merge_head) *MergeHead {
- mh := &MergeHead{ptr: c}
- runtime.SetFinalizer(mh, (*MergeHead).Free)
+func newAnnotatedCommitFromC(c *C.git_annotated_commit) *AnnotatedCommit {
+ mh := &AnnotatedCommit{ptr: c}
+ runtime.SetFinalizer(mh, (*AnnotatedCommit).Free)
return mh
}
-func (mh *MergeHead) Free() {
+func (mh *AnnotatedCommit) Free() {
runtime.SetFinalizer(mh, nil)
- C.git_merge_head_free(mh.ptr)
+ C.git_annotated_commit_free(mh.ptr)
}
-func (r *Repository) MergeHeadFromFetchHead(branchName string, remoteURL string, oid *Oid) (*MergeHead, error) {
- mh := &MergeHead{}
+func (r *Repository) AnnotatedCommitFromFetchHead(branchName string, remoteURL string, oid *Oid) (*AnnotatedCommit, error) {
+ mh := &AnnotatedCommit{}
cbranchName := C.CString(branchName)
defer C.free(unsafe.Pointer(cbranchName))
@@ -39,33 +39,33 @@ func (r *Repository) MergeHeadFromFetchHead(branchName string, remoteURL string,
cremoteURL := C.CString(remoteURL)
defer C.free(unsafe.Pointer(cremoteURL))
- ret := C.git_merge_head_from_fetchhead(&mh.ptr, r.ptr, cbranchName, cremoteURL, oid.toC())
+ ret := C.git_annotated_commit_from_fetchhead(&mh.ptr, r.ptr, cbranchName, cremoteURL, oid.toC())
if ret < 0 {
return nil, MakeGitError(ret)
}
- runtime.SetFinalizer(mh, (*MergeHead).Free)
+ runtime.SetFinalizer(mh, (*AnnotatedCommit).Free)
return mh, nil
}
-func (r *Repository) MergeHeadFromId(oid *Oid) (*MergeHead, error) {
- mh := &MergeHead{}
+func (r *Repository) LookupAnnotatedCommit(oid *Oid) (*AnnotatedCommit, error) {
+ mh := &AnnotatedCommit{}
- ret := C.git_merge_head_from_id(&mh.ptr, r.ptr, oid.toC())
+ ret := C.git_annotated_commit_lookup(&mh.ptr, r.ptr, oid.toC())
if ret < 0 {
return nil, MakeGitError(ret)
}
- runtime.SetFinalizer(mh, (*MergeHead).Free)
+ runtime.SetFinalizer(mh, (*AnnotatedCommit).Free)
return mh, nil
}
-func (r *Repository) MergeHeadFromRef(ref *Reference) (*MergeHead, error) {
- mh := &MergeHead{}
+func (r *Repository) AnnotatedCommitFromRef(ref *Reference) (*AnnotatedCommit, error) {
+ mh := &AnnotatedCommit{}
- ret := C.git_merge_head_from_ref(&mh.ptr, r.ptr, ref.ptr)
+ ret := C.git_annotated_commit_from_ref(&mh.ptr, r.ptr, ref.ptr)
if ret < 0 {
return nil, MakeGitError(ret)
}
- runtime.SetFinalizer(mh, (*MergeHead).Free)
+ runtime.SetFinalizer(mh, (*AnnotatedCommit).Free)
return mh, nil
}
@@ -127,19 +127,19 @@ const (
MergeFileFavorUnion MergeFileFavor = C.GIT_MERGE_FILE_FAVOR_UNION
)
-func (r *Repository) Merge(theirHeads []*MergeHead, mergeOptions *MergeOptions, checkoutOptions *CheckoutOpts) error {
+func (r *Repository) Merge(theirHeads []*AnnotatedCommit, mergeOptions *MergeOptions, checkoutOptions *CheckoutOpts) error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
cMergeOpts := mergeOptions.toC()
cCheckoutOpts := checkoutOptions.toC()
- gmerge_head_array := make([]*C.git_merge_head, len(theirHeads))
+ gmerge_head_array := make([]*C.git_annotated_commit, len(theirHeads))
for i := 0; i < len(theirHeads); i++ {
gmerge_head_array[i] = theirHeads[i].ptr
}
ptr := unsafe.Pointer(&gmerge_head_array[0])
- err := C.git_merge(r.ptr, (**C.git_merge_head)(ptr), C.size_t(len(theirHeads)), cMergeOpts, cCheckoutOpts)
+ err := C.git_merge(r.ptr, (**C.git_annotated_commit)(ptr), C.size_t(len(theirHeads)), cMergeOpts, cCheckoutOpts)
if err < 0 {
return MakeGitError(err)
}
@@ -164,18 +164,18 @@ const (
MergePreferenceFastForwardOnly MergePreference = C.GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY
)
-func (r *Repository) MergeAnalysis(theirHeads []*MergeHead) (MergeAnalysis, MergePreference, error) {
+func (r *Repository) MergeAnalysis(theirHeads []*AnnotatedCommit) (MergeAnalysis, MergePreference, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
- gmerge_head_array := make([]*C.git_merge_head, len(theirHeads))
+ gmerge_head_array := make([]*C.git_annotated_commit, len(theirHeads))
for i := 0; i < len(theirHeads); i++ {
gmerge_head_array[i] = theirHeads[i].ptr
}
ptr := unsafe.Pointer(&gmerge_head_array[0])
var analysis C.git_merge_analysis_t
var preference C.git_merge_preference_t
- err := C.git_merge_analysis(&analysis, &preference, r.ptr, (**C.git_merge_head)(ptr), C.size_t(len(theirHeads)))
+ err := C.git_merge_analysis(&analysis, &preference, r.ptr, (**C.git_annotated_commit)(ptr), C.size_t(len(theirHeads)))
if err < 0 {
return MergeAnalysisNone, MergePreferenceNone, MakeGitError(err)
}
diff --git a/merge_test.go b/merge_test.go
index 7e884c0..1eba806 100644
--- a/merge_test.go
+++ b/merge_test.go
@@ -13,10 +13,10 @@ func TestMergeWithSelf(t *testing.T) {
master, err := repo.LookupReference("refs/heads/master")
checkFatal(t, err)
- mergeHead, err := repo.MergeHeadFromRef(master)
+ mergeHead, err := repo.AnnotatedCommitFromRef(master)
checkFatal(t, err)
- mergeHeads := make([]*MergeHead, 1)
+ mergeHeads := make([]*AnnotatedCommit, 1)
mergeHeads[0] = mergeHead
err = repo.Merge(mergeHeads, nil, nil)
checkFatal(t, err)
@@ -30,10 +30,10 @@ func TestMergeAnalysisWithSelf(t *testing.T) {
master, err := repo.LookupReference("refs/heads/master")
checkFatal(t, err)
- mergeHead, err := repo.MergeHeadFromRef(master)
+ mergeHead, err := repo.AnnotatedCommitFromRef(master)
checkFatal(t, err)
- mergeHeads := make([]*MergeHead, 1)
+ mergeHeads := make([]*AnnotatedCommit, 1)
mergeHeads[0] = mergeHead
a, _, err := repo.MergeAnalysis(mergeHeads)
checkFatal(t, err)
diff --git a/remote.go b/remote.go
index a2288fa..96cc4c1 100644
--- a/remote.go
+++ b/remote.go
@@ -278,6 +278,20 @@ func (repo *Repository) CreateRemote(name string, url string) (*Remote, error) {
return remote, nil
}
+func (repo *Repository) DeleteRemote(name string) error {
+ cname := C.CString(name)
+ defer C.free(unsafe.Pointer(cname))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_remote_delete(repo.ptr, cname)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
func (repo *Repository) CreateRemoteWithFetchspec(name string, url string, fetch string) (*Remote, error) {
remote := &Remote{}
@@ -318,7 +332,7 @@ func (repo *Repository) CreateAnonymousRemote(url, fetch string) (*Remote, error
return remote, nil
}
-func (repo *Repository) LoadRemote(name string) (*Remote, error) {
+func (repo *Repository) LookupRemote(name string) (*Remote, error) {
remote := &Remote{}
cname := C.CString(name)
@@ -327,7 +341,7 @@ func (repo *Repository) LoadRemote(name string) (*Remote, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
- ret := C.git_remote_load(&remote.ptr, repo.ptr, cname)
+ ret := C.git_remote_lookup(&remote.ptr, repo.ptr, cname)
if ret < 0 {
return nil, MakeGitError(ret)
}
diff --git a/vendor/libgit2 b/vendor/libgit2
-Subproject d09458f3e9f24afa0689ce90b7d419187237263
+Subproject 169497d1e7c238d2925577d1af3dc03e9a507cd