summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rebase.go15
-rw-r--r--rebase_test.go247
2 files changed, 199 insertions, 63 deletions
diff --git a/rebase.go b/rebase.go
index 3e7da53..fb3d612 100644
--- a/rebase.go
+++ b/rebase.go
@@ -139,6 +139,11 @@ func (rebase *Rebase) Finish() error {
return nil
}
+// OperationCount gets the count of rebase operations that are to be applied.
+func (rebase *Rebase) OperationCount() uint {
+ return uint(C.git_rebase_operation_entrycount(rebase.ptr))
+}
+
//Free frees the Rebase object and underlying git_rebase C pointer.
func (rebase *Rebase) Free() {
runtime.SetFinalizer(rebase, nil)
@@ -150,3 +155,13 @@ func newRebaseFromC(ptr *C.git_rebase) *Rebase {
runtime.SetFinalizer(rebase, (*Rebase).Free)
return rebase
}
+
+/* TODO -- Add last wrapper services and manage rebase_options
+
+int git_rebase_abort(git_rebase *rebase);
+int git_rebase_init_options(git_rebase_options *opts, unsigned int version);
+int git_rebase_open(git_rebase **out, git_repository *repo, const git_rebase_options *opts);
+git_rebase_operation * git_rebase_operation_byindex(git_rebase *rebase, size_t idx);
+size_t git_rebase_operation_current(git_rebase *rebase);
+
+*/
diff --git a/rebase_test.go b/rebase_test.go
index d4b4251..7106e7f 100644
--- a/rebase_test.go
+++ b/rebase_test.go
@@ -1,19 +1,142 @@
package git
import (
+ "errors"
+ "strconv"
"testing"
"time"
)
-func createBranch(repo *Repository, branch string) error {
- head, err := repo.Head()
+// Tests
+
+func TestRebaseNoConflicts(t *testing.T) {
+ // TEST DATA
+
+ // Inputs
+ branchName := "emile"
+ masterCommit := "something"
+ emileCommits := []string{
+ "fou",
+ "barre",
+ "ouich",
+ }
+
+ // Outputs
+ expectedHistory := []string{
+ "Test rebase onto, Baby! " + emileCommits[2],
+ "Test rebase onto, Baby! " + emileCommits[1],
+ "Test rebase onto, Baby! " + emileCommits[0],
+ "Test rebase onto, Baby! " + masterCommit,
+ "This is a commit\n",
+ }
+
+ // TEST
+ repo := createTestRepo(t)
+ seedTestRepo(t, repo)
+
+ // Setup a repo with 2 branches and a different tree
+ err := setupRepoForRebase(repo, masterCommit, branchName)
+ checkFatal(t, err)
+ defer cleanupTestRepo(t, repo)
+
+ // Create several commits in emile
+ for _, commit := range emileCommits {
+ _, err = commitSomething(repo, commit, commit)
+ checkFatal(t, err)
+ }
+
+ // Rebase onto master
+ err = performRebaseOnto(repo, "master")
+ checkFatal(t, err)
+
+ // Check history is in correct order
+ actualHistory, err := commitMsgsList(repo)
+ checkFatal(t, err)
+ assertStringList(t, expectedHistory, actualHistory)
+
+}
+
+// Utils
+func setupRepoForRebase(repo *Repository, masterCommit, branchName string) error {
+ // Create a new branch from master
+ err := createBranch(repo, branchName)
if err != nil {
return err
}
- commit, err := repo.LookupCommit(head.Target())
+
+ // Create a commit in master
+ _, err = commitSomething(repo, masterCommit, masterCommit)
+ if err != nil {
+ return err
+ }
+
+ // Switch to emile
+ err = repo.SetHead("refs/heads/" + branchName)
+ if err != nil {
+ return err
+ }
+
+ // Check master commit is not in emile branch
+ if entryExists(repo, masterCommit) {
+ return errors.New(masterCommit + " entry should not exist in " + branchName + " branch.")
+ }
+
+ return nil
+}
+
+func performRebaseOnto(repo *Repository, branch string) error {
+ master, err := repo.LookupBranch(branch, BranchLocal)
+ if err != nil {
+ return err
+ }
+ defer master.Free()
+
+ onto, err := repo.AnnotatedCommitFromRef(master.Reference)
+ if err != nil {
+ return err
+ }
+ defer onto.Free()
+
+ rebase, err := repo.RebaseInit(nil, nil, onto, nil)
+ if err != nil {
+ return err
+ }
+ defer rebase.Free()
+
+ opCount := int(rebase.OperationCount())
+
+ for op := 0; op < opCount; op++ {
+ operation, err := rebase.Next()
+ if err != nil {
+ return err
+ }
+
+ commit, err := repo.LookupCommit(operation.ID)
+ if err != nil {
+ return err
+ }
+ defer commit.Free()
+
+ err = rebase.Commit(operation.ID, signature(), signature(), commit.Message())
+ if err != nil {
+ return err
+ }
+ }
+
+ err = rebase.Finish()
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func createBranch(repo *Repository, branch string) error {
+ commit, err := headCommit(repo)
if err != nil {
return err
}
+ defer commit.Free()
_, err = repo.CreateBranch(branch, commit, false)
if err != nil {
return err
@@ -30,16 +153,42 @@ func signature() *Signature {
}
}
-func commitSomething(repo *Repository, something string) (*Oid, error) {
+func headCommit(repo *Repository) (*Commit, error) {
head, err := repo.Head()
if err != nil {
return nil, err
}
+ defer head.Free()
+
+ commit, err := repo.LookupCommit(head.Target())
+ if err != nil {
+ return nil, err
+ }
+
+ return commit, nil
+}
- headCommit, err := repo.LookupCommit(head.Target())
+func headTree(repo *Repository) (*Tree, error) {
+ headCommit, err := headCommit(repo)
if err != nil {
return nil, err
}
+ defer headCommit.Free()
+
+ tree, err := headCommit.Tree()
+ if err != nil {
+ return nil, err
+ }
+
+ return tree, nil
+}
+
+func commitSomething(repo *Repository, something, content string) (*Oid, error) {
+ headCommit, err := headCommit(repo)
+ if err != nil {
+ return nil, err
+ }
+ defer headCommit.Free()
index, err := NewIndex()
if err != nil {
@@ -47,7 +196,7 @@ func commitSomething(repo *Repository, something string) (*Oid, error) {
}
defer index.Free()
- blobOID, err := repo.CreateBlobFromBuffer([]byte("fou"))
+ blobOID, err := repo.CreateBlobFromBuffer([]byte(content))
if err != nil {
return nil, err
}
@@ -71,6 +220,7 @@ func commitSomething(repo *Repository, something string) (*Oid, error) {
if err != nil {
return nil, err
}
+ defer newTree.Free()
if err != nil {
return nil, err
@@ -92,76 +242,47 @@ func commitSomething(repo *Repository, something string) (*Oid, error) {
}
func entryExists(repo *Repository, file string) bool {
- head, err := repo.Head()
- if err != nil {
- return false
- }
- headCommit, err := repo.LookupCommit(head.Target())
- if err != nil {
- return false
- }
- headTree, err := headCommit.Tree()
+ headTree, err := headTree(repo)
if err != nil {
return false
}
+ defer headTree.Free()
+
_, err = headTree.EntryByPath(file)
return err == nil
}
-func TestRebaseOnto(t *testing.T) {
- repo := createTestRepo(t)
- defer cleanupTestRepo(t, repo)
-
- fileInMaster := "something"
- fileInEmile := "something else"
-
- // Seed master
- seedTestRepo(t, repo)
-
- // Create a new branch from master
- err := createBranch(repo, "emile")
- checkFatal(t, err)
-
- // Create a commit in master
- _, err = commitSomething(repo, fileInMaster)
- checkFatal(t, err)
-
- // Switch to this emile
- err = repo.SetHead("refs/heads/emile")
- checkFatal(t, err)
-
- // Check master commit is not in emile branch
- if entryExists(repo, fileInMaster) {
- t.Fatal("something entry should not exist in emile branch")
+func commitMsgsList(repo *Repository) ([]string, error) {
+ head, err := headCommit(repo)
+ if err != nil {
+ return nil, err
}
+ defer head.Free()
- // Create a commit in emile
- _, err = commitSomething(repo, fileInEmile)
- checkFatal(t, err)
-
- // Rebase onto master
- master, err := repo.LookupBranch("master", BranchLocal)
- branch, err := repo.AnnotatedCommitFromRef(master.Reference)
- checkFatal(t, err)
+ var commits []string
- rebase, err := repo.RebaseInit(nil, nil, branch, nil)
- checkFatal(t, err)
- defer rebase.Free()
+ parent := head.Parent(0)
+ defer parent.Free()
+ commits = append(commits, head.Message(), parent.Message())
- operation, err := rebase.Next()
- checkFatal(t, err)
-
- commit, err := repo.LookupCommit(operation.ID)
- checkFatal(t, err)
-
- err = rebase.Commit(operation.ID, signature(), signature(), commit.Message())
- checkFatal(t, err)
+ for parent.ParentCount() != 0 {
+ parent = parent.Parent(0)
+ defer parent.Free()
+ commits = append(commits, parent.Message())
+ }
- rebase.Finish()
+ return commits, nil
+}
- // Check master commit is now also in emile branch
- if !entryExists(repo, fileInMaster) {
- t.Fatal("something entry should now exist in emile branch")
+func assertStringList(t *testing.T, expected, actual []string) {
+ if len(expected) != len(actual) {
+ t.Fatal("Lists are not the same size, expected " + strconv.Itoa(len(expected)) +
+ ", got " + strconv.Itoa(len(actual)))
+ }
+ for index, element := range expected {
+ if element != actual[index] {
+ t.Error("Expected element " + strconv.Itoa(index) + " to be " + element + ", got " + actual[index])
+ }
}
}