summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Burke <[email protected]>2018-07-03 22:05:05 +0100
committerlhchavez <[email protected]>2020-02-22 19:39:50 -0800
commit30c3d0ffe2118376ccbf3ff5ea1676bd7442440d (patch)
tree8e944163a8de8370b03de5b9a8c317d3f2575da3
parent2bb5930733a50b441c4a591dee931af00cf293f2 (diff)
Add revert functionality
Closes #436
-rw-r--r--revert.go103
-rw-r--r--revert_test.go76
2 files changed, 179 insertions, 0 deletions
diff --git a/revert.go b/revert.go
new file mode 100644
index 0000000..8e8bb29
--- /dev/null
+++ b/revert.go
@@ -0,0 +1,103 @@
+package git
+
+/*
+#include <git2.h>
+*/
+import "C"
+import (
+ "runtime"
+)
+
+// RevertOptions contains options for performing a revert
+type RevertOptions struct {
+ Version uint
+ Mainline uint
+ MergeOpts MergeOptions
+ CheckoutOpts CheckoutOpts
+}
+
+func (opts *RevertOptions) toC() *C.git_revert_options {
+ return &C.git_revert_options{
+ version: C.uint(opts.Version),
+ mainline: C.uint(opts.Mainline),
+ merge_opts: *opts.MergeOpts.toC(),
+ checkout_opts: *opts.CheckoutOpts.toC(),
+ }
+}
+
+func revertOptionsFromC(opts *C.git_revert_options) RevertOptions {
+ return RevertOptions{
+ Version: uint(opts.version),
+ Mainline: uint(opts.mainline),
+ MergeOpts: mergeOptionsFromC(&opts.merge_opts),
+ CheckoutOpts: checkoutOptionsFromC(&opts.checkout_opts),
+ }
+}
+
+func freeRevertOptions(opts *C.git_revert_options) {
+ freeCheckoutOpts(&opts.checkout_opts)
+}
+
+// DefaultRevertOptions initialises a RevertOptions struct with default values
+func DefaultRevertOptions() (RevertOptions, error) {
+ opts := C.git_revert_options{}
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ecode := C.git_revert_init_options(&opts, C.GIT_REVERT_OPTIONS_VERSION)
+ if ecode < 0 {
+ return RevertOptions{}, MakeGitError(ecode)
+ }
+
+ defer freeRevertOptions(&opts)
+ return revertOptionsFromC(&opts), nil
+}
+
+// Revert the provided commit leaving the index updated with the results of the revert
+func (r *Repository) Revert(commit *Commit, revertOptions *RevertOptions) error {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var cOpts *C.git_revert_options
+
+ if revertOptions != nil {
+ cOpts = revertOptions.toC()
+ defer freeRevertOptions(cOpts)
+ }
+
+ ecode := C.git_revert(r.ptr, commit.cast_ptr, cOpts)
+ runtime.KeepAlive(r)
+ runtime.KeepAlive(commit)
+
+ if ecode < 0 {
+ return MakeGitError(ecode)
+ }
+
+ return nil
+}
+
+// RevertCommit reverts the provided commit against "ourCommit"
+// The returned index contains the result of the revert and should be freed
+func (r *Repository) RevertCommit(revertCommit *Commit, ourCommit *Commit, mainline uint, mergeOptions *MergeOptions) (*Index, error) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ var cOpts *C.git_merge_options
+
+ if mergeOptions != nil {
+ cOpts = mergeOptions.toC()
+ }
+
+ var index *C.git_index
+
+ ecode := C.git_revert_commit(&index, r.ptr, revertCommit.cast_ptr, ourCommit.cast_ptr, C.uint(mainline), cOpts)
+ runtime.KeepAlive(revertCommit)
+ runtime.KeepAlive(ourCommit)
+
+ if ecode < 0 {
+ return nil, MakeGitError(ecode)
+ }
+
+ return newIndexFromC(index, r), nil
+}
diff --git a/revert_test.go b/revert_test.go
new file mode 100644
index 0000000..fcf8e43
--- /dev/null
+++ b/revert_test.go
@@ -0,0 +1,76 @@
+package git
+
+import (
+ "testing"
+)
+
+const (
+ expectedRevertedReadmeContents = "foo\n"
+)
+
+func TestRevert(t *testing.T) {
+ t.Parallel()
+ repo := createTestRepo(t)
+ defer cleanupTestRepo(t, repo)
+
+ seedTestRepo(t, repo)
+ commitID, _ := updateReadme(t, repo, content)
+
+ commit, err := repo.LookupCommit(commitID)
+ checkFatal(t, err)
+
+ revertOptions, err := DefaultRevertOptions()
+ checkFatal(t, err)
+
+ err = repo.Revert(commit, &revertOptions)
+ checkFatal(t, err)
+
+ actualReadmeContents := readReadme(t, repo)
+
+ if actualReadmeContents != expectedRevertedReadmeContents {
+ t.Fatalf(`README has incorrect contents after revert. Expected: "%v", Actual: "%v"`,
+ expectedRevertedReadmeContents, actualReadmeContents)
+ }
+
+ state := repo.State()
+ if state != RepositoryStateRevert {
+ t.Fatalf("Incorrect repository state. Expected: %v, Actual: %v", RepositoryStateRevert, state)
+ }
+
+ err = repo.StateCleanup()
+ checkFatal(t, err)
+
+ state = repo.State()
+ if state != RepositoryStateNone {
+ t.Fatalf("Incorrect repository state. Expected: %v, Actual: %v", RepositoryStateNone, state)
+ }
+}
+
+func TestRevertCommit(t *testing.T) {
+ t.Parallel()
+ repo := createTestRepo(t)
+ defer cleanupTestRepo(t, repo)
+
+ seedTestRepo(t, repo)
+ commitID, _ := updateReadme(t, repo, content)
+
+ commit, err := repo.LookupCommit(commitID)
+ checkFatal(t, err)
+
+ revertOptions, err := DefaultRevertOptions()
+ checkFatal(t, err)
+
+ index, err := repo.RevertCommit(commit, commit, 0, &revertOptions.MergeOpts)
+ checkFatal(t, err)
+ defer index.Free()
+
+ err = repo.CheckoutIndex(index, &revertOptions.CheckoutOpts)
+ checkFatal(t, err)
+
+ actualReadmeContents := readReadme(t, repo)
+
+ if actualReadmeContents != expectedRevertedReadmeContents {
+ t.Fatalf(`README has incorrect contents after revert. Expected: "%v", Actual: "%v"`,
+ expectedRevertedReadmeContents, actualReadmeContents)
+ }
+}