Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <psteinhardt@gitlab.com>2021-01-13 12:59:44 +0300
committerPatrick Steinhardt <psteinhardt@gitlab.com>2021-01-26 10:07:59 +0300
commit16af76ac3004eee3ed9a92e19b3769e73f610088 (patch)
treeb3fdfd37b683c29d397d86135eac0dde0952f252
parent232df1394c114a6ef2d844d572e0493bf4a6e60d (diff)
git2go: Implement handling of AllowConflicts for UserMergeToRef
While we ported the UserMergeToRef RPC to Go, a new flag "allow_conflicts" was added to its request. What it does is that instead of raising an error when there's any conflict, the RPC will now commit the conflicting file together with its conflict markers. Given that both efforts kind of crossed, the parameter isn't supported by the Go implementation nowadays. This commit lays the groundwork to support it.
-rw-r--r--cmd/gitaly-git2go/merge.go74
-rw-r--r--internal/git2go/merge.go3
2 files changed, 76 insertions, 1 deletions
diff --git a/cmd/gitaly-git2go/merge.go b/cmd/gitaly-git2go/merge.go
index 907e717c0..dc9efd808 100644
--- a/cmd/gitaly-git2go/merge.go
+++ b/cmd/gitaly-git2go/merge.go
@@ -12,6 +12,7 @@ import (
"time"
git "github.com/libgit2/git2go/v30"
+ "gitlab.com/gitlab-org/gitaly/cmd/gitaly-git2go/conflicts"
"gitlab.com/gitlab-org/gitaly/internal/git2go"
)
@@ -64,7 +65,13 @@ func (cmd *mergeSubcommand) Run(context.Context, io.Reader, io.Writer) error {
defer index.Free()
if index.HasConflicts() {
- return errors.New("could not auto-merge due to conflicts")
+ if !request.AllowConflicts {
+ return errors.New("could not auto-merge due to conflicts")
+ }
+
+ if err := resolveConflicts(repo, index); err != nil {
+ return fmt.Errorf("could not resolve conflicts: %w", err)
+ }
}
tree, err := index.WriteTreeTo(repo)
@@ -88,3 +95,68 @@ func (cmd *mergeSubcommand) Run(context.Context, io.Reader, io.Writer) error {
return nil
}
+
+func resolveConflicts(repo *git.Repository, index *git.Index) error {
+ // We need to get all conflicts up front as resolving conflicts as we
+ // iterate breaks the iterator.
+ indexConflicts, err := getConflicts(index)
+ if err != nil {
+ return err
+ }
+
+ for _, conflict := range indexConflicts {
+ merge, err := conflicts.Merge(repo, conflict)
+ if err != nil {
+ return err
+ }
+
+ mergedBlob, err := repo.CreateBlobFromBuffer(merge.Contents)
+ if err != nil {
+ return err
+ }
+
+ mergedIndexEntry := git.IndexEntry{
+ Path: merge.Path,
+ Mode: git.Filemode(merge.Mode),
+ Id: mergedBlob,
+ }
+
+ if err := index.Add(&mergedIndexEntry); err != nil {
+ return err
+ }
+
+ if err := index.RemoveConflict(merge.Path); err != nil {
+ return err
+ }
+ }
+
+ if index.HasConflicts() {
+ return errors.New("index still has conflicts")
+ }
+
+ return nil
+}
+
+func getConflicts(index *git.Index) ([]git.IndexConflict, error) {
+ var conflicts []git.IndexConflict
+
+ iterator, err := index.ConflictIterator()
+ if err != nil {
+ return nil, err
+ }
+ defer iterator.Free()
+
+ for {
+ conflict, err := iterator.Next()
+ if err != nil {
+ if git.IsErrorCode(err, git.ErrIterOver) {
+ break
+ }
+ return nil, err
+ }
+
+ conflicts = append(conflicts, conflict)
+ }
+
+ return conflicts, nil
+}
diff --git a/internal/git2go/merge.go b/internal/git2go/merge.go
index 7659930a1..e92856810 100644
--- a/internal/git2go/merge.go
+++ b/internal/git2go/merge.go
@@ -37,6 +37,9 @@ type MergeCommand struct {
Ours string `json:"ours"`
// Theirs is the commit into which ours is to be merged.
Theirs string `json:"theirs"`
+ // AllowConflicts controls whether conflicts are allowed. If they are,
+ // then conflicts will be committed as part of the result.
+ AllowConflicts bool `json:"allow_conflicts"`
}
// MergeResult contains results from a merge.