Add revert functionality
Closes #436
(cherry picked from commit 30c3d0ffe2
)
This commit is contained in:
parent
2fba250690
commit
b55ee91e3c
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue