diff options
-rw-r--r-- | options.go | 7 | ||||
-rw-r--r-- | repository.go | 19 | ||||
-rw-r--r-- | repository_test.go | 53 |
3 files changed, 79 insertions, 0 deletions
@@ -89,6 +89,13 @@ type CloneOptions struct { Shared bool } +// MergeOptions describes how a merge should be erformed +type MergeOptions struct { + // Requires a merge to be fast forward only. If this is true, then a merge will + // throw an error if ff is not possible. + FFOnly bool +} + // Validate validates the fields and sets the default values. func (o *CloneOptions) Validate() error { if o.URL == "" { diff --git a/repository.go b/repository.go index 1524a69..6ab40c0 100644 --- a/repository.go +++ b/repository.go @@ -1769,6 +1769,25 @@ func (r *Repository) RepackObjects(cfg *RepackConfig) (err error) { return nil } +// Merge attempts to merge ref onto HEAD. Currently only supports fast-forward merges +func (r *Repository) Merge(ref plumbing.Reference, opts MergeOptions) error { + if !opts.FFOnly { + return errors.New("non fast-forward merges are not supported yet") + } + + head, err := r.Head() + if err != nil { + return err + } + + ff, err := IsFastForward(r.Storer, head.Hash(), ref.Hash()) + if !ff { + return errors.New("fast forward is not possible") + } + + return r.Storer.SetReference(plumbing.NewHashReference(head.Name(), ref.Hash())) +} + // createNewObjectPack is a helper for RepackObjects taking care // of creating a new pack. It is used so the the PackfileWriter // deferred close has the right scope. diff --git a/repository_test.go b/repository_test.go index 51df845..bcfecc7 100644 --- a/repository_test.go +++ b/repository_test.go @@ -439,6 +439,59 @@ func (s *RepositorySuite) TestCreateBranchAndBranch(c *C) { c.Assert(branch.Merge, Equals, testBranch.Merge) } +func (s *RepositorySuite) TestMergeFF(c *C) { + r, _ := Init(memory.NewStorage(), memfs.New()) + err := r.clone(context.Background(), &CloneOptions{ + URL: s.GetBasicLocalRepositoryURL(), + }) + c.Assert(err, IsNil) + head, err := r.Head() + c.Assert(err, IsNil) + + mergeBranchRefname := plumbing.NewBranchReferenceName("foo") + err = r.Storer.SetReference(plumbing.NewHashReference(mergeBranchRefname, head.Hash())) + c.Assert(err, IsNil) + + commit, err := r.CommitObject(head.Hash()) + c.Assert(err, IsNil) + treeHash := commit.TreeHash + + hash := commit.Hash + + for i := 0; i < 10; i++ { + commit = &object.Commit{ + Author: object.Signature{ + Name: "A U Thor", + Email: "author@example.com", + }, + Committer: object.Signature{ + Name: "A U Thor", + Email: "author@example.com", + }, + Message: fmt.Sprintf("commit #%d", i), + TreeHash: treeHash, + ParentHashes: []plumbing.Hash{ + hash, + }, + } + + o := r.Storer.NewEncodedObject() + c.Assert(commit.Encode(o), IsNil) + hash, err = r.Storer.SetEncodedObject(o) + } + + mergeBranchRef := plumbing.NewHashReference(mergeBranchRefname, hash) + c.Assert(r.Storer.SetReference(mergeBranchRef), IsNil) + + err = r.Merge(*mergeBranchRef, MergeOptions{ + FFOnly: true, + }) + c.Assert(err, IsNil) + + head, err = r.Head() + c.Assert(head.Hash(), Equals, mergeBranchRef.Hash()) +} + func (s *RepositorySuite) TestCreateBranchUnmarshal(c *C) { r, _ := Init(memory.NewStorage(), nil) |