Repository: libgit2/git2go (go)

Issue:
Support git_repository_set_config
It would be nice to support https://github.com/libgit2/libgit2/blob/v1.1.0/include/git2/sys/repository.h#L86 which is introduced in v0.16.0 . Thank you! 

Pull request:
Implement git_repository_set_config
Closes #732 

Patch:
diff --git a/remote.go b/remote.go
index 1887f79..08d8414 100644
--- a/remote.go
+++ b/remote.go
@@ -18,6 +18,23 @@ import (
 	"unsafe"
 )
 
+// RemoteCreateOptionsFlag is Remote creation options flags
+type RemoteCreateOptionsFlag uint
+
+const (
+	// Ignore the repository apply.insteadOf configuration
+	RemoteCreateSkipInsteadof RemoteCreateOptionsFlag = C.GIT_REMOTE_CREATE_SKIP_INSTEADOF
+	// Don't build a fetchspec from the name if none is set
+	RemoteCreateSkipDefaultFetchspec RemoteCreateOptionsFlag = C.GIT_REMOTE_CREATE_SKIP_DEFAULT_FETCHSPEC
+)
+
+// RemoteCreateOptions contains options for creating a remote
+type RemoteCreateOptions struct {
+	Name       string
+	FetchSpec  string
+	Flags      RemoteCreateOptionsFlag
+}
+
 type TransferProgress struct {
 	TotalObjects    uint
 	IndexedObjects  uint
@@ -539,6 +556,28 @@ func (c *RemoteCollection) Create(name string, url string) (*Remote, error) {
 	return remote, nil
 }
 
+//CreateWithOptions Creates a repository object with extended options.
+func (c *RemoteCollection) CreateWithOptions(url string, option *RemoteCreateOptions) (*Remote, error) {
+	remote := &Remote{repo: c.repo}
+
+	curl := C.CString(url)
+	defer C.free(unsafe.Pointer(curl))
+
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	copts := populateRemoteCreateOptions(&C.git_remote_create_options{}, option, c.repo)
+	defer freeRemoteCreateOptions(copts)
+	ret := C.git_remote_create_with_opts(&remote.ptr, curl, copts)
+	runtime.KeepAlive(c.repo)
+	if ret < 0 {
+		return nil, MakeGitError(ret)
+	}
+
+	runtime.SetFinalizer(remote, (*Remote).Free)
+	return remote, nil
+}
+
 func (c *RemoteCollection) Delete(name string) error {
 	cname := C.CString(name)
 	defer C.free(unsafe.Pointer(cname))
@@ -1027,3 +1066,45 @@ func (o *Remote) Prune(callbacks *RemoteCallbacks) error {
 	}
 	return nil
 }
+
+// DefaultApplyOptions returns default options for remote create
+func DefaultRemoteCreateOptions() (*RemoteCreateOptions, error) {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	opts := C.git_remote_create_options{}
+	ecode := C.git_remote_create_options_init(&opts, C.GIT_REMOTE_CREATE_OPTIONS_VERSION)
+	if ecode < 0 {
+		return nil, MakeGitError(ecode)
+	}
+
+	return &RemoteCreateOptions{
+		Flags: RemoteCreateOptionsFlag(opts.flags),
+	}, nil
+}
+
+func populateRemoteCreateOptions(copts *C.git_remote_create_options, opts *RemoteCreateOptions, repo *Repository) *C.git_remote_create_options {
+	C.git_remote_create_options_init(copts, C.GIT_REMOTE_CREATE_OPTIONS_VERSION)
+	if opts == nil {
+		return nil
+	}
+
+	var cRepository *C.git_repository
+	if repo != nil {
+		cRepository = repo.ptr
+	}
+	copts.repository = cRepository
+	copts.name = C.CString(opts.Name)
+	copts.fetchspec = C.CString(opts.FetchSpec)
+	copts.flags = C.uint(opts.Flags)
+
+	return copts
+}
+
+func freeRemoteCreateOptions(ptr *C.git_remote_create_options) {
+	if ptr == nil {
+		return
+	}
+	C.free(unsafe.Pointer(ptr.name))
+	C.free(unsafe.Pointer(ptr.fetchspec))
+}
diff --git a/repository.go b/repository.go
index d2b9961..a6eb7f1 100644
--- a/repository.go
+++ b/repository.go
@@ -165,6 +165,23 @@ func (v *Repository) Config() (*Config, error) {
 	return config, nil
 }
 
+// SetConfig sets the configuration file for this repository.
+//
+// This configuration file will be used for all configuration queries involving
+// this repository.
+func (v *Repository) SetConfig(c *Config) error {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	ret := C.git_repository_set_config(v.ptr, c.ptr)
+	runtime.KeepAlive(v)
+	runtime.KeepAlive(c)
+	if ret < 0 {
+		return MakeGitError(ret)
+	}
+	return nil
+}
+
 func (v *Repository) Index() (*Index, error) {
 	var ptr *C.git_index
 
@@ -688,3 +705,39 @@ func (r *Repository) ClearGitIgnoreRules() error {
 	}
 	return nil
 }
+
+// Message retrieves git's prepared message.
+// Operations such as git revert/cherry-pick/merge with the -n option stop just
+// short of creating a commit with the changes and save their prepared message
+// in .git/MERGE_MSG so the next git-commit execution can present it to the
+// user for them to amend if they wish.
+//
+// Use this function to get the contents of this file. Don't forget to remove
+// the file after you create the commit.
+func (r *Repository) Message() (string, error) {
+	buf := C.git_buf{}
+	defer C.git_buf_dispose(&buf)
+
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	cErr := C.git_repository_message(&buf, r.ptr)
+	runtime.KeepAlive(r)
+	if cErr < 0 {
+		return "", MakeGitError(cErr)
+	}
+	return C.GoString(buf.ptr), nil
+}
+
+// RemoveMessage removes git's prepared message.
+func (r *Repository) RemoveMessage() error {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	cErr := C.git_repository_message_remove(r.ptr)
+	runtime.KeepAlive(r)
+	if cErr < 0 {
+		return MakeGitError(cErr)
+	}
+	return  nil
+}


Test patch:
diff --git a/merge_test.go b/merge_test.go
index d49d07c..72b1a26 100644
--- a/merge_test.go
+++ b/merge_test.go
@@ -43,6 +43,14 @@ func TestMergeWithSelf(t *testing.T) {
 	mergeHeads[0] = mergeHead
 	err = repo.Merge(mergeHeads, nil, nil)
 	checkFatal(t, err)
+
+	mergeMessage, err := repo.Message()
+	checkFatal(t, err)
+
+	expectedMessage := "Merge branch 'master'\n"
+	if mergeMessage != expectedMessage {
+		t.Errorf("merge Message = %v, want %v", mergeMessage, expectedMessage)
+	}
 }
 
 func TestMergeAnalysisWithSelf(t *testing.T) {
diff --git a/remote_test.go b/remote_test.go
index 16ac06b..22fd292 100644
--- a/remote_test.go
+++ b/remote_test.go
@@ -80,6 +80,28 @@ func TestRemoteConnect(t *testing.T) {
 	checkFatal(t, err)
 }
 
+func TestRemoteConnectOption(t *testing.T) {
+	t.Parallel()
+	repo := createTestRepo(t)
+	defer cleanupTestRepo(t, repo)
+
+	config, err := repo.Config()
+	checkFatal(t, err)
+	err = config.SetString("url.git@github.com:.insteadof", "https://github.com/")
+	checkFatal(t, err)
+
+	option, err := DefaultRemoteCreateOptions()
+	checkFatal(t, err)
+	option.Name = "origin"
+	option.Flags = RemoteCreateSkipInsteadof
+
+	remote, err := repo.Remotes.CreateWithOptions("https://github.com/libgit2/TestGitRepository", option)
+	checkFatal(t, err)
+
+	err = remote.ConnectFetch(nil, nil, nil)
+	checkFatal(t, err)
+}
+
 func TestRemoteLs(t *testing.T) {
 	t.Parallel()
 	repo := createTestRepo(t)
diff --git a/repository_test.go b/repository_test.go
index 1950c69..5a0f920 100644
--- a/repository_test.go
+++ b/repository_test.go
@@ -40,3 +40,55 @@ func TestCreateCommitFromIds(t *testing.T) {
 		t.Errorf("mismatched commit ids, expected %v, got %v", expectedCommitId.String(), commitId.String())
 	}
 }
+
+func TestRepositorySetConfig(t *testing.T) {
+	repo := createTestRepo(t)
+	defer cleanupTestRepo(t, repo)
+
+	loc, err := time.LoadLocation("Europe/Berlin")
+	checkFatal(t, err)
+	sig := &Signature{
+		Name:  "Rand Om Hacker",
+		Email: "random@hacker.com",
+		When:  time.Date(2013, 03, 06, 14, 30, 0, 0, loc),
+	}
+
+	idx, err := repo.Index()
+	checkFatal(t, err)
+	err = idx.AddByPath("README")
+
+	treeId, err := idx.WriteTree()
+	checkFatal(t, err)
+
+	message := "This is a commit\n"
+	tree, err := repo.LookupTree(treeId)
+	checkFatal(t, err)
+	_, err = repo.CreateCommit("HEAD", sig, sig, message, tree)
+	checkFatal(t, err)
+
+	repoConfig, err := repo.Config()
+	checkFatal(t, err)
+
+	temp := Config{}
+	localConfig, err := temp.OpenLevel(repoConfig, ConfigLevelLocal)
+	checkFatal(t, err)
+	repoConfig = nil
+
+	err = repo.SetConfig(localConfig)
+	checkFatal(t, err)
+
+	configFieldName := "core.filemode"
+	err = localConfig.SetBool(configFieldName, true)
+	checkFatal(t, err)
+
+	localConfig = nil
+
+	repoConfig, err = repo.Config()
+	checkFatal(t, err)
+
+	result, err := repoConfig.LookupBool(configFieldName)
+	checkFatal(t, err)
+	if result != true {
+		t.Fatal("result must be true")
+	}
+}