Merge pull request #180 from arcamael/master

Add possibiliy of checkout on specific path
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 8eb5872..0000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "vendor/libgit2"]
-	path = vendor/libgit2
-	url = https://github.com/libgit2/libgit2
diff --git a/.travis.yml b/.travis.yml
index f84d07e..f8b7e93 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,9 +1,19 @@
 language: go
 
+install:
+  - cd "${HOME}"
+  - wget -O libgit2-0.22.1.tar.gz https://github.com/libgit2/libgit2/archive/v0.22.1.tar.gz
+  - tar -xzvf libgit2-0.22.1.tar.gz
+  - cd libgit2-0.22.1 && mkdir build && cd build
+  - cmake -DTHREADSAFE=ON -DBUILD_CLAR=OFF -DCMAKE_C_FLAGS=-fPIC -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DCMAKE_INSTALL_PREFIX=/usr/local .. && make && sudo make install
+  - sudo ldconfig
+  - cd "${TRAVIS_BUILD_DIR}"
+
 go:
   - 1.1
   - 1.2
   - 1.3
+  - 1.4
   - tip
 
 matrix:
diff --git a/Makefile b/Makefile
index 3040857..9c42283 100644
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,8 @@
 default: test
 
-build-libgit2:
-	./script/build-libgit2-static.sh
-
-test: build-libgit2
+test:
 	go run script/check-MakeGitError-thread-lock.go
-	./script/with-static.sh go test ./...
+	go test ./...
 
-install: build-libgit2
-	./script/with-static.sh go install ./...
+install:
+	go install ./...
diff --git a/README.md b/README.md
index faeb5f5..386ff83 100644
--- a/README.md
+++ b/README.md
@@ -3,27 +3,34 @@
 [![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. The versioned branches indicate which libgit2 version they work against.
+Go bindings for [libgit2](http://libgit2.github.com/). The `master` branch follows the latest libgit2 release. The versioned branches indicate which libgit2 version they work against.
 
 Installing
 ----------
 
-This project needs libgit2, which is written in C so we need to build that as well. In order to build libgit2, you need `cmake`, `pkg-config` and a C compiler. You will also need the development packages for OpenSSL and LibSSH2 installed if you want libgit2 to support HTTPS and SSH respectively.
+This project wraps the functionality provided by libgit2. If you're using a stable version, install it to your system via your system's package manger and then install git2go as usual.
+
+Otherwise (`next` which tracks an unstable version), we need to build libgit2 as well. In order to build it, you need `cmake`, `pkg-config` and a C compiler. You will also need the development packages for OpenSSL and LibSSH2 installed if you want libgit2 to support HTTPS and SSH respectively.
 
 ### Stable version
 
-git2go has versioned branches which indicate which version of libgit2 they work against. Install the development package it on your system via your favourite package manager or from source and you can use a service like gopkg.in to use the appropriate version. For the libgit2 v0.22 case, you can use
+git2go has `master` which tracks the latest release of libgit2, and versioned branches which indicate which version of libgit2 they work against. Install the development package it on your system via your favourite package manager or from source and you can use a service like gopkg.in to use the appropriate version. For the libgit2 v0.22 case, you can use
 
     import "gopkg.in/libgit2/git2go.v22"
 
-to use a version of git2go which will work against libgit2 v0.22 and dynamically link to the library.
+to use a version of git2go which will work against libgit2 v0.22 and dynamically link to the library. You can use
 
-### From master
+    import "github.com/libgit2/git2go"
 
-The master branch follows libgit2's master branch, which means there is no stable API or ABI to link against. git2go can statically link against a vendored version of libgit2.
+to use the version which works against the latest release.
+
+### From `next`
+
+The `next` branch follows libgit2's master branch, which means there is no stable API or ABI to link against. git2go can statically link against a vendored version of libgit2.
 
 Run `go get -d github.com/libgit2/git2go` to download the code and go to your `$GOPATH/src/github.com/libgit2/git2go` dir. From there, we need to build the C code and put it into the resulting go binary.
 
+    git checkout next
     git submodule update --init # get libgit2
     make install
 
@@ -37,7 +44,7 @@
 Running the tests
 -----------------
 
-For the stable version, `go test` will work as usual. For the master branch, similarly to installing, running the tests requires linking against the local libgit2 library, so the Makefile provides a wrapper
+For the stable version, `go test` will work as usual. For the `next` branch, similarly to installing, running the tests requires linking against the local libgit2 library, so the Makefile provides a wrapper
 
     make test
 
diff --git a/branch.go b/branch.go
index 54b01fb..22b767e 100644
--- a/branch.go
+++ b/branch.go
@@ -96,7 +96,10 @@
 	cBranchName := C.CString(branchName)
 	cForce := cbool(force)
 
-	cSignature := signature.toC()
+	cSignature, err := signature.toC()
+	if err != nil {
+		return nil, err
+	}
 	defer C.git_signature_free(cSignature)
 
 	var cmsg *C.char
@@ -133,7 +136,10 @@
 	cNewBranchName := C.CString(newBranchName)
 	cForce := cbool(force)
 
-	cSignature := signature.toC()
+	cSignature, err := signature.toC()
+	if err != nil {
+		return nil, err
+	}
 	defer C.git_signature_free(cSignature)
 
 	var cmsg *C.char
diff --git a/checkout.go b/checkout.go
index c507172..9874d2b 100644
--- a/checkout.go
+++ b/checkout.go
@@ -20,10 +20,10 @@
 	CheckoutAllowConflicts            CheckoutStrategy = C.GIT_CHECKOUT_ALLOW_CONFLICTS              // Allow checkout to make safe updates even if conflicts are found
 	CheckoutRemoveUntracked           CheckoutStrategy = C.GIT_CHECKOUT_REMOVE_UNTRACKED             // Remove untracked files not in index (that are not ignored)
 	CheckoutRemoveIgnored             CheckoutStrategy = C.GIT_CHECKOUT_REMOVE_IGNORED               // Remove ignored files not in index
-	CheckotUpdateOnly                 CheckoutStrategy = C.GIT_CHECKOUT_UPDATE_ONLY                  // Only update existing files, don't create new ones
+	CheckoutUpdateOnly                CheckoutStrategy = C.GIT_CHECKOUT_UPDATE_ONLY                  // Only update existing files, don't create new ones
 	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
-	CheckooutDisablePathspecMatch     CheckoutStrategy = C.GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH       // Treat pathspec as simple list of exact match file paths
+	CheckoutDisablePathspecMatch      CheckoutStrategy = C.GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH       // Treat pathspec as simple list of exact match file paths
 	CheckoutSkipUnmerged              CheckoutStrategy = C.GIT_CHECKOUT_SKIP_UNMERGED                // Allow checkout to skip unmerged files (NOT IMPLEMENTED)
 	CheckoutUserOurs                  CheckoutStrategy = C.GIT_CHECKOUT_USE_OURS                     // For unmerged files, checkout stage 2 from index (NOT IMPLEMENTED)
 	CheckoutUseTheirs                 CheckoutStrategy = C.GIT_CHECKOUT_USE_THEIRS                   // For unmerged files, checkout stage 3 from index (NOT IMPLEMENTED)
@@ -41,6 +41,19 @@
 	Paths			[]string
 }
 
+func checkoutOptionsFromC(c *C.git_checkout_options) CheckoutOpts {
+	opts := CheckoutOpts{}
+	opts.Strategy = CheckoutStrategy(c.checkout_strategy)
+	opts.DisableFilters = c.disable_filters != 0
+	opts.DirMode = os.FileMode(c.dir_mode)
+	opts.FileMode = os.FileMode(c.file_mode)
+	opts.FileOpenFlags = int(c.file_open_flags)
+	if c.target_directory != nil {
+		opts.TargetDirectory = C.GoString(c.target_directory)
+	}
+	return opts
+}
+
 func (opts *CheckoutOpts) toC() *C.git_checkout_options {
 	if opts == nil {
 		return nil
diff --git a/cherrypick.go b/cherrypick.go
new file mode 100644
index 0000000..afc1b7e
--- /dev/null
+++ b/cherrypick.go
@@ -0,0 +1,73 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import (
+	"runtime"
+)
+
+type CherrypickOptions struct {
+	Version      uint
+	Mainline     uint
+	MergeOpts    MergeOptions
+	CheckoutOpts CheckoutOpts
+}
+
+func cherrypickOptionsFromC(c *C.git_cherrypick_options) CherrypickOptions {
+	opts := CherrypickOptions{
+		Version:      uint(c.version),
+		Mainline:     uint(c.mainline),
+		MergeOpts:    mergeOptionsFromC(&c.merge_opts),
+		CheckoutOpts: checkoutOptionsFromC(&c.checkout_opts),
+	}
+	return opts
+}
+
+func (opts *CherrypickOptions) toC() *C.git_cherrypick_options {
+	if opts == nil {
+		return nil
+	}
+	c := C.git_cherrypick_options{}
+	c.version = C.uint(opts.Version)
+	c.mainline = C.uint(opts.Mainline)
+	c.merge_opts = *opts.MergeOpts.toC()
+	c.checkout_opts = *opts.CheckoutOpts.toC()
+	return &c
+}
+
+func freeCherrypickOpts(ptr *C.git_cherrypick_options) {
+	if ptr == nil {
+		return
+	}
+	freeCheckoutOpts(&ptr.checkout_opts)
+}
+
+func DefaultCherrypickOptions() (CherrypickOptions, error) {
+	c := C.git_cherrypick_options{}
+
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	ecode := C.git_cherrypick_init_options(&c, C.GIT_CHERRYPICK_OPTIONS_VERSION)
+	if ecode < 0 {
+		return CherrypickOptions{}, MakeGitError(ecode)
+	}
+	defer freeCherrypickOpts(&c)
+	return cherrypickOptionsFromC(&c), nil
+}
+
+func (v *Repository) Cherrypick(commit *Commit, opts CherrypickOptions) error {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	cOpts := opts.toC()
+	defer freeCherrypickOpts(cOpts)
+
+	ecode := C.git_cherrypick(v.ptr, commit.cast_ptr, cOpts)
+	if ecode < 0 {
+		return MakeGitError(ecode)
+	}
+	return nil
+}
diff --git a/cherrypick_test.go b/cherrypick_test.go
new file mode 100644
index 0000000..f06dbdd
--- /dev/null
+++ b/cherrypick_test.go
@@ -0,0 +1,83 @@
+package git
+
+import (
+	"io/ioutil"
+	"testing"
+)
+
+func checkout(t *testing.T, repo *Repository, commit *Commit) {
+	tree, err := commit.Tree()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = repo.CheckoutTree(tree, &CheckoutOpts{Strategy: CheckoutSafe})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = repo.SetHeadDetached(commit.Id(), commit.Author(), "checkout")
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+const content = "Herro, Worrd!"
+
+func readReadme(t *testing.T, repo *Repository) string {
+	bytes, err := ioutil.ReadFile(pathInRepo(repo, "README"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	return string(bytes)
+}
+
+func TestCherrypick(t *testing.T) {
+	repo := createTestRepo(t)
+	c1, _ := seedTestRepo(t, repo)
+	c2, _ := updateReadme(t, repo, content)
+
+	commit1, err := repo.LookupCommit(c1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	commit2, err := repo.LookupCommit(c2)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	checkout(t, repo, commit1)
+
+	if readReadme(t, repo) == content {
+		t.Fatalf("README has wrong content after checking out initial commit")
+	}
+
+	opts, err := DefaultCherrypickOptions()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = repo.Cherrypick(commit2, opts)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if readReadme(t, repo) != content {
+		t.Fatalf("README has wrong contents after cherry-picking")
+	}
+
+	state := repo.State()
+	if state != RepositoryStateCherrypick {
+		t.Fatal("Incorrect repository state: ", state)
+	}
+
+	err = repo.StateCleanup()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	state = repo.State()
+	if state != RepositoryStateNone {
+		t.Fatal("Incorrect repository state: ", state)
+	}
+}
diff --git a/commit.go b/commit.go
index 559a1bd..57e1a77 100644
--- a/commit.go
+++ b/commit.go
@@ -9,8 +9,6 @@
 
 import (
 	"runtime"
-	"time"
-	"unsafe"
 )
 
 // Commit
@@ -23,6 +21,10 @@
 	return C.GoString(C.git_commit_message(c.cast_ptr))
 }
 
+func (c Commit) Summary() string {
+	return C.GoString(C.git_commit_summary(c.cast_ptr))
+}
+
 func (c Commit) Tree() (*Tree, error) {
 	var ptr *C.git_tree
 
@@ -68,49 +70,3 @@
 func (c *Commit) ParentCount() uint {
 	return uint(C.git_commit_parentcount(c.cast_ptr))
 }
-
-// Signature
-
-type Signature struct {
-	Name  string
-	Email string
-	When  time.Time
-}
-
-func newSignatureFromC(sig *C.git_signature) *Signature {
-	// git stores minutes, go wants seconds
-	loc := time.FixedZone("", int(sig.when.offset)*60)
-	return &Signature{
-		C.GoString(sig.name),
-		C.GoString(sig.email),
-		time.Unix(int64(sig.when.time), 0).In(loc),
-	}
-}
-
-// the offset in mintes, which is what git wants
-func (v *Signature) Offset() int {
-	_, offset := v.When.Zone()
-	return offset / 60
-}
-
-func (sig *Signature) toC() *C.git_signature {
-
-	if sig == nil {
-		return nil
-	}
-
-	var out *C.git_signature
-
-	name := C.CString(sig.Name)
-	defer C.free(unsafe.Pointer(name))
-
-	email := C.CString(sig.Email)
-	defer C.free(unsafe.Pointer(email))
-
-	ret := C.git_signature_new(&out, name, email, C.git_time_t(sig.When.Unix()), C.int(sig.Offset()))
-	if ret < 0 {
-		return nil
-	}
-
-	return out
-}
diff --git a/git.go b/git.go
index 8e78710..9496d2d 100644
--- a/git.go
+++ b/git.go
@@ -3,6 +3,7 @@
 /*
 #include <git2.h>
 #include <git2/sys/openssl.h>
+#cgo pkg-config: libgit2
 */
 import "C"
 import (
diff --git a/git_test.go b/git_test.go
index 56adeed..b9cf0a9 100644
--- a/git_test.go
+++ b/git_test.go
@@ -57,6 +57,10 @@
 	return commitId, treeId
 }
 
+func pathInRepo(repo *Repository, name string) string {
+	return path.Join(path.Dir(path.Dir(repo.Path())), name)
+}
+
 func updateReadme(t *testing.T, repo *Repository, content string) (*Oid, *Oid) {
 	loc, err := time.LoadLocation("Europe/Berlin")
 	checkFatal(t, err)
@@ -67,7 +71,7 @@
 	}
 
 	tmpfile := "README"
-	err = ioutil.WriteFile(path.Join(path.Dir(path.Dir(repo.Path())), tmpfile), []byte(content), 0644)
+	err = ioutil.WriteFile(pathInRepo(repo, tmpfile), []byte(content), 0644)
 	checkFatal(t, err)
 
 	idx, err := repo.Index()
diff --git a/object.go b/object.go
index 7428e0f..20cee85 100644
--- a/object.go
+++ b/object.go
@@ -25,12 +25,12 @@
 }
 
 type gitObject struct {
-	ptr *C.git_object
+	ptr  *C.git_object
 	repo *Repository
 }
 
-func (t ObjectType) String() (string) {
-	switch (t) {
+func (t ObjectType) String() string {
+	switch t {
 	case ObjectAny:
 		return "Any"
 	case ObjectBad:
@@ -71,7 +71,7 @@
 
 func allocObject(cobj *C.git_object, repo *Repository) Object {
 	obj := gitObject{
-		ptr: cobj,
+		ptr:  cobj,
 		repo: repo,
 	}
 
diff --git a/odb.go b/odb.go
index 19bb71c..ba03860 100644
--- a/odb.go
+++ b/odb.go
@@ -94,7 +94,7 @@
 
 type foreachData struct {
 	callback OdbForEachCallback
-	err error
+	err      error
 }
 
 //export odbForEachCb
@@ -111,9 +111,9 @@
 }
 
 func (v *Odb) ForEach(callback OdbForEachCallback) error {
-	data := foreachData {
+	data := foreachData{
 		callback: callback,
-		err: nil,
+		err:      nil,
 	}
 
 	runtime.LockOSThread()
@@ -138,7 +138,7 @@
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
 
-	ret := C.git_odb_hash(oid.toC(), ptr, C.size_t(header.Len), C.git_otype(otype));
+	ret := C.git_odb_hash(oid.toC(), ptr, C.size_t(header.Len), C.git_otype(otype))
 	if ret < 0 {
 		return nil, MakeGitError(ret)
 	}
diff --git a/odb_test.go b/odb_test.go
index 14a3658..5e6b7ff 100644
--- a/odb_test.go
+++ b/odb_test.go
@@ -1,9 +1,9 @@
 package git
 
 import (
+	"errors"
 	"io"
 	"os"
-	"errors"
 	"testing"
 )
 
@@ -37,7 +37,7 @@
 
 func TestOdbHash(t *testing.T) {
 
-    repo := createTestRepo(t)
+	repo := createTestRepo(t)
 	defer os.RemoveAll(repo.Workdir())
 	_, _ = seedTestRepo(t, repo)
 
diff --git a/packbuilder.go b/packbuilder.go
index 7c94926..54a8390 100644
--- a/packbuilder.go
+++ b/packbuilder.go
@@ -128,7 +128,7 @@
 func (pb *Packbuilder) ForEach(callback PackbuilderForeachCallback) error {
 	data := packbuilderCbData{
 		callback: callback,
-		err: nil,
+		err:      nil,
 	}
 
 	runtime.LockOSThread()
diff --git a/reference.go b/reference.go
index 46436a6..ef12d0b 100644
--- a/reference.go
+++ b/reference.go
@@ -36,7 +36,10 @@
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
 
-	csig := sig.toC()
+	csig, err := sig.toC()
+	if err != nil {
+		return nil, err
+	}
 	defer C.free(unsafe.Pointer(csig))
 
 	var cmsg *C.char
@@ -61,7 +64,10 @@
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
 
-	csig := sig.toC()
+	csig, err := sig.toC()
+	if err != nil {
+		return nil, err
+	}
 	defer C.free(unsafe.Pointer(csig))
 
 	var cmsg *C.char
@@ -99,7 +105,10 @@
 	cname := C.CString(name)
 	defer C.free(unsafe.Pointer(cname))
 
-	csig := sig.toC()
+	csig, err := sig.toC()
+	if err != nil {
+		return nil, err
+	}
 	defer C.free(unsafe.Pointer(csig))
 
 	var cmsg *C.char
diff --git a/remote.go b/remote.go
index 2684c20..84750d3 100644
--- a/remote.go
+++ b/remote.go
@@ -604,7 +604,10 @@
 
 	var csig *C.git_signature = nil
 	if sig != nil {
-		csig = sig.toC()
+		csig, err := sig.toC()
+		if err != nil {
+			return err
+		}
 		defer C.free(unsafe.Pointer(csig))
 	}
 
@@ -696,7 +699,10 @@
 func (o *Remote) Push(refspecs []string, opts *PushOptions, sig *Signature, msg string) error {
 	var csig *C.git_signature = nil
 	if sig != nil {
-		csig = sig.toC()
+		csig, err := sig.toC()
+		if err != nil {
+			return err
+		}
 		defer C.free(unsafe.Pointer(csig))
 	}
 
diff --git a/repository.go b/repository.go
index 7760c3a..7fac277 100644
--- a/repository.go
+++ b/repository.go
@@ -210,7 +210,10 @@
 	cname := C.CString(refname)
 	defer C.free(unsafe.Pointer(cname))
 
-	csig := sig.toC()
+	csig, err := sig.toC()
+	if err != nil {
+		return err
+	}
 	defer C.free(unsafe.Pointer(csig))
 
 	var cmsg *C.char
@@ -230,7 +233,10 @@
 }
 
 func (v *Repository) SetHeadDetached(id *Oid, sig *Signature, msg string) error {
-	csig := sig.toC()
+	csig, err := sig.toC()
+	if err != nil {
+		return err
+	}
 	defer C.free(unsafe.Pointer(csig))
 
 	var cmsg *C.char
@@ -253,7 +259,10 @@
 	cname := C.CString(name)
 	defer C.free(unsafe.Pointer(cname))
 
-	csig := sig.toC()
+	csig, err := sig.toC()
+	if err != nil {
+		return nil, err
+	}
 	defer C.free(unsafe.Pointer(csig))
 
 	var cmsg *C.char
@@ -284,7 +293,10 @@
 	ctarget := C.CString(target)
 	defer C.free(unsafe.Pointer(ctarget))
 
-	csig := sig.toC()
+	csig, err := sig.toC()
+	if err != nil {
+		return nil, err
+	}
 	defer C.free(unsafe.Pointer(csig))
 
 	var cmsg *C.char
@@ -352,10 +364,16 @@
 		parentsarg = &cparents[0]
 	}
 
-	authorSig := author.toC()
+	authorSig, err := author.toC()
+	if err != nil {
+		return nil, err
+	}
 	defer C.git_signature_free(authorSig)
 
-	committerSig := committer.toC()
+	committerSig, err := committer.toC()
+	if err != nil {
+		return nil, err
+	}
 	defer C.git_signature_free(committerSig)
 
 	runtime.LockOSThread()
@@ -384,7 +402,10 @@
 	cmessage := C.CString(message)
 	defer C.free(unsafe.Pointer(cmessage))
 
-	taggerSig := tagger.toC()
+	taggerSig, err := tagger.toC()
+	if err != nil {
+		return nil, err
+	}
 	defer C.git_signature_free(taggerSig)
 
 	ctarget := commit.gitObject.ptr
@@ -546,10 +567,16 @@
 		defer C.free(unsafe.Pointer(cref))
 	}
 
-	authorSig := author.toC()
+	authorSig, err := author.toC()
+	if err != nil {
+		return nil, err
+	}
 	defer C.git_signature_free(authorSig)
 
-	committerSig := committer.toC()
+	committerSig, err := committer.toC()
+	if err != nil {
+		return nil, err
+	}
 	defer C.git_signature_free(committerSig)
 
 	cnote := C.CString(note)
@@ -601,10 +628,16 @@
 		defer C.free(unsafe.Pointer(cref))
 	}
 
-	authorSig := author.toC()
+	authorSig, err := author.toC()
+	if err != nil {
+		return err
+	}
 	defer C.git_signature_free(authorSig)
 
-	committerSig := committer.toC()
+	committerSig, err := committer.toC()
+	if err != nil {
+		return err
+	}
 	defer C.git_signature_free(committerSig)
 
 	runtime.LockOSThread()
@@ -630,3 +663,36 @@
 
 	return C.GoString(ptr), nil
 }
+
+type RepositoryState int
+
+const (
+	RepositoryStateNone                 RepositoryState = C.GIT_REPOSITORY_STATE_NONE
+	RepositoryStateMerge                RepositoryState = C.GIT_REPOSITORY_STATE_MERGE
+	RepositoryStateRevert               RepositoryState = C.GIT_REPOSITORY_STATE_REVERT
+	RepositoryStateCherrypick           RepositoryState = C.GIT_REPOSITORY_STATE_CHERRYPICK
+	RepositoryStateBisect               RepositoryState = C.GIT_REPOSITORY_STATE_BISECT
+	RepositoryStateRebase               RepositoryState = C.GIT_REPOSITORY_STATE_REBASE
+	RepositoryStateRebaseInteractive    RepositoryState = C.GIT_REPOSITORY_STATE_REBASE_INTERACTIVE
+	RepositoryStateRebaseMerge          RepositoryState = C.GIT_REPOSITORY_STATE_REBASE_MERGE
+	RepositoryStateApplyMailbox         RepositoryState = C.GIT_REPOSITORY_STATE_APPLY_MAILBOX
+	RepositoryStateApplyMailboxOrRebase RepositoryState = C.GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE
+)
+
+func (r *Repository) State() RepositoryState {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	return RepositoryState(C.git_repository_state(r.ptr))
+}
+
+func (r *Repository) StateCleanup() error {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	cErr := C.git_repository_state_cleanup(r.ptr)
+	if cErr < 0 {
+		return MakeGitError(cErr)
+	}
+	return nil
+}
diff --git a/script/build-libgit2-static.sh b/script/build-libgit2-static.sh
deleted file mode 100755
index 5723721..0000000
--- a/script/build-libgit2-static.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/sh
-
-set -ex
-
-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 .
diff --git a/script/with-static.sh b/script/with-static.sh
deleted file mode 100755
index 3f60e31..0000000
--- a/script/with-static.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-
-set -ex
-
-export BUILD="$PWD/vendor/libgit2/build"
-export PCFILE="$BUILD/libgit2.pc"
-
-FLAGS=$(pkg-config --static --libs $PCFILE) || exit 1
-export CGO_LDFLAGS="$BUILD/libgit2.a -L$BUILD ${FLAGS}"
-export CGO_CFLAGS="-I$PWD/vendor/libgit2/include"
-
-$@
diff --git a/signature.go b/signature.go
new file mode 100644
index 0000000..0518387
--- /dev/null
+++ b/signature.go
@@ -0,0 +1,73 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import (
+	"runtime"
+	"time"
+	"unsafe"
+)
+
+type Signature struct {
+	Name  string
+	Email string
+	When  time.Time
+}
+
+func newSignatureFromC(sig *C.git_signature) *Signature {
+	// git stores minutes, go wants seconds
+	loc := time.FixedZone("", int(sig.when.offset)*60)
+	return &Signature{
+		C.GoString(sig.name),
+		C.GoString(sig.email),
+		time.Unix(int64(sig.when.time), 0).In(loc),
+	}
+}
+
+// the offset in mintes, which is what git wants
+func (v *Signature) Offset() int {
+	_, offset := v.When.Zone()
+	return offset / 60
+}
+
+func (sig *Signature) toC() (*C.git_signature, error) {
+	if sig == nil {
+		return nil, nil
+	}
+
+	var out *C.git_signature
+
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	name := C.CString(sig.Name)
+	defer C.free(unsafe.Pointer(name))
+
+	email := C.CString(sig.Email)
+	defer C.free(unsafe.Pointer(email))
+
+	ret := C.git_signature_new(&out, name, email, C.git_time_t(sig.When.Unix()), C.int(sig.Offset()))
+	if ret < 0 {
+		return nil, MakeGitError(ret)
+	}
+
+	return out, nil
+}
+
+func (repo *Repository) DefaultSignature() (*Signature, error) {
+	var out *C.git_signature
+
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	cErr := C.git_signature_default(&out, repo.ptr)
+	if cErr < 0 {
+		return nil, MakeGitError(cErr)
+	}
+
+	defer C.git_signature_free(out)
+
+	return newSignatureFromC(out), nil
+}
diff --git a/status.go b/status.go
index c849aca..3f5a06d 100644
--- a/status.go
+++ b/status.go
@@ -45,7 +45,7 @@
 		indexToWorkdir = diffDeltaFromC(statusEntry.index_to_workdir)
 	}
 
-	return StatusEntry {
+	return StatusEntry{
 		Status:         Status(statusEntry.status),
 		HeadToIndex:    headToIndex,
 		IndexToWorkdir: indexToWorkdir,
@@ -96,20 +96,20 @@
 type StatusOpt int
 
 const (
-	StatusOptIncludeUntracked           StatusOpt = C.GIT_STATUS_OPT_INCLUDE_UNTRACKED
-	StatusOptIncludeIgnored             StatusOpt = C.GIT_STATUS_OPT_INCLUDE_IGNORED
-	StatusOptIncludeUnmodified          StatusOpt = C.GIT_STATUS_OPT_INCLUDE_UNMODIFIED
-	StatusOptExcludeSubmodules          StatusOpt = C.GIT_STATUS_OPT_EXCLUDE_SUBMODULES
-	StatusOptRecurseUntrackedDirs       StatusOpt = C.GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS
-	StatusOptDisablePathspecMatch       StatusOpt = C.GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH
-	StatusOptRecurseIgnoredDirs         StatusOpt = C.GIT_STATUS_OPT_RECURSE_IGNORED_DIRS
-	StatusOptRenamesHeadToIndex         StatusOpt = C.GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
-	StatusOptRenamesIndexToWorkdir      StatusOpt = C.GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
-	StatusOptSortCaseSensitively        StatusOpt = C.GIT_STATUS_OPT_SORT_CASE_SENSITIVELY
-	StatusOptSortCaseInsensitively      StatusOpt = C.GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY
-	StatusOptRenamesFromRewrites        StatusOpt = C.GIT_STATUS_OPT_RENAMES_FROM_REWRITES
-	StatusOptNoRefresh                  StatusOpt = C.GIT_STATUS_OPT_NO_REFRESH
-	StatusOptUpdateIndex                StatusOpt = C.GIT_STATUS_OPT_UPDATE_INDEX
+	StatusOptIncludeUntracked      StatusOpt = C.GIT_STATUS_OPT_INCLUDE_UNTRACKED
+	StatusOptIncludeIgnored        StatusOpt = C.GIT_STATUS_OPT_INCLUDE_IGNORED
+	StatusOptIncludeUnmodified     StatusOpt = C.GIT_STATUS_OPT_INCLUDE_UNMODIFIED
+	StatusOptExcludeSubmodules     StatusOpt = C.GIT_STATUS_OPT_EXCLUDE_SUBMODULES
+	StatusOptRecurseUntrackedDirs  StatusOpt = C.GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS
+	StatusOptDisablePathspecMatch  StatusOpt = C.GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH
+	StatusOptRecurseIgnoredDirs    StatusOpt = C.GIT_STATUS_OPT_RECURSE_IGNORED_DIRS
+	StatusOptRenamesHeadToIndex    StatusOpt = C.GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
+	StatusOptRenamesIndexToWorkdir StatusOpt = C.GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
+	StatusOptSortCaseSensitively   StatusOpt = C.GIT_STATUS_OPT_SORT_CASE_SENSITIVELY
+	StatusOptSortCaseInsensitively StatusOpt = C.GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY
+	StatusOptRenamesFromRewrites   StatusOpt = C.GIT_STATUS_OPT_RENAMES_FROM_REWRITES
+	StatusOptNoRefresh             StatusOpt = C.GIT_STATUS_OPT_NO_REFRESH
+	StatusOptUpdateIndex           StatusOpt = C.GIT_STATUS_OPT_UPDATE_INDEX
 )
 
 type StatusShow int
@@ -173,7 +173,6 @@
 	return newStatusListFromC(ptr), nil
 }
 
-
 func (v *Repository) StatusFile(path string) (Status, error) {
 	var statusFlags C.uint
 	cPath := C.CString(path)
diff --git a/status_test.go b/status_test.go
index 4be4824..d18fca1 100644
--- a/status_test.go
+++ b/status_test.go
@@ -12,6 +12,11 @@
 	defer repo.Free()
 	defer os.RemoveAll(repo.Workdir())
 
+	state := repo.State()
+	if state != RepositoryStateNone {
+		t.Fatal("Incorrect repository state: ", state)
+	}
+
 	err := ioutil.WriteFile(path.Join(path.Dir(repo.Workdir()), "hello.txt"), []byte("Hello, World"), 0644)
 	checkFatal(t, err)
 
diff --git a/submodule.go b/submodule.go
index 6923c61..7c6c922 100644
--- a/submodule.go
+++ b/submodule.go
@@ -318,7 +318,10 @@
 
 func (sub *Submodule) Update(init bool, opts *SubmoduleUpdateOptions) error {
 	var copts C.git_submodule_update_options
-	populateSubmoduleUpdateOptions(&copts, opts)
+	err := populateSubmoduleUpdateOptions(&copts, opts)
+	if err != nil {
+		return err
+	}
 
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
@@ -331,15 +334,22 @@
 	return nil
 }
 
-func populateSubmoduleUpdateOptions(ptr *C.git_submodule_update_options, opts *SubmoduleUpdateOptions) {
+func populateSubmoduleUpdateOptions(ptr *C.git_submodule_update_options, opts *SubmoduleUpdateOptions) error {
 	C.git_submodule_update_init_options(ptr, C.GIT_SUBMODULE_UPDATE_OPTIONS_VERSION)
 
 	if opts == nil {
-		return
+		return nil
 	}
 
 	populateCheckoutOpts(&ptr.checkout_opts, opts.CheckoutOpts)
 	populateRemoteCallbacks(&ptr.remote_callbacks, opts.RemoteCallbacks)
 	ptr.clone_checkout_strategy = C.uint(opts.CloneCheckoutStrategy)
-	ptr.signature = opts.Signature.toC()
+
+	sig, err := opts.Signature.toC()
+	if err != nil {
+		return err
+	}
+	ptr.signature = sig
+
+	return nil
 }
diff --git a/tag_test.go b/tag_test.go
index 5ebd53d..126cf6e 100644
--- a/tag_test.go
+++ b/tag_test.go
@@ -2,8 +2,8 @@
 
 import (
 	"os"
-	"time"
 	"testing"
+	"time"
 )
 
 func TestCreateTag(t *testing.T) {
diff --git a/vendor/libgit2 b/vendor/libgit2
deleted file mode 160000
index 04bdd97..0000000
--- a/vendor/libgit2
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 04bdd97f2b63793a8720fd19007911e946ba3c55