Merge remote-tracking branch 'upstream/master' into next
diff --git a/README.md b/README.md
index a5e6100..315032f 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
 Installing
 ----------
 
-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 manaager and then install git2go as usual.
+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 manager 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.
 
diff --git a/blob.go b/blob.go
index 16ec183..1a86e60 100644
--- a/blob.go
+++ b/blob.go
@@ -84,7 +84,7 @@
 
 	var chintPath *C.char = nil
 	if len(hintPath) > 0 {
-		C.CString(hintPath)
+		chintPath = C.CString(hintPath)
 		defer C.free(unsafe.Pointer(chintPath))
 	}
 	oid := C.git_oid{}
diff --git a/checkout.go b/checkout.go
index ce2f469..a2e312b 100644
--- a/checkout.go
+++ b/checkout.go
@@ -45,6 +45,7 @@
 	FileOpenFlags   int              // Default is O_CREAT | O_TRUNC | O_WRONLY
 	TargetDirectory string           // Alternative checkout path to workdir
 	Paths           []string
+	Baseline        *Tree
 }
 
 func checkoutOptionsFromC(c *C.git_checkout_options) CheckoutOpts {
@@ -90,6 +91,10 @@
 		ptr.paths.count = C.size_t(len(opts.Paths))
 	}
 
+	if opts.Baseline != nil {
+		ptr.baseline = opts.Baseline.cast_ptr
+	}
+
 	return ptr
 }
 
diff --git a/config.go b/config.go
index 73365c8..7408fbc 100644
--- a/config.go
+++ b/config.go
@@ -118,18 +118,20 @@
 }
 
 func (c *Config) LookupString(name string) (string, error) {
-	var ptr *C.char
 	cname := C.CString(name)
 	defer C.free(unsafe.Pointer(cname))
 
+	valBuf := C.git_buf{}
+
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
 
-	if ret := C.git_config_get_string(&ptr, c.ptr, cname); ret < 0 {
+	if ret := C.git_config_get_string_buf(&valBuf, c.ptr, cname); ret < 0 {
 		return "", MakeGitError(ret)
 	}
+	defer C.git_buf_free(&valBuf)
 
-	return C.GoString(ptr), nil
+	return C.GoString(valBuf.ptr), nil
 }
 
 func (c *Config) LookupBool(name string) (bool, error) {
diff --git a/config_test.go b/config_test.go
new file mode 100644
index 0000000..fea8d8a
--- /dev/null
+++ b/config_test.go
@@ -0,0 +1,108 @@
+package git
+
+import (
+	"os"
+	"testing"
+)
+
+var tempConfig = "./temp.gitconfig"
+
+func setupConfig() (*Config, error) {
+	var (
+		c   *Config
+		err error
+	)
+
+	c, err = OpenOndisk(nil, tempConfig)
+	if err != nil {
+		return nil, err
+	}
+
+	err = c.SetString("foo.bar", "baz")
+	if err != nil {
+		return nil, err
+	}
+	err = c.SetBool("foo.bool", true)
+	if err != nil {
+		return nil, err
+	}
+	err = c.SetInt32("foo.int32", 32)
+	if err != nil {
+		return nil, err
+	}
+	err = c.SetInt64("foo.int64", 64)
+	if err != nil {
+		return nil, err
+	}
+
+	return c, err
+}
+
+func cleanupConfig() {
+	os.Remove(tempConfig)
+}
+
+type TestRunner func(*Config, *testing.T)
+
+var tests = []TestRunner{
+	// LookupString
+	func(c *Config, t *testing.T) {
+		val, err := c.LookupString("foo.bar")
+		if err != nil {
+			t.Errorf("Got LookupString error: '%v', expected none\n", err)
+		}
+		if val != "baz" {
+			t.Errorf("Got '%s' from LookupString, expected 'bar'\n", val)
+		}
+	},
+	// LookupBool
+	func(c *Config, t *testing.T) {
+		val, err := c.LookupBool("foo.bool")
+		if err != nil {
+			t.Errorf("Got LookupBool error: '%v', expected none\n", err)
+		}
+		if !val {
+			t.Errorf("Got %b from LookupBool, expected 'false'\n", val)
+		}
+	},
+	// LookupInt32
+	func(c *Config, t *testing.T) {
+		val, err := c.LookupInt32("foo.int32")
+		if err != nil {
+			t.Errorf("Got LookupInt32 error: '%v', expected none\n", err)
+		}
+		if val != 32 {
+			t.Errorf("Got %v, expected 32\n", val)
+		}
+	},
+	// LookupInt64
+	func(c *Config, t *testing.T) {
+		val, err := c.LookupInt64("foo.int64")
+		if err != nil {
+			t.Errorf("Got LookupInt64 error: '%v', expected none\n", err)
+		}
+		if val != 64 {
+			t.Errorf("Got %v, expected 64\n", val)
+		}
+	},
+}
+
+func TestConfigLookups(t *testing.T) {
+	var (
+		err error
+		c   *Config
+	)
+
+	c, err = setupConfig()
+	defer cleanupConfig()
+
+	if err != nil {
+		t.Errorf("Setup error: '%v'. Expected none\n", err)
+		return
+	}
+	defer c.Free()
+
+	for _, test := range tests {
+		test(c, t)
+	}
+}
diff --git a/index.go b/index.go
index 16e63a1..ae94864 100644
--- a/index.go
+++ b/index.go
@@ -115,7 +115,7 @@
 		return nil, MakeGitError(err)
 	}
 
-	return &Index{ptr: ptr}, nil
+	return newIndexFromC(ptr), nil
 }
 
 // OpenIndex creates a new index at the given path. If the file does
@@ -133,7 +133,7 @@
 		return nil, MakeGitError(err)
 	}
 
-	return &Index{ptr: ptr}, nil
+	return newIndexFromC(ptr), nil
 }
 
 // Path returns the index' path on disk or an empty string if it
diff --git a/merge.go b/merge.go
index 53d5a72..0b0a8f1 100644
--- a/merge.go
+++ b/merge.go
@@ -185,6 +185,9 @@
 	MergePreferenceFastForwardOnly MergePreference = C.GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY
 )
 
+// MergeAnalysis returns the possible actions which could be taken by
+// a 'git-merge' command. There may be multiple answers, so the first
+// return value is a bitmask of MergeAnalysis values.
 func (r *Repository) MergeAnalysis(theirHeads []*AnnotatedCommit) (MergeAnalysis, MergePreference, error) {
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
diff --git a/odb.go b/odb.go
index ff8b739..d881f63 100644
--- a/odb.go
+++ b/odb.go
@@ -8,7 +8,6 @@
 */
 import "C"
 import (
-	"fmt"
 	"reflect"
 	"runtime"
 	"unsafe"
@@ -55,6 +54,21 @@
 	return nil
 }
 
+func (v *Odb) ReadHeader(oid *Oid) (uint64, ObjectType, error) {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+	
+	var sz C.size_t
+	var cotype C.git_otype 
+
+	ret := C.git_odb_read_header(&sz, &cotype, v.ptr, oid.toC())
+	if ret < 0 {
+		return 0, C.GIT_OBJ_BAD, MakeGitError(ret)
+	}
+
+	return uint64(sz), ObjectType(cotype), nil
+}
+	
 func (v *Odb) Exists(oid *Oid) bool {
 	ret := C.git_odb_exists(v.ptr, oid.toC())
 	return ret != 0
@@ -107,9 +121,7 @@
 	}
 
 	err := data.callback(newOidFromC(id))
-	fmt.Println("err %v", err)
 	if err != nil {
-		fmt.Println("returning EUSER")
 		data.err = err
 		return C.GIT_EUSER
 	}
@@ -130,7 +142,6 @@
 	defer pointerHandles.Untrack(handle)
 
 	ret := C._go_git_odb_foreach(v.ptr, handle)
-	fmt.Println("ret %v", ret)
 	if ret == C.GIT_EUSER {
 		return data.err
 	} else if ret < 0 {
diff --git a/odb_test.go b/odb_test.go
index 0d765b9..dfd2ad0 100644
--- a/odb_test.go
+++ b/odb_test.go
@@ -6,6 +6,34 @@
 	"testing"
 )
 
+func TestOdbReadHeader(t *testing.T) {
+	repo := createTestRepo(t)
+	defer cleanupTestRepo(t, repo)
+
+	_, _ = seedTestRepo(t, repo)
+	odb, err := repo.Odb()
+	if err != nil {
+		t.Fatalf("Odb: %v", err)
+	}
+	data := []byte("hello")
+	id, err := odb.Write(data, ObjectBlob)
+	if err != nil {
+		t.Fatalf("odb.Write: %v", err)
+	}
+
+	sz, typ, err := odb.ReadHeader(id)
+	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)
+	}
+}
+
 func TestOdbStream(t *testing.T) {
 	repo := createTestRepo(t)
 	defer cleanupTestRepo(t, repo)
diff --git a/remote.go b/remote.go
index a216513..8a57280 100644
--- a/remote.go
+++ b/remote.go
@@ -637,15 +637,17 @@
 	crefspecs.strings = makeCStringsFromStrings(refspecs)
 	defer freeStrarray(&crefspecs)
 
-	var coptions C.git_fetch_options
-	populateFetchOptions(&coptions, opts)
+	coptions := (*C.git_fetch_options)(C.calloc(1, C.size_t(unsafe.Sizeof(C.git_fetch_options{}))))
+	defer C.free(unsafe.Pointer(coptions))
+
+	populateFetchOptions(coptions, opts)
 	defer untrackCalbacksPayload(&coptions.callbacks)
 	defer freeStrarray(&coptions.custom_headers)
 
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
 
-	ret := C.git_remote_fetch(o.ptr, &crefspecs, &coptions, cmsg)
+	ret := C.git_remote_fetch(o.ptr, &crefspecs, coptions, cmsg)
 	if ret < 0 {
 		return MakeGitError(ret)
 	}
@@ -737,15 +739,17 @@
 	crefspecs.strings = makeCStringsFromStrings(refspecs)
 	defer freeStrarray(&crefspecs)
 
-	var coptions C.git_push_options
-	populatePushOptions(&coptions, opts)
+	coptions := (*C.git_push_options)(C.calloc(1, C.size_t(unsafe.Sizeof(C.git_push_options{}))))
+	defer C.free(unsafe.Pointer(coptions))
+
+	populatePushOptions(coptions, opts)
 	defer untrackCalbacksPayload(&coptions.callbacks)
 	defer freeStrarray(&coptions.custom_headers)
 
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
 
-	ret := C.git_remote_push(o.ptr, &crefspecs, &coptions)
+	ret := C.git_remote_push(o.ptr, &crefspecs, coptions)
 	if ret < 0 {
 		return MakeGitError(ret)
 	}
diff --git a/repository.go b/repository.go
index 398f91a..77e9f9c 100644
--- a/repository.go
+++ b/repository.go
@@ -447,3 +447,24 @@
 	}
 	return nil
 }
+func (r *Repository) AddGitIgnoreRules(rules string) error {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	crules := C.CString(rules)
+	defer C.free(unsafe.Pointer(crules))
+	if ret := C.git_ignore_add_rule(r.ptr, crules); ret < 0 {
+		return MakeGitError(ret)
+	}
+	return nil
+}
+
+func (r *Repository) ClearGitIgnoreRules() error {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	if ret := C.git_ignore_clear_internal_rules(r.ptr); ret < 0 {
+		return MakeGitError(ret)
+	}
+	return nil
+}
diff --git a/walk.go b/walk.go
index c314f60..60e618d 100644
--- a/walk.go
+++ b/walk.go
@@ -194,6 +194,10 @@
 	return nil
 }
 
+func (v *RevWalk) SimplifyFirstParent() {
+	C.git_revwalk_simplify_first_parent(v.ptr)
+}
+
 func (v *RevWalk) Sorting(sm SortType) {
 	C.git_revwalk_sorting(v.ptr, C.uint(sm))
 }