aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Cai <jcai@gitlab.com>2022-01-05 16:28:46 -0500
committerPaulo Gomes <paulo.gomes@suse.com>2024-03-09 08:57:47 +0000
commit4bed23037f0e374d85bce1506e9df98ce0cfcd32 (patch)
tree71bab2968373e3d3586a08dff4bab623bccfdd10
parentd9497bae668afcc540fa6f2177575777b3ff91de (diff)
downloadgo-git-4bed23037f0e374d85bce1506e9df98ce0cfcd32.tar.gz
git: Add Merge with ff-only
Add a Merge function that behaves like git merge. This is a first iteration that only supports --ff-only, which is the simplest type of merge.
-rw-r--r--options.go7
-rw-r--r--repository.go19
-rw-r--r--repository_test.go53
3 files changed, 79 insertions, 0 deletions
diff --git a/options.go b/options.go
index 635a883..6a7963f 100644
--- a/options.go
+++ b/options.go
@@ -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)