Merge branch 'next'
diff --git a/blame.go b/blame.go
index c24c934..b07d6bc 100644
--- a/blame.go
+++ b/blame.go
@@ -58,8 +58,8 @@
 			version:              C.GIT_BLAME_OPTIONS_VERSION,
 			flags:                C.uint32_t(opts.Flags),
 			min_match_characters: C.uint16_t(opts.MinMatchCharacters),
-			min_line:             C.uint32_t(opts.MinLine),
-			max_line:             C.uint32_t(opts.MaxLine),
+			min_line:             C.size_t(opts.MinLine),
+			max_line:             C.size_t(opts.MaxLine),
 		}
 		if opts.NewestCommit != nil {
 			copts.newest_commit = *opts.NewestCommit.toC()
@@ -100,7 +100,7 @@
 }
 
 func (blame *Blame) HunkByLine(lineno int) (BlameHunk, error) {
-	ptr := C.git_blame_get_hunk_byline(blame.ptr, C.uint32_t(lineno))
+	ptr := C.git_blame_get_hunk_byline(blame.ptr, C.size_t(lineno))
 	if ptr == nil {
 		return BlameHunk{}, ErrInvalid
 	}
diff --git a/blob.go b/blob.go
index 382bb9e..1a86e60 100644
--- a/blob.go
+++ b/blob.go
@@ -18,7 +18,7 @@
 )
 
 type Blob struct {
-	gitObject
+	Object
 	cast_ptr *C.git_blob
 }
 
diff --git a/commit.go b/commit.go
index 52f7c01..6830da3 100644
--- a/commit.go
+++ b/commit.go
@@ -14,7 +14,7 @@
 
 // Commit
 type Commit struct {
-	gitObject
+	Object
 	cast_ptr *C.git_commit
 }
 
@@ -37,7 +37,7 @@
 		return nil, MakeGitError(err)
 	}
 
-	return allocObject((*C.git_object)(ptr), c.repo).(*Tree), nil
+	return allocTree(ptr, c.repo), nil
 }
 
 func (c Commit) TreeId() *Oid {
@@ -61,7 +61,7 @@
 		return nil
 	}
 
-	return allocObject((*C.git_object)(cobj), c.repo).(*Commit)
+	return allocCommit(cobj, c.repo)
 }
 
 func (c *Commit) ParentId(n uint) *Oid {
diff --git a/config.go b/config.go
index c4c4028..7408fbc 100644
--- a/config.go
+++ b/config.go
@@ -12,6 +12,9 @@
 type ConfigLevel int
 
 const (
+	// System-wide on Windows, for compatibility with portable git
+	ConfigLevelProgramdata ConfigLevel = C.GIT_CONFIG_LEVEL_PROGRAMDATA
+
 	// System-wide configuration file; /etc/gitconfig on Linux systems
 	ConfigLevelSystem ConfigLevel = C.GIT_CONFIG_LEVEL_SYSTEM
 
@@ -412,3 +415,21 @@
 
 	return C.GoString(buf.ptr), nil
 }
+
+// ConfigFindProgramdata locate the path to the configuration file in ProgramData.
+//
+// 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)
+
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	ret := C.git_config_find_programdata(&buf)
+	if ret < 0 {
+		return "", MakeGitError(ret)
+	}
+
+	return C.GoString(buf.ptr), nil
+}
diff --git a/describe.go b/describe.go
index c6f9a79..d75dbcb 100644
--- a/describe.go
+++ b/describe.go
@@ -127,7 +127,7 @@
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
 
-	ecode := C.git_describe_commit(&resultPtr, c.gitObject.ptr, cDescribeOpts)
+	ecode := C.git_describe_commit(&resultPtr, c.ptr, cDescribeOpts)
 	if ecode < 0 {
 		return nil, MakeGitError(ecode)
 	}
diff --git a/diff.go b/diff.go
index de56374..565fcee 100644
--- a/diff.go
+++ b/diff.go
@@ -550,7 +550,7 @@
 
 		if opts.NotifyCallback != nil {
 			C._go_git_setup_diff_notify_callbacks(copts)
-			copts.notify_payload = pointerHandles.Track(notifyData)
+			copts.payload = pointerHandles.Track(notifyData)
 		}
 	}
 	return
@@ -562,8 +562,8 @@
 		freeStrarray(&cpathspec)
 		C.free(unsafe.Pointer(copts.old_prefix))
 		C.free(unsafe.Pointer(copts.new_prefix))
-		if copts.notify_payload != nil {
-			pointerHandles.Untrack(copts.notify_payload)
+		if copts.payload != nil {
+			pointerHandles.Untrack(copts.payload)
 		}
 	}
 }
diff --git a/git.go b/git.go
index 7c7f99c..45b01d5 100644
--- a/git.go
+++ b/git.go
@@ -53,6 +53,7 @@
 
 	// No error
 	ErrOk ErrorCode = C.GIT_OK
+
 	// Generic error
 	ErrGeneric ErrorCode = C.GIT_ERROR
 	// Requested object could not be found
@@ -63,10 +64,12 @@
 	ErrAmbigious ErrorCode = C.GIT_EAMBIGUOUS
 	// Output buffer too short to hold data
 	ErrBuffs ErrorCode = C.GIT_EBUFS
+
 	// GIT_EUSER is a special error that is never generated by libgit2
 	// code.  You can return it from a callback (e.g to stop an iteration)
 	// to know that it was generated by the callback and not by libgit2.
 	ErrUser ErrorCode = C.GIT_EUSER
+
 	// Operation not allowed on bare repository
 	ErrBareRepo ErrorCode = C.GIT_EBAREREPO
 	// HEAD refers to branch with no commits
@@ -83,12 +86,27 @@
 	ErrLocked ErrorCode = C.GIT_ELOCKED
 	// Reference value does not match expected
 	ErrModified ErrorCode = C.GIT_EMODIFIED
+	// Authentication failed
+	ErrAuth ErrorCode = C.GIT_EAUTH
+	// Server certificate is invalid
+	ErrCertificate ErrorCode = C.GIT_ECERTIFICATE
+	// Patch/merge has already been applied
+	ErrApplied ErrorCode = C.GIT_EAPPLIED
+	// The requested peel operation is not possible
+	ErrPeel ErrorCode = C.GIT_EPEEL
+	// Unexpected EOF
+	ErrEOF ErrorCode = C.GIT_EEOF
+	// Uncommitted changes in index prevented operation
+	ErrUncommitted ErrorCode = C.GIT_EUNCOMMITTED
+	// The operation is not valid for a directory
+	ErrDirectory ErrorCode = C.GIT_EDIRECTORY
+	// A merge conflict exists and cannot continue
+	ErrMergeConflict ErrorCode = C.GIT_EMERGECONFLICT
+
 	// Internal only
 	ErrPassthrough ErrorCode = C.GIT_PASSTHROUGH
 	// Signals end of iteration with iterator
 	ErrIterOver ErrorCode = C.GIT_ITEROVER
-	// Authentication failed
-	ErrAuth ErrorCode = C.GIT_EAUTH
 )
 
 var (
diff --git a/ignore.go b/ignore.go
new file mode 100644
index 0000000..6b12348
--- /dev/null
+++ b/ignore.go
@@ -0,0 +1,51 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import (
+	"runtime"
+	"unsafe"
+)
+
+func (v *Repository) AddIgnoreRule(rules string) error {
+	crules := C.CString(rules)
+	defer C.free(unsafe.Pointer(crules))
+
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	ret := C.git_ignore_add_rule(v.ptr, crules)
+	if ret < 0 {
+		return MakeGitError(ret)
+	}
+	return nil
+}
+
+func (v *Repository) ClearInternalIgnoreRules() error {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	ret := C.git_ignore_clear_internal_rules(v.ptr)
+	if ret < 0 {
+		return MakeGitError(ret)
+	}
+	return nil
+}
+
+func (v *Repository) IsPathIgnored(path string) (bool, error) {
+	var ignored C.int
+
+	cpath := C.CString(path)
+	defer C.free(unsafe.Pointer(cpath))
+
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	ret := C.git_ignore_path_is_ignored(&ignored, v.ptr, cpath)
+	if ret < 0 {
+		return false, MakeGitError(ret)
+	}
+	return ignored == 1, nil
+}
diff --git a/index.go b/index.go
index 1eb5e9d..ae94864 100644
--- a/index.go
+++ b/index.go
@@ -26,6 +26,24 @@
 	IndexAddCheckPathspec        IndexAddOpts = C.GIT_INDEX_ADD_CHECK_PATHSPEC
 )
 
+type IndexStageOpts int
+
+const (
+	// IndexStageAny matches any index stage.
+	//
+	// Some index APIs take a stage to match; pass this value to match
+	// any entry matching the path regardless of stage.
+	IndexStageAny IndexStageOpts = C.GIT_INDEX_STAGE_ANY
+	// IndexStageNormal is a normal staged file in the index.
+	IndexStageNormal IndexStageOpts = C.GIT_INDEX_STAGE_NORMAL
+	// IndexStageAncestor is the ancestor side of a conflict.
+	IndexStageAncestor IndexStageOpts = C.GIT_INDEX_STAGE_ANCESTOR
+	// IndexStageOurs is the "ours" side of a conflict.
+	IndexStageOurs IndexStageOpts = C.GIT_INDEX_STAGE_OURS
+	// IndexStageTheirs is the "theirs" side of a conflict.
+	IndexStageTheirs IndexStageOpts = C.GIT_INDEX_STAGE_THEIRS
+)
+
 type Index struct {
 	ptr *C.git_index
 }
@@ -51,8 +69,8 @@
 		return nil
 	}
 	return &IndexEntry{
-		IndexTime { int32(entry.ctime.seconds), uint32(entry.ctime.nanoseconds) },
-		IndexTime { int32(entry.mtime.seconds), uint32(entry.mtime.nanoseconds) },
+		IndexTime{int32(entry.ctime.seconds), uint32(entry.ctime.nanoseconds)},
+		IndexTime{int32(entry.mtime.seconds), uint32(entry.mtime.nanoseconds)},
 		Filemode(entry.mode),
 		uint32(entry.uid),
 		uint32(entry.gid),
@@ -280,7 +298,7 @@
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
 
-	ret := C.git_index_read_tree(v.ptr, tree.cast_ptr);
+	ret := C.git_index_read_tree(v.ptr, tree.cast_ptr)
 	if ret < 0 {
 		return MakeGitError(ret)
 	}
@@ -331,6 +349,50 @@
 	return newIndexEntryFromC(centry), nil
 }
 
+func (v *Index) EntryByPath(path string, stage int) (*IndexEntry, error) {
+	cpath := C.CString(path)
+	defer C.free(unsafe.Pointer(cpath))
+
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	centry := C.git_index_get_bypath(v.ptr, cpath, C.int(stage))
+	if centry == nil {
+		return nil, MakeGitError(C.GIT_ENOTFOUND)
+	}
+	return newIndexEntryFromC(centry), nil
+}
+
+func (v *Index) Find(path string) (uint, error) {
+	cpath := C.CString(path)
+	defer C.free(unsafe.Pointer(cpath))
+
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	var pos C.size_t
+	ret := C.git_index_find(&pos, v.ptr, cpath)
+	if ret < 0 {
+		return uint(0), MakeGitError(ret)
+	}
+	return uint(pos), nil
+}
+
+func (v *Index) FindPrefix(prefix string) (uint, error) {
+	cprefix := C.CString(prefix)
+	defer C.free(unsafe.Pointer(cprefix))
+
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	var pos C.size_t
+	ret := C.git_index_find_prefix(&pos, v.ptr, cprefix)
+	if ret < 0 {
+		return uint(0), MakeGitError(ret)
+	}
+	return uint(pos), nil
+}
+
 func (v *Index) HasConflicts() bool {
 	return C.git_index_has_conflicts(v.ptr) != 0
 }
diff --git a/index_test.go b/index_test.go
index 7c65f4f..5f6b375 100644
--- a/index_test.go
+++ b/index_test.go
@@ -32,10 +32,11 @@
 	ref, err := repo.Head()
 	checkFatal(t, err)
 
-	obj, err := ref.Peel(ObjectTree);
+	obj, err := ref.Peel(ObjectTree)
 	checkFatal(t, err)
 
-	tree := obj.(*Tree)
+	tree, err := obj.AsTree()
+	checkFatal(t, err)
 
 	idx, err := NewIndex()
 	checkFatal(t, err)
diff --git a/merge.go b/merge.go
index 756c792..b3fd818 100644
--- a/merge.go
+++ b/merge.go
@@ -82,12 +82,19 @@
 type MergeTreeFlag int
 
 const (
-	MergeTreeFindRenames MergeTreeFlag = C.GIT_MERGE_TREE_FIND_RENAMES
+	// Detect renames that occur between the common ancestor and the "ours"
+	// side or the common ancestor and the "theirs" side.  This will enable
+	// the ability to merge between a modified and renamed file.
+	MergeTreeFindRenames MergeTreeFlag = C.GIT_MERGE_FIND_RENAMES
+	// If a conflict occurs, exit immediately instead of attempting to
+	// continue resolving conflicts.  The merge operation will fail with
+	// GIT_EMERGECONFLICT and no index will be returned.
+	MergeTreeFailOnConflict MergeTreeFlag = C.GIT_MERGE_FAIL_ON_CONFLICT
 )
 
 type MergeOptions struct {
-	Version     uint
-	TreeFlags   MergeTreeFlag
+	Version   uint
+	TreeFlags MergeTreeFlag
 
 	RenameThreshold uint
 	TargetLimit     uint
@@ -99,7 +106,7 @@
 func mergeOptionsFromC(opts *C.git_merge_options) MergeOptions {
 	return MergeOptions{
 		Version:         uint(opts.version),
-		TreeFlags:           MergeTreeFlag(opts.tree_flags),
+		TreeFlags:       MergeTreeFlag(opts.flags),
 		RenameThreshold: uint(opts.rename_threshold),
 		TargetLimit:     uint(opts.target_limit),
 		FileFavor:       MergeFileFavor(opts.file_favor),
@@ -125,7 +132,7 @@
 	}
 	return &C.git_merge_options{
 		version:          C.uint(mo.Version),
-		tree_flags:       C.git_merge_tree_flag_t(mo.TreeFlags),
+		flags:            C.git_merge_flag_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),
@@ -263,10 +270,10 @@
 	}
 
 	oids := make([]*Oid, coids.count)
-	hdr := reflect.SliceHeader {
+	hdr := reflect.SliceHeader{
 		Data: uintptr(unsafe.Pointer(coids.ids)),
-		Len: int(coids.count),
-		Cap: int(coids.count),
+		Len:  int(coids.count),
+		Cap:  int(coids.count),
 	}
 
 	goSlice := *(*[]C.git_oid)(unsafe.Pointer(&hdr))
@@ -354,7 +361,7 @@
 	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.uint(options.Flags)
+	c.flags = C.git_merge_file_flag_t(options.Flags)
 }
 
 func freeCMergeFileOptions(c *C.git_merge_file_options) {
diff --git a/merge_test.go b/merge_test.go
index ad01319..8059727 100644
--- a/merge_test.go
+++ b/merge_test.go
@@ -115,7 +115,10 @@
 	parent, err := ref.Peel(ObjectCommit)
 	checkFatal(t, err)
 
-	commitId, err := repo.CreateCommit("HEAD", sig, sig, message, tree, parent.(*Commit))
+	parentCommit, err := parent.AsCommit()
+	checkFatal(t, err)
+
+	commitId, err := repo.CreateCommit("HEAD", sig, sig, message, tree, parentCommit)
 	checkFatal(t, err)
 
 	return commitId, treeId
diff --git a/object.go b/object.go
index 6ecebf8..1981980 100644
--- a/object.go
+++ b/object.go
@@ -4,7 +4,11 @@
 #include <git2.h>
 */
 import "C"
-import "runtime"
+import (
+	"errors"
+	"fmt"
+	"runtime"
+)
 
 type ObjectType int
 
@@ -17,15 +21,7 @@
 	ObjectTag    ObjectType = C.GIT_OBJ_TAG
 )
 
-type Object interface {
-	Free()
-	Id() *Oid
-	Type() ObjectType
-	Owner() *Repository
-	Peel(t ObjectType) (Object, error)
-}
-
-type gitObject struct {
+type Object struct {
 	ptr  *C.git_object
 	repo *Repository
 }
@@ -49,23 +45,128 @@
 	return ""
 }
 
-func (o gitObject) Id() *Oid {
+func (o *Object) Id() *Oid {
 	return newOidFromC(C.git_object_id(o.ptr))
 }
 
-func (o gitObject) Type() ObjectType {
+func (o *Object) Type() ObjectType {
 	return ObjectType(C.git_object_type(o.ptr))
 }
 
 // Owner returns a weak reference to the repository which owns this
-// object
-func (o gitObject) Owner() *Repository {
+// object. This won't keep the underlying repository alive.
+func (o *Object) Owner() *Repository {
 	return &Repository{
 		ptr: C.git_object_owner(o.ptr),
 	}
 }
 
-func (o *gitObject) Free() {
+func dupObject(obj *Object, kind ObjectType) (*C.git_object, error) {
+	if obj.Type() != kind {
+		return nil, errors.New(fmt.Sprintf("object is not a %v", kind))
+	}
+
+	var cobj *C.git_object
+
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	if err := C.git_object_dup(&cobj, obj.ptr); err < 0 {
+		return nil, MakeGitError(err)
+	}
+
+	return cobj, nil
+}
+
+func allocTree(ptr *C.git_tree, repo *Repository) *Tree {
+	tree := &Tree{
+		Object: Object{
+			ptr:  (*C.git_object)(ptr),
+			repo: repo,
+		},
+		cast_ptr: ptr,
+	}
+	runtime.SetFinalizer(tree, (*Tree).Free)
+
+	return tree
+}
+
+func (o *Object) AsTree() (*Tree, error) {
+	cobj, err := dupObject(o, ObjectTree)
+	if err != nil {
+		return nil, err
+	}
+
+	return allocTree((*C.git_tree)(cobj), o.repo), nil
+}
+
+func allocCommit(ptr *C.git_commit, repo *Repository) *Commit {
+	commit := &Commit{
+		Object: Object{
+			ptr:  (*C.git_object)(ptr),
+			repo: repo,
+		},
+		cast_ptr: ptr,
+	}
+	runtime.SetFinalizer(commit, (*Commit).Free)
+
+	return commit
+}
+
+func (o *Object) AsCommit() (*Commit, error) {
+	cobj, err := dupObject(o, ObjectCommit)
+	if err != nil {
+		return nil, err
+	}
+
+	return allocCommit((*C.git_commit)(cobj), o.repo), nil
+}
+
+func allocBlob(ptr *C.git_blob, repo *Repository) *Blob {
+	blob := &Blob{
+		Object: Object{
+			ptr:  (*C.git_object)(ptr),
+			repo: repo,
+		},
+		cast_ptr: ptr,
+	}
+	runtime.SetFinalizer(blob, (*Blob).Free)
+
+	return blob
+}
+
+func (o *Object) AsBlob() (*Blob, error) {
+	cobj, err := dupObject(o, ObjectBlob)
+	if err != nil {
+		return nil, err
+	}
+
+	return allocBlob((*C.git_blob)(cobj), o.repo), nil
+}
+
+func allocTag(ptr *C.git_tag, repo *Repository) *Tag {
+	tag := &Tag{
+		Object: Object{
+			ptr:  (*C.git_object)(ptr),
+			repo: repo,
+		},
+		cast_ptr: ptr,
+	}
+	runtime.SetFinalizer(tag, (*Tag).Free)
+
+	return tag
+}
+
+func (o *Object) AsTag() (*Tag, error) {
+	cobj, err := dupObject(o, ObjectTag)
+	if err != nil {
+		return nil, err
+	}
+
+	return allocTag((*C.git_tag)(cobj), o.repo), nil
+}
+
+func (o *Object) Free() {
 	runtime.SetFinalizer(o, nil)
 	C.git_object_free(o.ptr)
 }
@@ -82,7 +183,7 @@
 //
 // If peeling a tag we discover an object which cannot be peeled to the target
 // type due to the object model, an error will be returned.
-func (o *gitObject) Peel(t ObjectType) (Object, error) {
+func (o *Object) Peel(t ObjectType) (*Object, error) {
 	var cobj *C.git_object
 
 	runtime.LockOSThread()
@@ -95,44 +196,12 @@
 	return allocObject(cobj, o.repo), nil
 }
 
-func allocObject(cobj *C.git_object, repo *Repository) Object {
-	obj := gitObject{
+func allocObject(cobj *C.git_object, repo *Repository) *Object {
+	obj := &Object{
 		ptr:  cobj,
 		repo: repo,
 	}
+	runtime.SetFinalizer(obj, (*Object).Free)
 
-	switch ObjectType(C.git_object_type(cobj)) {
-	case ObjectCommit:
-		commit := &Commit{
-			gitObject: obj,
-			cast_ptr:  (*C.git_commit)(cobj),
-		}
-		runtime.SetFinalizer(commit, (*Commit).Free)
-		return commit
-
-	case ObjectTree:
-		tree := &Tree{
-			gitObject: obj,
-			cast_ptr:  (*C.git_tree)(cobj),
-		}
-		runtime.SetFinalizer(tree, (*Tree).Free)
-		return tree
-
-	case ObjectBlob:
-		blob := &Blob{
-			gitObject: obj,
-			cast_ptr:  (*C.git_blob)(cobj),
-		}
-		runtime.SetFinalizer(blob, (*Blob).Free)
-		return blob
-	case ObjectTag:
-		tag := &Tag{
-			gitObject: obj,
-			cast_ptr:  (*C.git_tag)(cobj),
-		}
-		runtime.SetFinalizer(tag, (*Tag).Free)
-		return tag
-	}
-
-	return nil
+	return obj
 }
diff --git a/object_test.go b/object_test.go
index ef6c5a1..2ae2a6a 100644
--- a/object_test.go
+++ b/object_test.go
@@ -10,12 +10,12 @@
 
 	commitId, treeId := seedTestRepo(t, repo)
 
-	var obj Object
+	var obj *Object
 
 	commit, err := repo.LookupCommit(commitId)
 	checkFatal(t, err)
 
-	obj = commit
+	obj = &commit.Object
 	if obj.Type() != ObjectCommit {
 		t.Fatalf("Wrong object type, expected commit, have %v", obj.Type())
 	}
@@ -27,13 +27,13 @@
 	tree, err := repo.LookupTree(treeId)
 	checkFatal(t, err)
 
-	obj = tree
+	obj = &tree.Object
 	if obj.Type() != ObjectTree {
 		t.Fatalf("Wrong object type, expected tree, have %v", obj.Type())
 	}
 
-	tree2, ok := obj.(*Tree)
-	if !ok {
+	tree2, err := obj.AsTree()
+	if err != nil {
 		t.Fatalf("Converting back to *Tree is not ok")
 	}
 
@@ -46,16 +46,16 @@
 		t.Fatal("Wrong filemode for \"README\"")
 	}
 
-	_, ok = obj.(*Commit)
-	if ok {
+	_, err = obj.AsCommit()
+	if err == nil {
 		t.Fatalf("*Tree is somehow the same as *Commit")
 	}
 
 	obj, err = repo.Lookup(tree.Id())
 	checkFatal(t, err)
 
-	_, ok = obj.(*Tree)
-	if !ok {
+	_, err = obj.AsTree()
+	if err != nil {
 		t.Fatalf("Lookup creates the wrong type")
 	}
 
@@ -99,8 +99,8 @@
 	tree, err := repo.LookupTree(treeId)
 	checkFatal(t, err)
 
-	checkOwner(t, repo, commit)
-	checkOwner(t, repo, tree)
+	checkOwner(t, repo, commit.Object)
+	checkOwner(t, repo, tree.Object)
 }
 
 func TestObjectPeel(t *testing.T) {
@@ -109,7 +109,7 @@
 
 	commitID, treeID := seedTestRepo(t, repo)
 
-	var obj Object
+	var obj *Object
 
 	commit, err := repo.LookupCommit(commitID)
 	checkFatal(t, err)
diff --git a/reference.go b/reference.go
index 140082f..463f2fc 100644
--- a/reference.go
+++ b/reference.go
@@ -263,7 +263,7 @@
 	return nil
 }
 
-func (v *Reference) Peel(t ObjectType) (Object, error) {
+func (v *Reference) Peel(t ObjectType) (*Object, error) {
 	var cobj *C.git_object
 
 	runtime.LockOSThread()
diff --git a/remote.go b/remote.go
index 330f202..8a57280 100644
--- a/remote.go
+++ b/remote.go
@@ -72,12 +72,12 @@
 type FetchPrune uint
 
 const (
-	 // Use the setting from the configuration
+	// Use the setting from the configuration
 	FetchPruneUnspecified FetchPrune = C.GIT_FETCH_PRUNE_UNSPECIFIED
 	// Force pruning on
-	FetchPruneOn       FetchPrune = C.GIT_FETCH_PRUNE
+	FetchPruneOn FetchPrune = C.GIT_FETCH_PRUNE
 	// Force pruning off
-	FetchNoPrune       FetchPrune = C.GIT_FETCH_NO_PRUNE
+	FetchNoPrune FetchPrune = C.GIT_FETCH_NO_PRUNE
 )
 
 type DownloadTags uint
@@ -88,20 +88,20 @@
 	DownloadTagsUnspecified DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED
 	// Ask the server for tags pointing to objects we're already
 	// downloading.
-	DownloadTagsAuto     DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_AUTO
+	DownloadTagsAuto DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_AUTO
 
 	// Don't ask for any tags beyond the refspecs.
-	DownloadTagsNone     DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_NONE
+	DownloadTagsNone DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_NONE
 
 	// Ask for the all the tags.
-	DownloadTagsAll      DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_ALL
+	DownloadTagsAll DownloadTags = C.GIT_REMOTE_DOWNLOAD_TAGS_ALL
 )
 
 type FetchOptions struct {
 	// Callbacks to use for this fetch operation
 	RemoteCallbacks RemoteCallbacks
 	// Whether to perform a prune after the fetch
-	Prune           FetchPrune
+	Prune FetchPrune
 	// Whether to write the results to FETCH_HEAD. Defaults to
 	// on. Leave this default in order to behave like git.
 	UpdateFetchhead bool
@@ -111,7 +111,10 @@
 	// downloading all of them.
 	//
 	// The default is to auto-follow tags.
-	DownloadTags    DownloadTags
+	DownloadTags DownloadTags
+
+	// Headers are extra headers for the fetch operation.
+	Headers []string
 }
 
 type Remote struct {
@@ -157,6 +160,9 @@
 	RemoteCallbacks RemoteCallbacks
 
 	PbParallelism uint
+
+	// Headers are extra headers for the push operation.
+	Headers []string
 }
 
 type RemoteHead struct {
@@ -588,12 +594,16 @@
 func populateFetchOptions(options *C.git_fetch_options, opts *FetchOptions) {
 	C.git_fetch_init_options(options, C.GIT_FETCH_OPTIONS_VERSION)
 	if opts == nil {
-		return;
+		return
 	}
 	populateRemoteCallbacks(&options.callbacks, &opts.RemoteCallbacks)
 	options.prune = C.git_fetch_prune_t(opts.Prune)
 	options.update_fetchhead = cbool(opts.UpdateFetchhead)
 	options.download_tags = C.git_remote_autotag_option_t(opts.DownloadTags)
+
+	options.custom_headers = C.git_strarray{}
+	options.custom_headers.count = C.size_t(len(opts.Headers))
+	options.custom_headers.strings = makeCStringsFromStrings(opts.Headers)
 }
 
 func populatePushOptions(options *C.git_push_options, opts *PushOptions) {
@@ -604,6 +614,10 @@
 
 	options.pb_parallelism = C.uint(opts.PbParallelism)
 
+	options.custom_headers = C.git_strarray{}
+	options.custom_headers.count = C.size_t(len(opts.Headers))
+	options.custom_headers.strings = makeCStringsFromStrings(opts.Headers)
+
 	populateRemoteCallbacks(&options.callbacks, &opts.RemoteCallbacks)
 }
 
@@ -611,7 +625,7 @@
 // to use for this fetch, use an empty list to use the refspecs from
 // the configuration; msg specifies what to use for the reflog
 // entries. Leave "" to use defaults.
-func (o *Remote) Fetch(refspecs []string, opts *FetchOptions,  msg string) error {
+func (o *Remote) Fetch(refspecs []string, opts *FetchOptions, msg string) error {
 	var cmsg *C.char = nil
 	if msg != "" {
 		cmsg = C.CString(msg)
@@ -628,6 +642,7 @@
 
 	populateFetchOptions(coptions, opts)
 	defer untrackCalbacksPayload(&coptions.callbacks)
+	defer freeStrarray(&coptions.custom_headers)
 
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
@@ -639,22 +654,34 @@
 	return nil
 }
 
-func (o *Remote) ConnectFetch(callbacks *RemoteCallbacks) error {
-	return o.Connect(ConnectDirectionFetch, callbacks)
+func (o *Remote) ConnectFetch(callbacks *RemoteCallbacks, headers []string) error {
+	return o.Connect(ConnectDirectionFetch, callbacks, headers)
 }
 
-func (o *Remote) ConnectPush(callbacks *RemoteCallbacks) error {
-	return o.Connect(ConnectDirectionPush, callbacks)
+func (o *Remote) ConnectPush(callbacks *RemoteCallbacks, headers []string) error {
+	return o.Connect(ConnectDirectionPush, callbacks, headers)
 }
 
-func (o *Remote) Connect(direction ConnectDirection, callbacks *RemoteCallbacks) error {
-	var ccallbacks C.git_remote_callbacks;
+// Connect opens a connection to a remote.
+//
+// The transport is selected based on the URL. The direction argument
+// is due to a limitation of the git protocol (over TCP or SSH) which
+// starts up a specific binary which can only do the one or the other.
+//
+// 'headers' are extra HTTP headers to use in this connection.
+func (o *Remote) Connect(direction ConnectDirection, callbacks *RemoteCallbacks, headers []string) error {
+	var ccallbacks C.git_remote_callbacks
 	populateRemoteCallbacks(&ccallbacks, callbacks)
 
+	cheaders := C.git_strarray{}
+	cheaders.count = C.size_t(len(headers))
+	cheaders.strings = makeCStringsFromStrings(headers)
+	defer freeStrarray(&cheaders)
+
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
 
-	if ret := C.git_remote_connect(o.ptr, C.git_direction(direction), &ccallbacks); ret != 0 {
+	if ret := C.git_remote_connect(o.ptr, C.git_direction(direction), &ccallbacks, &cheaders); ret != 0 {
 		return MakeGitError(ret)
 	}
 	return nil
@@ -717,6 +744,7 @@
 
 	populatePushOptions(coptions, opts)
 	defer untrackCalbacksPayload(&coptions.callbacks)
+	defer freeStrarray(&coptions.custom_headers)
 
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
@@ -733,7 +761,7 @@
 }
 
 func (o *Remote) Prune(callbacks *RemoteCallbacks) error {
-	var ccallbacks C.git_remote_callbacks;
+	var ccallbacks C.git_remote_callbacks
 	populateRemoteCallbacks(&ccallbacks, callbacks)
 
 	runtime.LockOSThread()
diff --git a/remote_test.go b/remote_test.go
index 73c637f..978b803 100644
--- a/remote_test.go
+++ b/remote_test.go
@@ -39,7 +39,7 @@
 	remote, err := repo.Remotes.Create("origin", "https://github.com/libgit2/TestGitRepository")
 	checkFatal(t, err)
 
-	options := FetchOptions {
+	options := FetchOptions{
 		RemoteCallbacks: RemoteCallbacks{
 			CertificateCheckCallback: func(cert *Certificate, valid bool, hostname string) ErrorCode {
 				return assertHostname(cert, valid, hostname, t)
@@ -58,7 +58,7 @@
 	remote, err := repo.Remotes.Create("origin", "https://github.com/libgit2/TestGitRepository")
 	checkFatal(t, err)
 
-	err = remote.ConnectFetch(nil)
+	err = remote.ConnectFetch(nil, nil)
 	checkFatal(t, err)
 }
 
@@ -69,7 +69,7 @@
 	remote, err := repo.Remotes.Create("origin", "https://github.com/libgit2/TestGitRepository")
 	checkFatal(t, err)
 
-	err = remote.ConnectFetch(nil)
+	err = remote.ConnectFetch(nil, nil)
 	checkFatal(t, err)
 
 	heads, err := remote.Ls()
@@ -87,7 +87,7 @@
 	remote, err := repo.Remotes.Create("origin", "https://github.com/libgit2/TestGitRepository")
 	checkFatal(t, err)
 
-	err = remote.ConnectFetch(nil)
+	err = remote.ConnectFetch(nil, nil)
 	checkFatal(t, err)
 
 	heads, err := remote.Ls("master")
@@ -166,7 +166,7 @@
 	rr, err := repo.Remotes.Lookup("origin")
 	checkFatal(t, err)
 
-	err = rr.ConnectFetch(nil)
+	err = rr.ConnectFetch(nil, nil)
 	checkFatal(t, err)
 
 	err = rr.Prune(nil)
diff --git a/repository.go b/repository.go
index 12638e1..77e9f9c 100644
--- a/repository.go
+++ b/repository.go
@@ -12,11 +12,11 @@
 
 // Repository
 type Repository struct {
-	ptr     *C.git_repository
+	ptr *C.git_repository
 	// Remotes represents the collection of remotes and can be
 	// used to add, remove and configure remotes for this
 	// repository.
-	Remotes  RemoteCollection
+	Remotes RemoteCollection
 	// Submodules represents the collection of submodules and can
 	// be used to add, remove and configure submodules in this
 	// repostiory.
@@ -26,7 +26,7 @@
 	References ReferenceCollection
 	// Notes represents the collection of notes and can be used to
 	// read, write and delete notes from this repository.
-	Notes      NoteCollection
+	Notes NoteCollection
 	// Tags represents the collection of tags and can be used to create,
 	// list and iterate tags in this repository.
 	Tags TagsCollection
@@ -35,10 +35,10 @@
 func newRepositoryFromC(ptr *C.git_repository) *Repository {
 	repo := &Repository{ptr: ptr}
 
-	repo.Remotes.repo    = repo
+	repo.Remotes.repo = repo
 	repo.Submodules.repo = repo
 	repo.References.repo = repo
-	repo.Notes.repo      = repo
+	repo.Notes.repo = repo
 	repo.Tags.repo = repo
 
 	runtime.SetFinalizer(repo, (*Repository).Free)
@@ -62,15 +62,29 @@
 	return newRepositoryFromC(ptr), nil
 }
 
-func OpenRepositoryExtended(path string) (*Repository, error) {
+type RepositoryOpenFlag int
+
+const (
+	RepositoryOpenNoSearch RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_NO_SEARCH
+	RepositoryOpenCrossFs  RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_CROSS_FS
+	RepositoryOpenBare     RepositoryOpenFlag = C.GIT_REPOSITORY_OPEN_BARE
+)
+
+func OpenRepositoryExtended(path string, flags RepositoryOpenFlag, ceiling string) (*Repository, error) {
 	cpath := C.CString(path)
 	defer C.free(unsafe.Pointer(cpath))
 
+	var cceiling *C.char = nil
+	if len(ceiling) > 0 {
+		cceiling = C.CString(ceiling)
+		defer C.free(unsafe.Pointer(cceiling))
+	}
+
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
 
 	var ptr *C.git_repository
-	ret := C.git_repository_open_ext(&ptr, cpath, 0, nil)
+	ret := C.git_repository_open_ext(&ptr, cpath, C.uint(flags), cceiling)
 	if ret < 0 {
 		return nil, MakeGitError(ret)
 	}
@@ -145,7 +159,7 @@
 	return newIndexFromC(ptr), nil
 }
 
-func (v *Repository) lookupType(id *Oid, t ObjectType) (Object, error) {
+func (v *Repository) lookupType(id *Oid, t ObjectType) (*Object, error) {
 	var ptr *C.git_object
 
 	runtime.LockOSThread()
@@ -159,7 +173,7 @@
 	return allocObject(ptr, v), nil
 }
 
-func (v *Repository) Lookup(id *Oid) (Object, error) {
+func (v *Repository) Lookup(id *Oid) (*Object, error) {
 	return v.lookupType(id, ObjectAny)
 }
 
@@ -169,7 +183,7 @@
 		return nil, err
 	}
 
-	return obj.(*Tree), nil
+	return obj.AsTree()
 }
 
 func (v *Repository) LookupCommit(id *Oid) (*Commit, error) {
@@ -178,7 +192,7 @@
 		return nil, err
 	}
 
-	return obj.(*Commit), nil
+	return obj.AsCommit()
 }
 
 func (v *Repository) LookupBlob(id *Oid) (*Blob, error) {
@@ -187,7 +201,7 @@
 		return nil, err
 	}
 
-	return obj.(*Blob), nil
+	return obj.AsBlob()
 }
 
 func (v *Repository) LookupTag(id *Oid) (*Tag, error) {
@@ -196,7 +210,7 @@
 		return nil, err
 	}
 
-	return obj.(*Tag), nil
+	return obj.AsTag()
 }
 
 func (v *Repository) Head() (*Reference, error) {
diff --git a/reset.go b/reset.go
index b5b7435..9da7625 100644
--- a/reset.go
+++ b/reset.go
@@ -17,7 +17,7 @@
 func (r *Repository) ResetToCommit(commit *Commit, resetType ResetType, opts *CheckoutOpts) error {
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
-	ret := C.git_reset(r.ptr, commit.gitObject.ptr, C.git_reset_t(resetType), opts.toC())
+	ret := C.git_reset(r.ptr, commit.ptr, C.git_reset_t(resetType), opts.toC())
 
 	if ret < 0 {
 		return MakeGitError(ret)
diff --git a/revparse.go b/revparse.go
index 7eb04f1..950932b 100644
--- a/revparse.go
+++ b/revparse.go
@@ -20,16 +20,16 @@
 )
 
 type Revspec struct {
-	to    Object
-	from  Object
+	to    *Object
+	from  *Object
 	flags RevparseFlag
 }
 
-func (rs *Revspec) To() Object {
+func (rs *Revspec) To() *Object {
 	return rs.to
 }
 
-func (rs *Revspec) From() Object {
+func (rs *Revspec) From() *Object {
 	return rs.from
 }
 
@@ -38,8 +38,8 @@
 }
 
 func newRevspecFromC(ptr *C.git_revspec, repo *Repository) *Revspec {
-	var to Object
-	var from Object
+	var to *Object
+	var from *Object
 
 	if ptr.to != nil {
 		to = allocObject(ptr.to, repo)
@@ -73,7 +73,7 @@
 	return newRevspecFromC(&crevspec, r), nil
 }
 
-func (v *Repository) RevparseSingle(spec string) (Object, error) {
+func (v *Repository) RevparseSingle(spec string) (*Object, error) {
 	cspec := C.CString(spec)
 	defer C.free(unsafe.Pointer(cspec))
 
@@ -90,7 +90,7 @@
 	return allocObject(ptr, v), nil
 }
 
-func (r *Repository) RevparseExt(spec string) (Object, *Reference, error) {
+func (r *Repository) RevparseExt(spec string) (*Object, *Reference, error) {
 	cspec := C.CString(spec)
 	defer C.free(unsafe.Pointer(cspec))
 
diff --git a/revparse_test.go b/revparse_test.go
index 091a76b..75e9ffd 100644
--- a/revparse_test.go
+++ b/revparse_test.go
@@ -46,7 +46,7 @@
 	}
 }
 
-func checkObject(t *testing.T, obj Object, id *Oid) {
+func checkObject(t *testing.T, obj *Object, id *Oid) {
 	if obj == nil {
 		t.Fatalf("bad object")
 	}
diff --git a/tag.go b/tag.go
index ca85156..8957430 100644
--- a/tag.go
+++ b/tag.go
@@ -13,7 +13,7 @@
 
 // Tag
 type Tag struct {
-	gitObject
+	Object
 	cast_ptr *C.git_tag
 }
 
@@ -30,7 +30,7 @@
 	return newSignatureFromC(cast_ptr)
 }
 
-func (t Tag) Target() Object {
+func (t Tag) Target() *Object {
 	var ptr *C.git_object
 	ret := C.git_tag_target(&ptr, t.cast_ptr)
 
@@ -70,7 +70,7 @@
 	}
 	defer C.git_signature_free(taggerSig)
 
-	ctarget := commit.gitObject.ptr
+	ctarget := commit.ptr
 
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
@@ -102,7 +102,7 @@
 	cname := C.CString(name)
 	defer C.free(unsafe.Pointer(cname))
 
-	ctarget := commit.gitObject.ptr
+	ctarget := commit.ptr
 
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
diff --git a/tree.go b/tree.go
index f543c11..eba9f3d 100644
--- a/tree.go
+++ b/tree.go
@@ -23,7 +23,7 @@
 )
 
 type Tree struct {
-	gitObject
+	Object
 	cast_ptr *C.git_tree
 }
 
@@ -149,7 +149,7 @@
 	C.git_treebuilder_free(v.ptr)
 }
 
-func (v *TreeBuilder) Insert(filename string, id *Oid, filemode int) error {
+func (v *TreeBuilder) Insert(filename string, id *Oid, filemode Filemode) error {
 	cfilename := C.CString(filename)
 	defer C.free(unsafe.Pointer(cfilename))
 
diff --git a/tree_test.go b/tree_test.go
index 4c6a4ed..fae395a 100644
--- a/tree_test.go
+++ b/tree_test.go
@@ -20,3 +20,44 @@
 		t.Fatalf("entry id %v was not found", id)
 	}
 }
+
+func TestTreeBuilderInsert(t *testing.T) {
+	repo := createTestRepo(t)
+	defer cleanupTestRepo(t, repo)
+
+	subTree, err := repo.TreeBuilder()
+	if err != nil {
+		t.Fatalf("TreeBuilder: %v", err)
+	}
+	defer subTree.Free()
+
+	odb, err := repo.Odb()
+	if err != nil {
+		t.Fatalf("repo.Odb: %v", err)
+	}
+	blobId, err := odb.Write([]byte("hello"), ObjectBlob)
+	if err != nil {
+		t.Fatalf("odb.Write: %v", err)
+	}
+	if err = subTree.Insert("subfile", blobId, FilemodeBlobExecutable); err != nil {
+		t.Fatalf("TreeBuilder.Insert: %v", err)
+	}
+	treeID, err := subTree.Write()
+	if err != nil {
+		t.Fatalf("TreeBuilder.Write: %v", err)
+	}
+
+	tree, err := repo.LookupTree(treeID)
+	if err != nil {
+		t.Fatalf("LookupTree: %v", err)
+	}
+
+	entry, err := tree.EntryByPath("subfile")
+	if err != nil {
+		t.Fatalf("tree.EntryByPath(%q): %v", "subfile", err)
+	}
+
+	if !entry.Id.Equal(blobId) {
+		t.Fatalf("got oid %v, want %v", entry.Id, blobId)
+	}
+}