summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Probst <[email protected]>2015-03-04 11:38:19 -0800
committerMark Probst <[email protected]>2015-03-04 15:52:54 -0800
commitc78b4d665e406af7e8cba608f65ac2171d3917b6 (patch)
treee37a40954d28fc7bd397f6f4596ab0535e0d371b
parent56ed0b22d7f7ab6185f14e0054346da3ca33c4fa (diff)
Cherrypick
-rw-r--r--checkout.go13
-rw-r--r--cherrypick.go73
-rw-r--r--cherrypick_test.go73
-rw-r--r--git_test.go6
4 files changed, 164 insertions, 1 deletions
diff --git a/checkout.go b/checkout.go
index 72a1fe3..6eb6098 100644
--- a/checkout.go
+++ b/checkout.go
@@ -40,6 +40,19 @@ type CheckoutOpts struct {
TargetDirectory string // Alternative checkout path to workdir
}
+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..c867cf9
--- /dev/null
+++ b/cherrypick_test.go
@@ -0,0 +1,73 @@
+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)
+ }
+}
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 @@ func seedTestRepo(t *testing.T, repo *Repository) (*Oid, *Oid) {
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 @@ func updateReadme(t *testing.T, repo *Repository, content string) (*Oid, *Oid) {
}
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()