summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlhchavez <[email protected]>2020-02-23 15:08:45 +0000
committerlhchavez <[email protected]>2020-02-23 15:08:45 +0000
commit3c88bd9f1aebc53ea9d77937829f8c155aa834c3 (patch)
tree8556d00fb42f2fcab5ba748e49e21e1141b9d604
parentc75e0221d70bc471917aa3de34ca1ead1a747987 (diff)
parent21d618136f415486d95965e75af80c0e6688a0d5 (diff)
Merge remote-tracking branch 'upstream/master' into cherrypick-commit
-rw-r--r--.github/workflows/ci.yml89
-rw-r--r--.gitignore2
-rw-r--r--.travis.yml22
-rw-r--r--Makefile51
-rw-r--r--branch.go4
-rw-r--r--checkout.go2
-rw-r--r--commit.go10
-rw-r--r--config.go12
-rw-r--r--config_test.go2
-rw-r--r--credentials.go5
-rw-r--r--delta_string.go33
-rw-r--r--describe.go2
-rw-r--r--diff.go38
-rw-r--r--difflinetype_string.go56
-rw-r--r--git.go16
-rw-r--r--git_dynamic.go4
-rw-r--r--git_static.go11
-rw-r--r--go.mod3
-rw-r--r--index.go40
-rw-r--r--index_test.go50
-rw-r--r--mempack.go91
-rw-r--r--mempack_test.go60
-rw-r--r--merge.go73
-rw-r--r--merge_test.go21
-rw-r--r--note.go2
-rw-r--r--object.go20
-rw-r--r--odb.go46
-rw-r--r--odb_test.go49
-rw-r--r--packbuilder.go13
-rw-r--r--patch.go2
-rw-r--r--rebase.go21
-rw-r--r--reference.go11
-rw-r--r--remote.go4
-rw-r--r--repository.go76
-rw-r--r--repository_test.go42
-rw-r--r--reset_test.go2
-rw-r--r--revert.go101
-rw-r--r--revert_test.go76
-rwxr-xr-xscript/build-libgit2-dynamic.sh5
-rwxr-xr-xscript/build-libgit2-static.sh18
-rwxr-xr-xscript/build-libgit2.sh46
-rw-r--r--settings.go2
-rw-r--r--signature.go2
-rw-r--r--stash.go2
-rw-r--r--tag.go12
-rw-r--r--tree.go30
m---------vendor/libgit20
-rw-r--r--wrapper.c5
48 files changed, 1137 insertions, 147 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..931cc09
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,89 @@
+name: git2go CI
+on:
+ pull_request:
+ push:
+ branches:
+ - master
+ - release-*
+ - v*
+
+jobs:
+
+ build-legacy:
+ strategy:
+ fail-fast: false
+ matrix:
+ go: [ '1.9', '1.10' ]
+ name: Go ${{ matrix.go }}
+
+ runs-on: ubuntu-18.04
+
+ steps:
+ - name: Set up Go
+ uses: actions/setup-go@v1
+ with:
+ go-version: ${{ matrix.go }}
+ id: go
+ - name: Check out code into the GOPATH
+ uses: actions/checkout@v1
+ with:
+ fetch-depth: 1
+ path: src/github.com/${{ github.repository }}
+ - name: Build
+ env:
+ GOPATH: /home/runner/work/git2go
+ run: |
+ git submodule update --init
+ make build-libgit2-static
+ go get --tags "static" github.com/${{ github.repository }}/...
+ go build --tags "static" github.com/${{ github.repository }}/...
+ - name: Test
+ env:
+ GOPATH: /home/runner/work/git2go
+ run: make test-static
+
+ build-static:
+ strategy:
+ fail-fast: false
+ matrix:
+ go: [ '1.11', '1.12', '1.13' ]
+ name: Go ${{ matrix.go }}
+
+ runs-on: ubuntu-18.04
+
+ steps:
+ - name: Set up Go
+ uses: actions/setup-go@v1
+ with:
+ go-version: ${{ matrix.go }}
+ id: go
+ - name: Check out code into the Go module directory
+ uses: actions/checkout@v1
+ - name: Build
+ run: |
+ git submodule update --init
+ make build-libgit2-static
+ - name: Test
+ run: make test-static
+
+ build-dynamic:
+ strategy:
+ fail-fast: false
+ name: Go (dynamic)
+
+ runs-on: ubuntu-18.04
+
+ steps:
+ - name: Set up Go
+ uses: actions/setup-go@v1
+ with:
+ go-version: '1.13'
+ id: go
+ - name: Check out code into the Go module directory
+ uses: actions/checkout@v1
+ - name: Build
+ run: |
+ git submodule update --init
+ make build-libgit2-dynamic
+ - name: Test
+ run: make test-dynamic
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..713781b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/static-build/
+/dynamic-build/
diff --git a/.travis.yml b/.travis.yml
index dd9f97a..b25a052 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,25 +1,29 @@
language: go
go:
- - 1.7
- - 1.8
- - 1.9
+ - "1.9"
+ - "1.10"
+ - "1.11"
+ - "1.12"
+ - "1.13"
- tip
-script: make test-static
+install:
+ - make build-libgit2-static
+ - go get --tags "static" ./...
+
+script:
+ - make test-static
matrix:
allow_failures:
- go: tip
git:
- submodules: false
-
-before_install:
- - git submodule update --init
+ submodules: true
branches:
only:
- master
- /v\d+/
- - next
+ - /release-.*/
diff --git a/Makefile b/Makefile
index cf00cef..182c53e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,18 +1,53 @@
default: test
-test: build-libgit2
+# System library
+# ==============
+# This uses whatever version of libgit2 can be found in the system.
+test:
go run script/check-MakeGitError-thread-lock.go
- go test ./...
+ go test --count=1 ./...
-install: build-libgit2
+install:
go install ./...
-build-libgit2:
+# Bundled dynamic library
+# =======================
+# In order to avoid having to manipulate `git_dynamic.go`, which would prevent
+# the system-wide libgit2.so from being used in a sort of ergonomic way, this
+# instead moves the complexity of overriding the paths so that the built
+# libraries can be found by the build and tests.
+.PHONY: build-libgit2-dynamic
+build-libgit2-dynamic:
+ ./script/build-libgit2-dynamic.sh
+
+dynamic-build/install/lib/libgit2.so:
+ ./script/build-libgit2-dynamic.sh
+
+test-dynamic: dynamic-build/install/lib/libgit2.so
+ PKG_CONFIG_PATH=dynamic-build/install/lib/pkgconfig \
+ go run script/check-MakeGitError-thread-lock.go
+ PKG_CONFIG_PATH=dynamic-build/install/lib/pkgconfig \
+ LD_LIBRARY_PATH=dynamic-build/install/lib \
+ go test --count=1 ./...
+
+install-dynamic: dynamic-build/install/lib/libgit2.so
+ PKG_CONFIG_PATH=dynamic-build/install/lib/pkgconfig \
+ go install ./...
+
+# Bundled static library
+# ======================
+# This is mostly used in tests, but can also be used to provide a
+# statically-linked library with the bundled version of libgit2.
+.PHONY: build-libgit2-static
+build-libgit2-static:
./script/build-libgit2-static.sh
-install-static: build-libgit2
- go install --tags "static" ./...
+static-build/install/lib/libgit2.a:
+ ./script/build-libgit2-static.sh
-test-static: build-libgit2
+test-static: static-build/install/lib/libgit2.a
go run script/check-MakeGitError-thread-lock.go
- go test --tags "static" ./...
+ go test --count=1 --tags "static" ./...
+
+install-static: static-build/install/lib/libgit2.a
+ go install --tags "static" ./...
diff --git a/branch.go b/branch.go
index d6e7a53..6f79825 100644
--- a/branch.go
+++ b/branch.go
@@ -208,7 +208,7 @@ func (repo *Repository) RemoteName(canonicalBranchName string) (string, error) {
if ret < 0 {
return "", MakeGitError(ret)
}
- defer C.git_buf_free(&nameBuf)
+ defer C.git_buf_dispose(&nameBuf)
return C.GoString(nameBuf.ptr), nil
}
@@ -256,7 +256,7 @@ func (repo *Repository) UpstreamName(canonicalBranchName string) (string, error)
if ret < 0 {
return "", MakeGitError(ret)
}
- defer C.git_buf_free(&nameBuf)
+ defer C.git_buf_dispose(&nameBuf)
return C.GoString(nameBuf.ptr), nil
}
diff --git a/checkout.go b/checkout.go
index db3118f..2b12058 100644
--- a/checkout.go
+++ b/checkout.go
@@ -35,7 +35,7 @@ const (
CheckoutDontUpdateIndex CheckoutStrategy = C.GIT_CHECKOUT_DONT_UPDATE_INDEX // Normally checkout updates index entries as it goes; this stops that
CheckoutNoRefresh CheckoutStrategy = C.GIT_CHECKOUT_NO_REFRESH // Don't refresh index/config/etc before doing checkout
CheckoutSkipUnmerged CheckoutStrategy = C.GIT_CHECKOUT_SKIP_UNMERGED // Allow checkout to skip unmerged files
- CheckoutUserOurs CheckoutStrategy = C.GIT_CHECKOUT_USE_OURS // For unmerged files, checkout stage 2 from index
+ CheckoutUseOurs CheckoutStrategy = C.GIT_CHECKOUT_USE_OURS // For unmerged files, checkout stage 2 from index
CheckoutUseTheirs CheckoutStrategy = C.GIT_CHECKOUT_USE_THEIRS // For unmerged files, checkout stage 3 from index
CheckoutDisablePathspecMatch CheckoutStrategy = C.GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH // Treat pathspec as simple list of exact match file paths
CheckoutSkipLockedDirectories CheckoutStrategy = C.GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES // Ignore directories in use, they will be left empty
diff --git a/commit.go b/commit.go
index 223b093..4262060 100644
--- a/commit.go
+++ b/commit.go
@@ -28,6 +28,12 @@ func (c *Commit) Message() string {
return ret
}
+func (c *Commit) MessageEncoding() string {
+ ret := C.GoString(C.git_commit_message_encoding(c.cast_ptr))
+ runtime.KeepAlive(c)
+ return ret
+}
+
func (c *Commit) RawMessage() string {
ret := C.GoString(C.git_commit_message_raw(c.cast_ptr))
runtime.KeepAlive(c)
@@ -37,10 +43,10 @@ func (c *Commit) RawMessage() string {
func (c *Commit) ExtractSignature() (string, string, error) {
var c_signed C.git_buf
- defer C.git_buf_free(&c_signed)
+ defer C.git_buf_dispose(&c_signed)
var c_signature C.git_buf
- defer C.git_buf_free(&c_signature)
+ defer C.git_buf_dispose(&c_signature)
oid := c.Id()
repo := C.git_commit_owner(c.cast_ptr)
diff --git a/config.go b/config.go
index ab9af38..7260089 100644
--- a/config.go
+++ b/config.go
@@ -134,7 +134,7 @@ func (c *Config) LookupString(name string) (string, error) {
if ret < 0 {
return "", MakeGitError(ret)
}
- defer C.git_buf_free(&valBuf)
+ defer C.git_buf_dispose(&valBuf)
return C.GoString(valBuf.ptr), nil
}
@@ -344,7 +344,7 @@ func (c *Config) OpenLevel(parent *Config, level ConfigLevel) (*Config, error) {
}
// OpenOndisk creates a new config instance containing a single on-disk file
-func OpenOndisk(parent *Config, path string) (*Config, error) {
+func OpenOndisk(path string) (*Config, error) {
cpath := C.CString(path)
defer C.free(unsafe.Pointer(cpath))
@@ -390,7 +390,7 @@ func (iter *ConfigIterator) Free() {
func ConfigFindGlobal() (string, error) {
var buf C.git_buf
- defer C.git_buf_free(&buf)
+ defer C.git_buf_dispose(&buf)
runtime.LockOSThread()
defer runtime.UnlockOSThread()
@@ -405,7 +405,7 @@ func ConfigFindGlobal() (string, error) {
func ConfigFindSystem() (string, error) {
var buf C.git_buf
- defer C.git_buf_free(&buf)
+ defer C.git_buf_dispose(&buf)
runtime.LockOSThread()
defer runtime.UnlockOSThread()
@@ -420,7 +420,7 @@ func ConfigFindSystem() (string, error) {
func ConfigFindXDG() (string, error) {
var buf C.git_buf
- defer C.git_buf_free(&buf)
+ defer C.git_buf_dispose(&buf)
runtime.LockOSThread()
defer runtime.UnlockOSThread()
@@ -438,7 +438,7 @@ func ConfigFindXDG() (string, error) {
// Look for the file in %PROGRAMDATA%\Git\config used by portable git.
func ConfigFindProgramdata() (string, error) {
var buf C.git_buf
- defer C.git_buf_free(&buf)
+ defer C.git_buf_dispose(&buf)
runtime.LockOSThread()
defer runtime.UnlockOSThread()
diff --git a/config_test.go b/config_test.go
index 196d4ad..398236e 100644
--- a/config_test.go
+++ b/config_test.go
@@ -13,7 +13,7 @@ func setupConfig() (*Config, error) {
err error
)
- c, err = OpenOndisk(nil, tempConfig)
+ c, err = OpenOndisk(tempConfig)
if err != nil {
return nil, err
}
diff --git a/credentials.go b/credentials.go
index 4e42b6e..038313b 100644
--- a/credentials.go
+++ b/credentials.go
@@ -2,6 +2,9 @@ package git
/*
#include <git2.h>
+#include <git2/sys/cred.h>
+
+git_credtype_t _go_git_cred_credtype(git_cred *cred);
*/
import "C"
import "unsafe"
@@ -27,7 +30,7 @@ func (o *Cred) HasUsername() bool {
}
func (o *Cred) Type() CredType {
- return (CredType)(o.ptr.credtype)
+ return (CredType)(C._go_git_cred_credtype(o.ptr))
}
func credFromC(ptr *C.git_cred) *Cred {
diff --git a/delta_string.go b/delta_string.go
new file mode 100644
index 0000000..53e02bd
--- /dev/null
+++ b/delta_string.go
@@ -0,0 +1,33 @@
+// Code generated by "stringer -type Delta -trimprefix Delta -tags static"; DO NOT EDIT.
+
+package git
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[DeltaUnmodified-0]
+ _ = x[DeltaAdded-1]
+ _ = x[DeltaDeleted-2]
+ _ = x[DeltaModified-3]
+ _ = x[DeltaRenamed-4]
+ _ = x[DeltaCopied-5]
+ _ = x[DeltaIgnored-6]
+ _ = x[DeltaUntracked-7]
+ _ = x[DeltaTypeChange-8]
+ _ = x[DeltaUnreadable-9]
+ _ = x[DeltaConflicted-10]
+}
+
+const _Delta_name = "UnmodifiedAddedDeletedModifiedRenamedCopiedIgnoredUntrackedTypeChangeUnreadableConflicted"
+
+var _Delta_index = [...]uint8{0, 10, 15, 22, 30, 37, 43, 50, 59, 69, 79, 89}
+
+func (i Delta) String() string {
+ if i < 0 || i >= Delta(len(_Delta_index)-1) {
+ return "Delta(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _Delta_name[_Delta_index[i]:_Delta_index[i+1]]
+}
diff --git a/describe.go b/describe.go
index 0b75076..f7036df 100644
--- a/describe.go
+++ b/describe.go
@@ -212,7 +212,7 @@ func (result *DescribeResult) Format(opts *DescribeFormatOptions) (string, error
if ecode < 0 {
return "", MakeGitError(ecode)
}
- defer C.git_buf_free(&resultBuf)
+ defer C.git_buf_dispose(&resultBuf)
return C.GoString(resultBuf.ptr), nil
}
diff --git a/diff.go b/diff.go
index 3088320..ed2949c 100644
--- a/diff.go
+++ b/diff.go
@@ -39,6 +39,8 @@ const (
DeltaConflicted Delta = C.GIT_DELTA_CONFLICTED
)
+//go:generate stringer -type Delta -trimprefix Delta -tags static
+
type DiffLineType int
const (
@@ -54,6 +56,8 @@ const (
DiffLineBinary DiffLineType = C.GIT_DIFF_LINE_BINARY
)
+//go:generate stringer -type DiffLineType -trimprefix DiffLine -tags static
+
type DiffFile struct {
Path string
Oid *Oid
@@ -246,7 +250,7 @@ const (
func (stats *DiffStats) String(format DiffStatsFormat,
width uint) (string, error) {
buf := C.git_buf{}
- defer C.git_buf_free(&buf)
+ defer C.git_buf_dispose(&buf)
runtime.LockOSThread()
defer runtime.UnlockOSThread()
@@ -284,7 +288,7 @@ type diffForEachData struct {
Error error
}
-type DiffForEachFileCallback func(DiffDelta, float64) (DiffForEachHunkCallback, error)
+type DiffForEachFileCallback func(delta DiffDelta, progress float64) (DiffForEachHunkCallback, error)
type DiffDetail int
@@ -405,6 +409,36 @@ func (diff *Diff) Patch(deltaIndex int) (*Patch, error) {
return newPatchFromC(patchPtr), nil
}
+type DiffFormat int
+
+const (
+ DiffFormatPatch DiffFormat = C.GIT_DIFF_FORMAT_PATCH
+ DiffFormatPatchHeader DiffFormat = C.GIT_DIFF_FORMAT_PATCH_HEADER
+ DiffFormatRaw DiffFormat = C.GIT_DIFF_FORMAT_RAW
+ DiffFormatNameOnly DiffFormat = C.GIT_DIFF_FORMAT_NAME_ONLY
+ DiffFormatNameStatus DiffFormat = C.GIT_DIFF_FORMAT_NAME_STATUS
+)
+
+func (diff *Diff) ToBuf(format DiffFormat) ([]byte, error) {
+ if diff.ptr == nil {
+ return nil, ErrInvalid
+ }
+
+ diffBuf := C.git_buf{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_diff_to_buf(&diffBuf, diff.ptr, C.git_diff_format_t(format))
+ runtime.KeepAlive(diff)
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+ defer C.git_buf_free(&diffBuf)
+
+ return C.GoBytes(unsafe.Pointer(diffBuf.ptr), C.int(diffBuf.size)), nil
+}
+
type DiffOptionsFlag int
const (
diff --git a/difflinetype_string.go b/difflinetype_string.go
new file mode 100644
index 0000000..3c1ad58
--- /dev/null
+++ b/difflinetype_string.go
@@ -0,0 +1,56 @@
+// Code generated by "stringer -type DiffLineType -trimprefix DiffLine -tags static"; DO NOT EDIT.
+
+package git
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[DiffLineContext-32]
+ _ = x[DiffLineAddition-43]
+ _ = x[DiffLineDeletion-45]
+ _ = x[DiffLineContextEOFNL-61]
+ _ = x[DiffLineAddEOFNL-62]
+ _ = x[DiffLineDelEOFNL-60]
+ _ = x[DiffLineFileHdr-70]
+ _ = x[DiffLineHunkHdr-72]
+ _ = x[DiffLineBinary-66]
+}
+
+const (
+ _DiffLineType_name_0 = "Context"
+ _DiffLineType_name_1 = "Addition"
+ _DiffLineType_name_2 = "Deletion"
+ _DiffLineType_name_3 = "DelEOFNLContextEOFNLAddEOFNL"
+ _DiffLineType_name_4 = "Binary"
+ _DiffLineType_name_5 = "FileHdr"
+ _DiffLineType_name_6 = "HunkHdr"
+)
+
+var (
+ _DiffLineType_index_3 = [...]uint8{0, 8, 20, 28}
+)
+
+func (i DiffLineType) String() string {
+ switch {
+ case i == 32:
+ return _DiffLineType_name_0
+ case i == 43:
+ return _DiffLineType_name_1
+ case i == 45:
+ return _DiffLineType_name_2
+ case 60 <= i && i <= 62:
+ i -= 60
+ return _DiffLineType_name_3[_DiffLineType_index_3[i]:_DiffLineType_index_3[i+1]]
+ case i == 66:
+ return _DiffLineType_name_4
+ case i == 70:
+ return _DiffLineType_name_5
+ case i == 72:
+ return _DiffLineType_name_6
+ default:
+ return "DiffLineType(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+}
diff --git a/git.go b/git.go
index 0925e45..968d404 100644
--- a/git.go
+++ b/git.go
@@ -189,22 +189,16 @@ func (oid *Oid) Cmp(oid2 *Oid) int {
}
func (oid *Oid) Copy() *Oid {
- ret := new(Oid)
- copy(ret[:], oid[:])
- return ret
+ ret := *oid
+ return &ret
}
func (oid *Oid) Equal(oid2 *Oid) bool {
- return bytes.Equal(oid[:], oid2[:])
+ return *oid == *oid2
}
func (oid *Oid) IsZero() bool {
- for _, a := range oid {
- if a != 0 {
- return false
- }
- }
- return true
+ return *oid == Oid{}
}
func (oid *Oid) NCmp(oid2 *Oid, n uint) int {
@@ -309,7 +303,7 @@ func Discover(start string, across_fs bool, ceiling_dirs []string) (string, erro
defer C.free(unsafe.Pointer(cstart))
var buf C.git_buf
- defer C.git_buf_free(&buf)
+ defer C.git_buf_dispose(&buf)
runtime.LockOSThread()
defer runtime.UnlockOSThread()
diff --git a/git_dynamic.go b/git_dynamic.go
index 00828a5..06deeeb 100644
--- a/git_dynamic.go
+++ b/git_dynamic.go
@@ -6,8 +6,8 @@ package git
#include <git2.h>
#cgo pkg-config: libgit2
-#if LIBGIT2_VER_MAJOR != 0 || LIBGIT2_VER_MINOR != 26
-# error "Invalid libgit2 version; this git2go supports libgit2 v0.26"
+#if LIBGIT2_VER_MAJOR != 0 || LIBGIT2_VER_MINOR != 28
+# error "Invalid libgit2 version; this git2go supports libgit2 v0.28"
#endif
*/
diff --git a/git_static.go b/git_static.go
index b42d49f..d7c2295 100644
--- a/git_static.go
+++ b/git_static.go
@@ -3,14 +3,13 @@
package git
/*
-#cgo CFLAGS: -I${SRCDIR}/vendor/libgit2/include
-#cgo LDFLAGS: -L${SRCDIR}/vendor/libgit2/build/ -lgit2
-#cgo windows LDFLAGS: -lwinhttp
-#cgo !windows pkg-config: --static ${SRCDIR}/vendor/libgit2/build/libgit2.pc
+#cgo windows CFLAGS: -I${SRCDIR}/static-build/install/include/
+#cgo windows LDFLAGS: -L${SRCDIR}/static-build/install/lib/ -lgit2 -lwinhttp
+#cgo !windows pkg-config: --static ${SRCDIR}/static-build/install/lib/pkgconfig/libgit2.pc
#include <git2.h>
-#if LIBGIT2_VER_MAJOR != 0 || LIBGIT2_VER_MINOR != 26
-# error "Invalid libgit2 version; this git2go supports libgit2 v0.26"
+#if LIBGIT2_VER_MAJOR != 0 || LIBGIT2_VER_MINOR != 28
+# error "Invalid libgit2 version; this git2go supports libgit2 v0.28"
#endif
*/
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..7a68658
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module github.com/libgit2/git2go
+
+go 1.13
diff --git a/index.go b/index.go
index 5106516..50538bd 100644
--- a/index.go
+++ b/index.go
@@ -90,7 +90,9 @@ func populateCIndexEntry(source *IndexEntry, dest *C.git_index_entry) {
dest.uid = C.uint32_t(source.Uid)
dest.gid = C.uint32_t(source.Gid)
dest.file_size = C.uint32_t(source.Size)
- dest.id = *source.Id.toC()
+ if source.Id != nil {
+ dest.id = *source.Id.toC()
+ }
dest.path = C.CString(source.Path)
}
@@ -145,6 +147,20 @@ func (v *Index) Path() string {
return ret
}
+// Clear clears the index object in memory; changes must be explicitly
+// written to disk for them to take effect persistently
+func (v *Index) Clear() error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := C.git_index_clear(v.ptr)
+ runtime.KeepAlive(v)
+ if err < 0 {
+ return MakeGitError(err)
+ }
+ return nil
+}
+
// Add adds or replaces the given entry to the index, making a copy of
// the data
func (v *Index) Add(entry *IndexEntry) error {
@@ -181,6 +197,28 @@ func (v *Index) AddByPath(path string) error {
return nil
}
+// AddFromBuffer adds or replaces an index entry from a buffer in memory
+func (v *Index) AddFromBuffer(entry *IndexEntry, buffer []byte) error {
+ var centry C.git_index_entry
+
+ populateCIndexEntry(entry, &centry)
+ defer freeCIndexEntry(&centry)
+
+ var cbuffer unsafe.Pointer
+ if len(buffer) > 0 {
+ cbuffer = unsafe.Pointer(&buffer[0])
+ }
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ if err := C.git_index_add_from_buffer(v.ptr, &centry, cbuffer, C.size_t(len(buffer))); err < 0 {
+ return MakeGitError(err)
+ }
+
+ return nil
+}
+
func (v *Index) AddAll(pathspecs []string, flags IndexAddOpts, callback IndexMatchedPathCallback) error {
cpathspecs := C.git_strarray{}
cpathspecs.count = C.size_t(len(pathspecs))
diff --git a/index_test.go b/index_test.go
index f47dace..5fa3f9f 100644
--- a/index_test.go
+++ b/index_test.go
@@ -3,6 +3,7 @@ package git
import (
"io/ioutil"
"os"
+ "path"
"runtime"
"testing"
)
@@ -59,14 +60,29 @@ func TestIndexWriteTreeTo(t *testing.T) {
repo := createTestRepo(t)
defer cleanupTestRepo(t, repo)
- repo2 := createTestRepo(t)
- defer cleanupTestRepo(t, repo2)
+ idx, err := NewIndex()
+ checkFatal(t, err)
- idx, err := repo.Index()
+ odb, err := repo.Odb()
checkFatal(t, err)
- err = idx.AddByPath("README")
+
+ content, err := ioutil.ReadFile(path.Join(repo.Workdir(), "README"))
checkFatal(t, err)
- treeId, err := idx.WriteTreeTo(repo2)
+
+ id, err := odb.Write(content, ObjectBlob)
+ checkFatal(t, err)
+
+ err = idx.Add(&IndexEntry{
+ Mode: FilemodeBlob,
+ Uid: 0,
+ Gid: 0,
+ Size: uint32(len(content)),
+ Id: id,
+ Path: "README",
+ })
+ checkFatal(t, err)
+
+ treeId, err := idx.WriteTreeTo(repo)
checkFatal(t, err)
if treeId.String() != "b7119b11e8ef7a1a5a34d3ac87f5b075228ac81e" {
@@ -149,6 +165,30 @@ func TestIndexRemoveDirectory(t *testing.T) {
}
}
+func TestIndexAddFromBuffer(t *testing.T) {
+ t.Parallel()
+ repo := createTestRepo(t)
+ defer cleanupTestRepo(t, repo)
+
+ idx, err := repo.Index()
+ checkFatal(t, err)
+
+ entry := IndexEntry{
+ Path: "README",
+ Mode: FilemodeBlob,
+ }
+
+ err = idx.AddFromBuffer(&entry, []byte("foo\n"))
+ checkFatal(t, err)
+
+ treeId, err := idx.WriteTreeTo(repo)
+ checkFatal(t, err)
+
+ if treeId.String() != "b7119b11e8ef7a1a5a34d3ac87f5b075228ac81e" {
+ t.Fatalf("%v", treeId.String())
+ }
+}
+
func TestIndexAddAllNoCallback(t *testing.T) {
t.Parallel()
repo := createTestRepo(t)
diff --git a/mempack.go b/mempack.go
new file mode 100644
index 0000000..bdea224
--- /dev/null
+++ b/mempack.go
@@ -0,0 +1,91 @@
+package git
+
+/*
+#include <git2.h>
+#include <git2/sys/mempack.h>
+
+extern int git_mempack_new(git_odb_backend **out);
+extern int git_mempack_dump(git_buf *pack, git_repository *repo, git_odb_backend *backend);
+extern int git_mempack_reset(git_odb_backend *backend);
+extern void _go_git_odb_backend_free(git_odb_backend *backend);
+*/
+import "C"
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+// Mempack is a custom ODB backend that permits packing object in-memory.
+type Mempack struct {
+ ptr *C.git_odb_backend
+}
+
+// NewMempack creates a new mempack instance and registers it to the ODB.
+func NewMempack(odb *Odb) (mempack *Mempack, err error) {
+ mempack = new(Mempack)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_mempack_new(&mempack.ptr)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ ret = C.git_odb_add_backend(odb.ptr, mempack.ptr, C.int(999))
+ runtime.KeepAlive(odb)
+ if ret < 0 {
+ // Since git_odb_add_alternate() takes ownership of the ODB backend, the
+ // only case in which we free the mempack's memory is if it fails to be
+ // added to the ODB.
+ C._go_git_odb_backend_free(mempack.ptr)
+ return nil, MakeGitError(ret)
+ }
+
+ return mempack, nil
+}
+
+// Dump dumps all the queued in-memory writes to a packfile.
+//
+// It is the caller's responsibility to ensure that the generated packfile is
+// available to the repository (e.g. by writing it to disk, or doing something
+// crazy like distributing it across several copies of the repository over a
+// network).
+//
+// Once the generated packfile is available to the repository, call
+// Mempack.Reset to cleanup the memory store.
+//
+// Calling Mempack.Reset before the packfile has been written to disk will
+// result in an inconsistent repository (the objects in the memory store won't
+// be accessible).
+func (mempack *Mempack) Dump(repository *Repository) ([]byte, error) {
+ buf := C.git_buf{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_mempack_dump(&buf, repository.ptr, mempack.ptr)
+ runtime.KeepAlive(repository)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+ defer C.git_buf_dispose(&buf)
+
+ return C.GoBytes(unsafe.Pointer(buf.ptr), C.int(buf.size)), nil
+}
+
+// Reset resets the memory packer by clearing all the queued objects.
+//
+// This assumes that Mempack.Dump has been called before to store all the
+// queued objects into a single packfile.
+func (mempack *Mempack) Reset() error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_mempack_reset(mempack.ptr)
+ if ret < 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
diff --git a/mempack_test.go b/mempack_test.go
new file mode 100644
index 0000000..3e31dcf
--- /dev/null
+++ b/mempack_test.go
@@ -0,0 +1,60 @@
+package git
+
+import (
+ "bytes"
+ "testing"
+)
+
+func TestMempack(t *testing.T) {
+ t.Parallel()
+
+ odb, err := NewOdb()
+ checkFatal(t, err)
+
+ repo, err := NewRepositoryWrapOdb(odb)
+ checkFatal(t, err)
+
+ mempack, err := NewMempack(odb)
+ checkFatal(t, err)
+
+ id, err := odb.Write([]byte("hello, world!"), ObjectBlob)
+ checkFatal(t, err)
+
+ expectedId, err := NewOid("30f51a3fba5274d53522d0f19748456974647b4f")
+ checkFatal(t, err)
+ if !expectedId.Equal(id) {
+ t.Errorf("mismatched id. expected %v, got %v", expectedId.String(), id.String())
+ }
+
+ // The object should be available from the odb.
+ {
+ obj, err := odb.Read(expectedId)
+ checkFatal(t, err)
+ defer obj.Free()
+ }
+
+ data, err := mempack.Dump(repo)
+ checkFatal(t, err)
+
+ expectedData := []byte{
+ 0x50, 0x41, 0x43, 0x4b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x9d, 0x08, 0x82, 0x3b, 0xd8, 0xa8, 0xea, 0xb5, 0x10, 0xad, 0x6a,
+ 0xc7, 0x5c, 0x82, 0x3c, 0xfd, 0x3e, 0xd3, 0x1e,
+ }
+ if !bytes.Equal(expectedData, data) {
+ t.Errorf("mismatched mempack data. expected %v, got %v", expectedData, data)
+ }
+
+ mempack.Reset()
+
+ // After the reset, the object should now be unavailable.
+ {
+ obj, err := odb.Read(expectedId)
+ if err == nil {
+ t.Errorf("object %s unexpectedly found", obj.Id().String())
+ obj.Free()
+ } else if !IsErrorCode(err, ErrNotFound) {
+ t.Errorf("unexpected error %v", err)
+ }
+ }
+}
diff --git a/merge.go b/merge.go
index bfbf9a3..06e98a0 100644
--- a/merge.go
+++ b/merge.go
@@ -27,6 +27,15 @@ func newAnnotatedCommitFromC(ptr *C.git_annotated_commit, r *Repository) *Annota
return mh
}
+func (mh *AnnotatedCommit) Id() *Oid {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := newOidFromC(C.git_annotated_commit_id(mh.ptr))
+ runtime.KeepAlive(mh)
+ return ret
+}
+
func (mh *AnnotatedCommit) Free() {
runtime.SetFinalizer(mh, nil)
C.git_annotated_commit_free(mh.ptr)
@@ -49,7 +58,9 @@ func (r *Repository) AnnotatedCommitFromFetchHead(branchName string, remoteURL s
return nil, MakeGitError(ret)
}
- return newAnnotatedCommitFromC(ptr, r), nil
+ annotatedCommit := newAnnotatedCommitFromC(ptr, r)
+ runtime.KeepAlive(r)
+ return annotatedCommit, nil
}
func (r *Repository) LookupAnnotatedCommit(oid *Oid) (*AnnotatedCommit, error) {
@@ -62,7 +73,10 @@ func (r *Repository) LookupAnnotatedCommit(oid *Oid) (*AnnotatedCommit, error) {
if ret < 0 {
return nil, MakeGitError(ret)
}
- return newAnnotatedCommitFromC(ptr, r), nil
+
+ annotatedCommit := newAnnotatedCommitFromC(ptr, r)
+ runtime.KeepAlive(r)
+ return annotatedCommit, nil
}
func (r *Repository) AnnotatedCommitFromRef(ref *Reference) (*AnnotatedCommit, error) {
@@ -76,7 +90,29 @@ func (r *Repository) AnnotatedCommitFromRef(ref *Reference) (*AnnotatedCommit, e
if ret < 0 {
return nil, MakeGitError(ret)
}
- return newAnnotatedCommitFromC(ptr, r), nil
+
+ annotatedCommit := newAnnotatedCommitFromC(ptr, r)
+ runtime.KeepAlive(r)
+ return annotatedCommit, nil
+}
+
+func (r *Repository) AnnotatedCommitFromRevspec(spec string) (*AnnotatedCommit, error) {
+ crevspec := C.CString(spec)
+ defer C.free(unsafe.Pointer(crevspec))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var ptr *C.git_annotated_commit
+ ret := C.git_annotated_commit_from_revspec(&ptr, r.ptr, crevspec)
+ runtime.KeepAlive(r)
+ if ret < 0 {
+ return nil, MakeGitError(ret)
+ }
+
+ annotatedCommit := newAnnotatedCommitFromC(ptr, r)
+ runtime.KeepAlive(r)
+ return annotatedCommit, nil
}
type MergeTreeFlag int
@@ -132,7 +168,7 @@ func (mo *MergeOptions) toC() *C.git_merge_options {
}
return &C.git_merge_options{
version: C.uint(mo.Version),
- flags: C.git_merge_flag_t(mo.TreeFlags),
+ flags: C.uint32_t(mo.TreeFlags),
rename_threshold: C.uint(mo.RenameThreshold),
target_limit: C.uint(mo.TargetLimit),
file_favor: C.git_merge_file_favor_t(mo.FileFavor),
@@ -344,9 +380,29 @@ type MergeFileFlags int
const (
MergeFileDefault MergeFileFlags = C.GIT_MERGE_FILE_DEFAULT
- MergeFileStyleMerge MergeFileFlags = C.GIT_MERGE_FILE_STYLE_MERGE
- MergeFileStyleDiff MergeFileFlags = C.GIT_MERGE_FILE_STYLE_DIFF3
+ // Create standard conflicted merge files
+ MergeFileStyleMerge MergeFileFlags = C.GIT_MERGE_FILE_STYLE_MERGE
+
+ // Create diff3-style files
+ MergeFileStyleDiff MergeFileFlags = C.GIT_MERGE_FILE_STYLE_DIFF3
+
+ // Condense non-alphanumeric regions for simplified diff file
MergeFileStyleSimplifyAlnum MergeFileFlags = C.GIT_MERGE_FILE_SIMPLIFY_ALNUM
+
+ // Ignore all whitespace
+ MergeFileIgnoreWhitespace MergeFileFlags = C.GIT_MERGE_FILE_IGNORE_WHITESPACE
+
+ // Ignore changes in amount of whitespace
+ MergeFileIgnoreWhitespaceChange MergeFileFlags = C.GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE
+
+ // Ignore whitespace at end of line
+ MergeFileIgnoreWhitespaceEOL MergeFileFlags = C.GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL
+
+ // Use the "patience diff" algorithm
+ MergeFileDiffPatience MergeFileFlags = C.GIT_MERGE_FILE_DIFF_PATIENCE
+
+ // Take extra time to find minimal diff
+ MergeFileDiffMinimal MergeFileFlags = C.GIT_MERGE_FILE_DIFF_MINIMAL
)
type MergeFileOptions struct {
@@ -355,6 +411,7 @@ type MergeFileOptions struct {
TheirLabel string
Favor MergeFileFavor
Flags MergeFileFlags
+ MarkerSize uint16
}
func mergeFileOptionsFromC(c C.git_merge_file_options) MergeFileOptions {
@@ -364,6 +421,7 @@ func mergeFileOptionsFromC(c C.git_merge_file_options) MergeFileOptions {
TheirLabel: C.GoString(c.their_label),
Favor: MergeFileFavor(c.favor),
Flags: MergeFileFlags(c.flags),
+ MarkerSize: uint16(c.marker_size),
}
}
@@ -372,7 +430,8 @@ func populateCMergeFileOptions(c *C.git_merge_file_options, options MergeFileOpt
c.our_label = C.CString(options.OurLabel)
c.their_label = C.CString(options.TheirLabel)
c.favor = C.git_merge_file_favor_t(options.Favor)
- c.flags = C.git_merge_file_flag_t(options.Flags)
+ c.flags = C.uint32_t(options.Flags)
+ c.marker_size = C.ushort(options.MarkerSize)
}
func freeCMergeFileOptions(c *C.git_merge_file_options) {
diff --git a/merge_test.go b/merge_test.go
index f2c84bc..7cf034f 100644
--- a/merge_test.go
+++ b/merge_test.go
@@ -5,6 +5,22 @@ import (
"time"
)
+func TestAnnotatedCommitFromRevspec(t *testing.T) {
+ t.Parallel()
+ repo := createTestRepo(t)
+ defer cleanupTestRepo(t, repo)
+
+ seedTestRepo(t, repo)
+
+ mergeHead, err := repo.AnnotatedCommitFromRevspec("refs/heads/master")
+ checkFatal(t, err)
+
+ expectedId := "473bf778b67b6d53e2ab289e0f1a2e8addef2fc2"
+ if mergeHead.Id().String() != expectedId {
+ t.Errorf("mergeHead.Id() = %v, want %v", mergeHead.Id(), expectedId)
+ }
+}
+
func TestMergeWithSelf(t *testing.T) {
t.Parallel()
repo := createTestRepo(t)
@@ -18,6 +34,11 @@ func TestMergeWithSelf(t *testing.T) {
mergeHead, err := repo.AnnotatedCommitFromRef(master)
checkFatal(t, err)
+ expectedId := "473bf778b67b6d53e2ab289e0f1a2e8addef2fc2"
+ if mergeHead.Id().String() != expectedId {
+ t.Errorf("mergeHead.Id() = %v, want %v", mergeHead.Id(), expectedId)
+ }
+
mergeHeads := make([]*AnnotatedCommit, 1)
mergeHeads[0] = mergeHead
err = repo.Merge(mergeHeads, nil, nil)
diff --git a/note.go b/note.go
index 21bed57..9df1b9d 100644
--- a/note.go
+++ b/note.go
@@ -132,7 +132,7 @@ func (c *NoteCollection) DefaultRef() (string, error) {
}
ret := C.GoString(buf.ptr)
- C.git_buf_free(&buf)
+ C.git_buf_dispose(&buf)
return ret, nil
}
diff --git a/object.go b/object.go
index 5505e35..2d75b06 100644
--- a/object.go
+++ b/object.go
@@ -13,12 +13,12 @@ import (
type ObjectType int
const (
- ObjectAny ObjectType = C.GIT_OBJ_ANY
- ObjectBad ObjectType = C.GIT_OBJ_BAD
- ObjectCommit ObjectType = C.GIT_OBJ_COMMIT
- ObjectTree ObjectType = C.GIT_OBJ_TREE
- ObjectBlob ObjectType = C.GIT_OBJ_BLOB
- ObjectTag ObjectType = C.GIT_OBJ_TAG
+ ObjectAny ObjectType = C.GIT_OBJECT_ANY
+ ObjectInvalid ObjectType = C.GIT_OBJECT_INVALID
+ ObjectCommit ObjectType = C.GIT_OBJECT_COMMIT
+ ObjectTree ObjectType = C.GIT_OBJECT_TREE
+ ObjectBlob ObjectType = C.GIT_OBJECT_BLOB
+ ObjectTag ObjectType = C.GIT_OBJECT_TAG
)
type Object struct {
@@ -35,8 +35,8 @@ func (t ObjectType) String() string {
switch t {
case ObjectAny:
return "Any"
- case ObjectBad:
- return "Bad"
+ case ObjectInvalid:
+ return "Invalid"
case ObjectCommit:
return "Commit"
case ObjectTree:
@@ -67,7 +67,7 @@ func (o *Object) ShortId() (string, error) {
if ecode < 0 {
return "", MakeGitError(ecode)
}
- defer C.git_buf_free(&resultBuf)
+ defer C.git_buf_dispose(&resultBuf)
return C.GoString(resultBuf.ptr), nil
}
@@ -217,7 +217,7 @@ func (o *Object) Peel(t ObjectType) (*Object, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
- err := C.git_object_peel(&cobj, o.ptr, C.git_otype(t))
+ err := C.git_object_peel(&cobj, o.ptr, C.git_object_t(t))
runtime.KeepAlive(o)
if err < 0 {
return nil, MakeGitError(err)
diff --git a/odb.go b/odb.go
index 64c5415..6489653 100644
--- a/odb.go
+++ b/odb.go
@@ -8,6 +8,7 @@ extern void _go_git_odb_backend_free(git_odb_backend *backend);
*/
import "C"
import (
+ "io"
"reflect"
"runtime"
"unsafe"
@@ -60,12 +61,12 @@ func (v *Odb) ReadHeader(oid *Oid) (uint64, ObjectType, error) {
defer runtime.UnlockOSThread()
var sz C.size_t
- var cotype C.git_otype
+ var cotype C.git_object_t
ret := C.git_odb_read_header(&sz, &cotype, v.ptr, oid.toC())
runtime.KeepAlive(v)
if ret < 0 {
- return 0, C.GIT_OBJ_BAD, MakeGitError(ret)
+ return 0, ObjectInvalid, MakeGitError(ret)
}
return uint64(sz), ObjectType(cotype), nil
@@ -80,15 +81,19 @@ func (v *Odb) Exists(oid *Oid) bool {
func (v *Odb) Write(data []byte, otype ObjectType) (oid *Oid, err error) {
oid = new(Oid)
- var cptr unsafe.Pointer
- if len(data) > 0 {
- cptr = unsafe.Pointer(&data[0])
- }
runtime.LockOSThread()
defer runtime.UnlockOSThread()
- ret := C.git_odb_write(oid.toC(), v.ptr, cptr, C.size_t(len(data)), C.git_otype(otype))
+ var size C.size_t
+ if len(data) > 0 {
+ size = C.size_t(len(data))
+ } else {
+ data = []byte{0}
+ size = C.size_t(0)
+ }
+
+ ret := C.git_odb_write(oid.toC(), v.ptr, unsafe.Pointer(&data[0]), size, C.git_object_t(otype))
runtime.KeepAlive(v)
if ret < 0 {
return nil, MakeGitError(ret)
@@ -164,13 +169,19 @@ func (v *Odb) ForEach(callback OdbForEachCallback) error {
// Hash determines the object-ID (sha1) of a data buffer.
func (v *Odb) Hash(data []byte, otype ObjectType) (oid *Oid, err error) {
oid = new(Oid)
- header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
- ptr := unsafe.Pointer(header.Data)
runtime.LockOSThread()
defer runtime.UnlockOSThread()
- ret := C.git_odb_hash(oid.toC(), ptr, C.size_t(header.Len), C.git_otype(otype))
+ var size C.size_t
+ if len(data) > 0 {
+ size = C.size_t(len(data))
+ } else {
+ data = []byte{0}
+ size = C.size_t(0)
+ }
+
+ ret := C.git_odb_hash(oid.toC(), unsafe.Pointer(&data[0]), size, C.git_object_t(otype))
runtime.KeepAlive(data)
if ret < 0 {
return nil, MakeGitError(ret)
@@ -182,17 +193,21 @@ func (v *Odb) Hash(data []byte, otype ObjectType) (oid *Oid, err error) {
// contents of the object.
func (v *Odb) NewReadStream(id *Oid) (*OdbReadStream, error) {
stream := new(OdbReadStream)
+ var ctype C.git_object_t
+ var csize C.size_t
runtime.LockOSThread()
defer runtime.UnlockOSThread()
- ret := C.git_odb_open_rstream(&stream.ptr, v.ptr, id.toC())
+ ret := C.git_odb_open_rstream(&stream.ptr, &csize, &ctype, v.ptr, id.toC())
runtime.KeepAlive(v)
runtime.KeepAlive(id)
if ret < 0 {
return nil, MakeGitError(ret)
}
+ stream.Size = uint64(csize)
+ stream.Type = ObjectType(ctype)
runtime.SetFinalizer(stream, (*OdbReadStream).Free)
return stream, nil
}
@@ -206,7 +221,7 @@ func (v *Odb) NewWriteStream(size int64, otype ObjectType) (*OdbWriteStream, err
runtime.LockOSThread()
defer runtime.UnlockOSThread()
- ret := C.git_odb_open_wstream(&stream.ptr, v.ptr, C.git_off_t(size), C.git_otype(otype))
+ ret := C.git_odb_open_wstream(&stream.ptr, v.ptr, C.git_object_size_t(size), C.git_object_t(otype))
runtime.KeepAlive(v)
if ret < 0 {
return nil, MakeGitError(ret)
@@ -264,7 +279,9 @@ func (object *OdbObject) Data() (data []byte) {
}
type OdbReadStream struct {
- ptr *C.git_odb_stream
+ ptr *C.git_odb_stream
+ Size uint64
+ Type ObjectType
}
// Read reads from the stream
@@ -281,6 +298,9 @@ func (stream *OdbReadStream) Read(data []byte) (int, error) {
if ret < 0 {
return 0, MakeGitError(ret)
}
+ if ret == 0 {
+ return 0, io.EOF
+ }
header.Len = int(ret)
diff --git a/odb_test.go b/odb_test.go
index 3d22fc9..46acdba 100644
--- a/odb_test.go
+++ b/odb_test.go
@@ -1,12 +1,14 @@
package git
import (
+ "bytes"
"errors"
"io"
+ "io/ioutil"
"testing"
)
-func TestOdbReadHeader(t *testing.T) {
+func TestOdbRead(t *testing.T) {
t.Parallel()
repo := createTestRepo(t)
defer cleanupTestRepo(t, repo)
@@ -26,13 +28,27 @@ func TestOdbReadHeader(t *testing.T) {
if err != nil {
t.Fatalf("ReadHeader: %v", err)
}
-
+
if sz != uint64(len(data)) {
t.Errorf("ReadHeader got size %d, want %d", sz, len(data))
}
if typ != ObjectBlob {
t.Errorf("ReadHeader got object type %s", typ)
}
+
+ obj, err := odb.Read(id)
+ if err != nil {
+ t.Fatalf("Read: %v", err)
+ }
+ if !bytes.Equal(obj.Data(), data) {
+ t.Errorf("Read got wrong data")
+ }
+ if sz := obj.Len(); sz != uint64(len(data)) {
+ t.Errorf("Read got size %d, want %d", sz, len(data))
+ }
+ if typ := obj.Type(); typ != ObjectBlob {
+ t.Errorf("Read got object type %s", typ)
+ }
}
func TestOdbStream(t *testing.T) {
@@ -47,22 +63,29 @@ func TestOdbStream(t *testing.T) {
str := "hello, world!"
- stream, error := odb.NewWriteStream(int64(len(str)), ObjectBlob)
+ writeStream, error := odb.NewWriteStream(int64(len(str)), ObjectBlob)
checkFatal(t, error)
- n, error := io.WriteString(stream, str)
+ n, error := io.WriteString(writeStream, str)
checkFatal(t, error)
if n != len(str) {
t.Fatalf("Bad write length %v != %v", n, len(str))
}
- error = stream.Close()
+ error = writeStream.Close()
checkFatal(t, error)
expectedId, error := NewOid("30f51a3fba5274d53522d0f19748456974647b4f")
checkFatal(t, error)
- if stream.Id.Cmp(expectedId) != 0 {
+ if writeStream.Id.Cmp(expectedId) != 0 {
t.Fatal("Wrong data written")
}
+
+ readStream, error := odb.NewReadStream(&writeStream.Id)
+ checkFatal(t, error)
+ data, error := ioutil.ReadAll(readStream)
+ if str != string(data) {
+ t.Fatalf("Wrong data read %v != %v", str, string(data))
+ }
}
func TestOdbHash(t *testing.T) {
@@ -82,14 +105,16 @@ committer John Doe <[email protected]> 1390682018 +0000
Initial commit.`
- oid, error := odb.Hash([]byte(str), ObjectCommit)
- checkFatal(t, error)
+ for _, data := range [][]byte{[]byte(str), doublePointerBytes()} {
+ oid, error := odb.Hash(data, ObjectCommit)
+ checkFatal(t, error)
- coid, error := odb.Write([]byte(str), ObjectCommit)
- checkFatal(t, error)
+ coid, error := odb.Write(data, ObjectCommit)
+ checkFatal(t, error)
- if oid.Cmp(coid) != 0 {
- t.Fatal("Hash and write Oids are different")
+ if oid.Cmp(coid) != 0 {
+ t.Fatal("Hash and write Oids are different")
+ }
}
}
diff --git a/packbuilder.go b/packbuilder.go
index 0e04bbf..576e5ca 100644
--- a/packbuilder.go
+++ b/packbuilder.go
@@ -85,6 +85,19 @@ func (pb *Packbuilder) InsertTree(id *Oid) error {
return nil
}
+func (pb *Packbuilder) InsertWalk(walk *RevWalk) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_packbuilder_insert_walk(pb.ptr, walk.ptr)
+ runtime.KeepAlive(pb)
+ runtime.KeepAlive(walk)
+ if ret != 0 {
+ return MakeGitError(ret)
+ }
+ return nil
+}
+
func (pb *Packbuilder) ObjectCount() uint32 {
ret := uint32(C.git_packbuilder_object_count(pb.ptr))
runtime.KeepAlive(pb)
diff --git a/patch.go b/patch.go
index 7e6f71d..6a16b5f 100644
--- a/patch.go
+++ b/patch.go
@@ -51,7 +51,7 @@ func (patch *Patch) String() (string, error) {
if ecode < 0 {
return "", MakeGitError(ecode)
}
- defer C.git_buf_free(&buf)
+ defer C.git_buf_dispose(&buf)
return C.GoString(buf.ptr), nil
}
diff --git a/rebase.go b/rebase.go
index 5206fca..d29e183 100644
--- a/rebase.go
+++ b/rebase.go
@@ -6,6 +6,7 @@ package git
import "C"
import (
"errors"
+ "fmt"
"runtime"
"unsafe"
)
@@ -16,6 +17,8 @@ type RebaseOperationType uint
const (
// RebaseOperationPick The given commit is to be cherry-picked. The client should commit the changes and continue if there are no conflicts.
RebaseOperationPick RebaseOperationType = C.GIT_REBASE_OPERATION_PICK
+ // RebaseOperationReword The given commit is to be cherry-picked, but the client should prompt the user to provide an updated commit message.
+ RebaseOperationReword RebaseOperationType = C.GIT_REBASE_OPERATION_REWORD
// RebaseOperationEdit The given commit is to be cherry-picked, but the client should stop to allow the user to edit the changes before committing them.
RebaseOperationEdit RebaseOperationType = C.GIT_REBASE_OPERATION_EDIT
// RebaseOperationSquash The given commit is to be squashed into the previous commit. The commit message will be merged with the previous message.
@@ -26,6 +29,24 @@ const (
RebaseOperationExec RebaseOperationType = C.GIT_REBASE_OPERATION_EXEC
)
+func (t RebaseOperationType) String() string {
+ switch t {
+ case RebaseOperationPick:
+ return "pick"
+ case RebaseOperationReword:
+ return "reword"
+ case RebaseOperationEdit:
+ return "edit"
+ case RebaseOperationSquash:
+ return "squash"
+ case RebaseOperationFixup:
+ return "fixup"
+ case RebaseOperationExec:
+ return "exec"
+ }
+ return fmt.Sprintf("RebaseOperationType(%d)", t)
+}
+
// Special value indicating that there is no currently active operation
var RebaseNoOperation uint = ^uint(0)
diff --git a/reference.go b/reference.go
index e10c9b2..b5f5e47 100644
--- a/reference.go
+++ b/reference.go
@@ -284,7 +284,7 @@ func (v *Reference) Peel(t ObjectType) (*Object, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
- err := C.git_reference_peel(&cobj, v.ptr, C.git_otype(t))
+ err := C.git_reference_peel(&cobj, v.ptr, C.git_object_t(t))
runtime.KeepAlive(v)
if err < 0 {
return nil, MakeGitError(err)
@@ -301,7 +301,7 @@ func (v *Reference) Owner() *Repository {
}
}
-// Cmp compares both references, retursn 0 on equality, otherwise a
+// Cmp compares v to ref2. It returns 0 on equality, otherwise a
// stable sorting.
func (v *Reference) Cmp(ref2 *Reference) int {
ret := int(C.git_reference_cmp(v.ptr, ref2.ptr))
@@ -310,13 +310,14 @@ func (v *Reference) Cmp(ref2 *Reference) int {
return ret
}
-// Shorthand ret :=s a "human-readable" short reference name
+// Shorthand returns a "human-readable" short reference name.
func (v *Reference) Shorthand() string {
ret := C.GoString(C.git_reference_shorthand(v.ptr))
runtime.KeepAlive(v)
return ret
}
+// Name returns the full name of v.
func (v *Reference) Name() string {
ret := C.GoString(C.git_reference_name(v.ptr))
runtime.KeepAlive(v)
@@ -455,10 +456,12 @@ func (v *ReferenceIterator) Next() (*Reference, error) {
}
func newReferenceIteratorFromC(ptr *C.git_reference_iterator, r *Repository) *ReferenceIterator {
- return &ReferenceIterator{
+ iter := &ReferenceIterator{
ptr: ptr,
repo: r,
}
+ runtime.SetFinalizer(iter, (*ReferenceIterator).Free)
+ return iter
}
// Free the reference iterator
diff --git a/remote.go b/remote.go
index b4b1dd7..43ffd33 100644
--- a/remote.go
+++ b/remote.go
@@ -1,9 +1,11 @@
package git
/*
-#include <git2.h>
#include <string.h>
+#include <git2.h>
+#include <git2/sys/cred.h>
+
extern void _go_git_setup_callbacks(git_remote_callbacks *callbacks);
*/
diff --git a/repository.go b/repository.go
index d8de97a..07b2605 100644
--- a/repository.go
+++ b/repository.go
@@ -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 (
@@ -174,7 +176,7 @@ func (v *Repository) lookupType(id *Oid, t ObjectType) (*Object, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
- ret := C.git_object_lookup(&ptr, v.ptr, id.toC(), C.git_otype(t))
+ ret := C.git_object_lookup(&ptr, v.ptr, id.toC(), C.git_object_t(t))
runtime.KeepAlive(id)
if ret < 0 {
return nil, MakeGitError(ret)
@@ -192,6 +194,7 @@ func (v *Repository) LookupTree(id *Oid) (*Tree, error) {
if err != nil {
return nil, err
}
+ defer obj.Free()
return obj.AsTree()
}
@@ -201,6 +204,7 @@ func (v *Repository) LookupCommit(id *Oid) (*Commit, error) {
if err != nil {
return nil, err
}
+ defer obj.Free()
return obj.AsCommit()
}
@@ -210,6 +214,7 @@ func (v *Repository) LookupBlob(id *Oid) (*Blob, error) {
if err != nil {
return nil, err
}
+ defer obj.Free()
return obj.AsBlob()
}
@@ -219,6 +224,7 @@ func (v *Repository) LookupTag(id *Oid) (*Tag, error) {
if err != nil {
return nil, err
}
+ defer obj.Free()
return obj.AsTag()
}
@@ -389,6 +395,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)
diff --git a/repository_test.go b/repository_test.go
new file mode 100644
index 0000000..1950c69
--- /dev/null
+++ b/repository_test.go
@@ -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: "[email protected]",
+ 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())
+ }
+}
diff --git a/reset_test.go b/reset_test.go
index 45777e4..89ebc49 100644
--- a/reset_test.go
+++ b/reset_test.go
@@ -8,6 +8,8 @@ import (
func TestResetToCommit(t *testing.T) {
t.Parallel()
repo := createTestRepo(t)
+ defer cleanupTestRepo(t, repo)
+
seedTestRepo(t, repo)
// create commit to reset to
commitId, _ := updateReadme(t, repo, "testing reset")
diff --git a/revert.go b/revert.go
new file mode 100644
index 0000000..e745f11
--- /dev/null
+++ b/revert.go
@@ -0,0 +1,101 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import (
+ "runtime"
+)
+
+// RevertOptions contains options for performing a revert
+type RevertOptions struct {
+ Mainline uint
+ MergeOpts MergeOptions
+ CheckoutOpts CheckoutOpts
+}
+
+func (opts *RevertOptions) toC() *C.git_revert_options {
+ return &C.git_revert_options{
+ version: C.GIT_REVERT_OPTIONS_VERSION,
+ mainline: C.uint(opts.Mainline),
+ merge_opts: *opts.MergeOpts.toC(),
+ checkout_opts: *opts.CheckoutOpts.toC(),
+ }
+}
+
+func revertOptionsFromC(opts *C.git_revert_options) RevertOptions {
+ return RevertOptions{
+ Mainline: uint(opts.mainline),
+ MergeOpts: mergeOptionsFromC(&opts.merge_opts),
+ CheckoutOpts: checkoutOptionsFromC(&opts.checkout_opts),
+ }
+}
+
+func freeRevertOptions(opts *C.git_revert_options) {
+ freeCheckoutOpts(&opts.checkout_opts)
+}
+
+// DefaultRevertOptions initialises a RevertOptions struct with default values
+func DefaultRevertOptions() (RevertOptions, error) {
+ opts := C.git_revert_options{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_revert_init_options(&opts, C.GIT_REVERT_OPTIONS_VERSION)
+ if ecode < 0 {
+ return RevertOptions{}, MakeGitError(ecode)
+ }
+
+ defer freeRevertOptions(&opts)
+ return revertOptionsFromC(&opts), nil
+}
+
+// Revert the provided commit leaving the index updated with the results of the revert
+func (r *Repository) Revert(commit *Commit, revertOptions *RevertOptions) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var cOpts *C.git_revert_options
+
+ if revertOptions != nil {
+ cOpts = revertOptions.toC()
+ defer freeRevertOptions(cOpts)
+ }
+
+ ecode := C.git_revert(r.ptr, commit.cast_ptr, cOpts)
+ runtime.KeepAlive(r)
+ runtime.KeepAlive(commit)
+
+ if ecode < 0 {
+ return MakeGitError(ecode)
+ }
+
+ return nil
+}
+
+// RevertCommit reverts the provided commit against "ourCommit"
+// The returned index contains the result of the revert and should be freed
+func (r *Repository) RevertCommit(revertCommit *Commit, ourCommit *Commit, mainline uint, mergeOptions *MergeOptions) (*Index, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var cOpts *C.git_merge_options
+
+ if mergeOptions != nil {
+ cOpts = mergeOptions.toC()
+ }
+
+ var index *C.git_index
+
+ ecode := C.git_revert_commit(&index, r.ptr, revertCommit.cast_ptr, ourCommit.cast_ptr, C.uint(mainline), cOpts)
+ runtime.KeepAlive(revertCommit)
+ runtime.KeepAlive(ourCommit)
+
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ return newIndexFromC(index, r), nil
+}
diff --git a/revert_test.go b/revert_test.go
new file mode 100644
index 0000000..fcf8e43
--- /dev/null
+++ b/revert_test.go
@@ -0,0 +1,76 @@
+package git
+
+import (
+ "testing"
+)
+
+const (
+ expectedRevertedReadmeContents = "foo\n"
+)
+
+func TestRevert(t *testing.T) {
+ t.Parallel()
+ repo := createTestRepo(t)
+ defer cleanupTestRepo(t, repo)
+
+ seedTestRepo(t, repo)
+ commitID, _ := updateReadme(t, repo, content)
+
+ commit, err := repo.LookupCommit(commitID)
+ checkFatal(t, err)
+
+ revertOptions, err := DefaultRevertOptions()
+ checkFatal(t, err)
+
+ err = repo.Revert(commit, &revertOptions)
+ checkFatal(t, err)
+
+ actualReadmeContents := readReadme(t, repo)
+
+ if actualReadmeContents != expectedRevertedReadmeContents {
+ t.Fatalf(`README has incorrect contents after revert. Expected: "%v", Actual: "%v"`,
+ expectedRevertedReadmeContents, actualReadmeContents)
+ }
+
+ state := repo.State()
+ if state != RepositoryStateRevert {
+ t.Fatalf("Incorrect repository state. Expected: %v, Actual: %v", RepositoryStateRevert, state)
+ }
+
+ err = repo.StateCleanup()
+ checkFatal(t, err)
+
+ state = repo.State()
+ if state != RepositoryStateNone {
+ t.Fatalf("Incorrect repository state. Expected: %v, Actual: %v", RepositoryStateNone, state)
+ }
+}
+
+func TestRevertCommit(t *testing.T) {
+ t.Parallel()
+ repo := createTestRepo(t)
+ defer cleanupTestRepo(t, repo)
+
+ seedTestRepo(t, repo)
+ commitID, _ := updateReadme(t, repo, content)
+
+ commit, err := repo.LookupCommit(commitID)
+ checkFatal(t, err)
+
+ revertOptions, err := DefaultRevertOptions()
+ checkFatal(t, err)
+
+ index, err := repo.RevertCommit(commit, commit, 0, &revertOptions.MergeOpts)
+ checkFatal(t, err)
+ defer index.Free()
+
+ err = repo.CheckoutIndex(index, &revertOptions.CheckoutOpts)
+ checkFatal(t, err)
+
+ actualReadmeContents := readReadme(t, repo)
+
+ if actualReadmeContents != expectedRevertedReadmeContents {
+ t.Fatalf(`README has incorrect contents after revert. Expected: "%v", Actual: "%v"`,
+ expectedRevertedReadmeContents, actualReadmeContents)
+ }
+}
diff --git a/script/build-libgit2-dynamic.sh b/script/build-libgit2-dynamic.sh
new file mode 100755
index 0000000..af037f3
--- /dev/null
+++ b/script/build-libgit2-dynamic.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+set -e
+
+exec "$(dirname "$0")/build-libgit2.sh" --dynamic
diff --git a/script/build-libgit2-static.sh b/script/build-libgit2-static.sh
index 5723721..1d28898 100755
--- a/script/build-libgit2-static.sh
+++ b/script/build-libgit2-static.sh
@@ -1,19 +1,5 @@
#!/bin/sh
-set -ex
+set -e
-VENDORED_PATH=vendor/libgit2
-
-cd $VENDORED_PATH &&
-mkdir -p install/lib &&
-mkdir -p build &&
-cd build &&
-cmake -DTHREADSAFE=ON \
- -DBUILD_CLAR=OFF \
- -DBUILD_SHARED_LIBS=OFF \
- -DCMAKE_C_FLAGS=-fPIC \
- -DCMAKE_BUILD_TYPE="RelWithDebInfo" \
- -DCMAKE_INSTALL_PREFIX=../install \
- .. &&
-
-cmake --build .
+exec "$(dirname "$0")/build-libgit2.sh" --static
diff --git a/script/build-libgit2.sh b/script/build-libgit2.sh
new file mode 100755
index 0000000..acbc84a
--- /dev/null
+++ b/script/build-libgit2.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+# Since CMake cannot build the static and dynamic libraries in the same
+# directory, this script helps build both static and dynamic versions of it and
+# have the common flags in one place instead of split between two places.
+
+set -e
+
+if [ "$#" -eq "0" ]; then
+ echo "Usage: $0 <--dynamic|--static>">&2
+ exit 1
+fi
+
+ROOT="$(cd "$(dirname "$0")/.." && echo "${PWD}")"
+VENDORED_PATH="${ROOT}/vendor/libgit2"
+
+case "$1" in
+ --static)
+ BUILD_PATH="${ROOT}/static-build"
+ BUILD_SHARED_LIBS=OFF
+ ;;
+
+ --dynamic)
+ BUILD_PATH="${ROOT}/dynamic-build"
+ BUILD_SHARED_LIBS=ON
+ ;;
+
+ *)
+ echo "Usage: $0 <--dynamic|--static>">&2
+ exit 1
+ ;;
+esac
+
+mkdir -p "${BUILD_PATH}/build" "${BUILD_PATH}/install/lib"
+
+cd "${BUILD_PATH}/build" &&
+cmake -DTHREADSAFE=ON \
+ -DBUILD_CLAR=OFF \
+ -DBUILD_SHARED_LIBS"=${BUILD_SHARED_LIBS}" \
+ -DREGEX_BACKEND=builtin \
+ -DCMAKE_C_FLAGS=-fPIC \
+ -DCMAKE_BUILD_TYPE="RelWithDebInfo" \
+ -DCMAKE_INSTALL_PREFIX="${BUILD_PATH}/install" \
+ "${VENDORED_PATH}" &&
+
+exec cmake --build . --target install
diff --git a/settings.go b/settings.go
index c7f1850..b9bc216 100644
--- a/settings.go
+++ b/settings.go
@@ -31,7 +31,7 @@ import (
func SearchPath(level ConfigLevel) (string, error) {
var buf C.git_buf
- defer C.git_buf_free(&buf)
+ defer C.git_buf_dispose(&buf)
runtime.LockOSThread()
defer runtime.UnlockOSThread()
diff --git a/signature.go b/signature.go
index 16964d2..220fe57 100644
--- a/signature.go
+++ b/signature.go
@@ -26,7 +26,7 @@ func newSignatureFromC(sig *C.git_signature) *Signature {
}
}
-// the offset in mintes, which is what git wants
+// Offset returns the time zone offset of v.When in minutes, which is what git wants.
func (v *Signature) Offset() int {
_, offset := v.When.Zone()
return offset / 60
diff --git a/stash.go b/stash.go
index 8743da8..6624bce 100644
--- a/stash.go
+++ b/stash.go
@@ -171,7 +171,7 @@ func (opts *StashApplyOptions) toC() (
optsC = &C.git_stash_apply_options{
version: C.GIT_STASH_APPLY_OPTIONS_VERSION,
- flags: C.git_stash_apply_flags(opts.Flags),
+ flags: C.uint32_t(opts.Flags),
}
populateCheckoutOpts(&optsC.checkout_options, &opts.CheckoutOptions)
if opts.ProgressCallback != nil {
diff --git a/tag.go b/tag.go
index 4debdb7..1bea2b7 100644
--- a/tag.go
+++ b/tag.go
@@ -21,26 +21,26 @@ func (t *Tag) AsObject() *Object {
return &t.Object
}
-func (t Tag) Message() string {
+func (t *Tag) Message() string {
ret := C.GoString(C.git_tag_message(t.cast_ptr))
runtime.KeepAlive(t)
return ret
}
-func (t Tag) Name() string {
+func (t *Tag) Name() string {
ret := C.GoString(C.git_tag_name(t.cast_ptr))
runtime.KeepAlive(t)
return ret
}
-func (t Tag) Tagger() *Signature {
+func (t *Tag) Tagger() *Signature {
cast_ptr := C.git_tag_tagger(t.cast_ptr)
ret := newSignatureFromC(cast_ptr)
runtime.KeepAlive(t)
return ret
}
-func (t Tag) Target() *Object {
+func (t *Tag) Target() *Object {
var ptr *C.git_object
ret := C.git_tag_target(&ptr, t.cast_ptr)
runtime.KeepAlive(t)
@@ -51,13 +51,13 @@ func (t Tag) Target() *Object {
return allocObject(ptr, t.repo)
}
-func (t Tag) TargetId() *Oid {
+func (t *Tag) TargetId() *Oid {
ret := newOidFromC(C.git_tag_target_id(t.cast_ptr))
runtime.KeepAlive(t)
return ret
}
-func (t Tag) TargetType() ObjectType {
+func (t *Tag) TargetType() ObjectType {
ret := ObjectType(C.git_tag_target_type(t.cast_ptr))
runtime.KeepAlive(t)
return ret
diff --git a/tree.go b/tree.go
index ee14ec5..b309193 100644
--- a/tree.go
+++ b/tree.go
@@ -47,17 +47,18 @@ func newTreeEntry(entry *C.git_tree_entry) *TreeEntry {
}
}
-func (t Tree) EntryByName(filename string) *TreeEntry {
+func (t *Tree) EntryByName(filename string) *TreeEntry {
cname := C.CString(filename)
defer C.free(unsafe.Pointer(cname))
entry := C.git_tree_entry_byname(t.cast_ptr, cname)
- runtime.KeepAlive(t)
if entry == nil {
return nil
}
- return newTreeEntry(entry)
+ goEntry := newTreeEntry(entry)
+ runtime.KeepAlive(t)
+ return goEntry
}
// EntryById performs a lookup for a tree entry with the given SHA value.
@@ -66,23 +67,24 @@ func (t Tree) EntryByName(filename string) *TreeEntry {
// free it, but you must not use it after the Tree is freed.
//
// Warning: this must examine every entry in the tree, so it is not fast.
-func (t Tree) EntryById(id *Oid) *TreeEntry {
+func (t *Tree) EntryById(id *Oid) *TreeEntry {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
entry := C.git_tree_entry_byid(t.cast_ptr, id.toC())
- runtime.KeepAlive(t)
runtime.KeepAlive(id)
if entry == nil {
return nil
}
- return newTreeEntry(entry)
+ goEntry := newTreeEntry(entry)
+ runtime.KeepAlive(t)
+ return goEntry
}
// EntryByPath looks up an entry by its full path, recursing into
// deeper trees if necessary (i.e. if there are slashes in the path)
-func (t Tree) EntryByPath(path string) (*TreeEntry, error) {
+func (t *Tree) EntryByPath(path string) (*TreeEntry, error) {
cpath := C.CString(path)
defer C.free(unsafe.Pointer(cpath))
var entry *C.git_tree_entry
@@ -100,17 +102,18 @@ func (t Tree) EntryByPath(path string) (*TreeEntry, error) {
return newTreeEntry(entry), nil
}
-func (t Tree) EntryByIndex(index uint64) *TreeEntry {
+func (t *Tree) EntryByIndex(index uint64) *TreeEntry {
entry := C.git_tree_entry_byindex(t.cast_ptr, C.size_t(index))
- runtime.KeepAlive(t)
if entry == nil {
return nil
}
- return newTreeEntry(entry)
+ goEntry := newTreeEntry(entry)
+ runtime.KeepAlive(t)
+ return goEntry
}
-func (t Tree) EntryCount() uint64 {
+func (t *Tree) EntryCount() uint64 {
num := C.git_tree_entrycount(t.cast_ptr)
runtime.KeepAlive(t)
return uint64(num)
@@ -119,9 +122,8 @@ func (t Tree) EntryCount() uint64 {
type TreeWalkCallback func(string, *TreeEntry) int
//export CallbackGitTreeWalk
-func CallbackGitTreeWalk(_root *C.char, _entry unsafe.Pointer, ptr unsafe.Pointer) C.int {
+func CallbackGitTreeWalk(_root *C.char, entry *C.git_tree_entry, ptr unsafe.Pointer) C.int {
root := C.GoString(_root)
- entry := (*C.git_tree_entry)(_entry)
if callback, ok := pointerHandles.Get(ptr).(TreeWalkCallback); ok {
return C.int(callback(root, newTreeEntry(entry)))
@@ -130,7 +132,7 @@ func CallbackGitTreeWalk(_root *C.char, _entry unsafe.Pointer, ptr unsafe.Pointe
}
}
-func (t Tree) Walk(callback TreeWalkCallback) error {
+func (t *Tree) Walk(callback TreeWalkCallback) error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
diff --git a/vendor/libgit2 b/vendor/libgit2
-Subproject f1323d9c161aeeada190fd9615a8b5a9fb8a7f3
+Subproject ee3307a183e39d602b25fa94831c6fc09e7c1b6
diff --git a/wrapper.c b/wrapper.c
index 11c2f32..3656773 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -2,6 +2,7 @@
#include <git2.h>
#include <git2/sys/odb_backend.h>
#include <git2/sys/refdb_backend.h>
+#include <git2/sys/cred.h>
typedef int (*gogit_submodule_cbk)(git_submodule *sm, const char *name, void *payload);
@@ -180,4 +181,8 @@ void _go_git_writestream_free(git_writestream *stream)
stream->free(stream);
}
+git_credtype_t _go_git_cred_credtype(git_cred *cred) {
+ return cred->credtype;
+}
+
/* EOF */