// +build static,system_libgit2 package main import ( "errors" "flag" "fmt" "os" "strings" "time" git "github.com/libgit2/git2go/v30" "gitlab.com/gitlab-org/gitaly/internal/git2go" ) type mergeSubcommand struct { request string } func (cmd *mergeSubcommand) Flags() *flag.FlagSet { flags := flag.NewFlagSet("merge", flag.ExitOnError) flags.StringVar(&cmd.request, "request", "", "git2go.MergeCommand") return flags } func sanitizeSignatureInfo(info string) string { return strings.Map(func(r rune) rune { switch r { case '<', '>', '\n': return -1 default: return r } }, info) } func (cmd *mergeSubcommand) Run() error { request, err := git2go.MergeCommandFromSerialized(cmd.request) if err != nil { return err } if request.AuthorDate.IsZero() { request.AuthorDate = time.Now() } repo, err := git.OpenRepository(request.Repository) if err != nil { return fmt.Errorf("could not open repository: %w", err) } defer repo.Free() ours, err := lookupCommit(repo, request.Ours) if err != nil { return fmt.Errorf("could not lookup commit %q: %w", request.Ours, err) } theirs, err := lookupCommit(repo, request.Theirs) if err != nil { return fmt.Errorf("could not lookup commit %q: %w", request.Theirs, err) } index, err := repo.MergeCommits(ours, theirs, nil) if err != nil { return fmt.Errorf("could not merge commits: %w", err) } defer index.Free() if index.HasConflicts() { return errors.New("could not auto-merge due to conflicts") } tree, err := index.WriteTreeTo(repo) if err != nil { return fmt.Errorf("could not write tree: %w", err) } committer := git.Signature{ Name: sanitizeSignatureInfo(request.AuthorName), Email: sanitizeSignatureInfo(request.AuthorMail), When: request.AuthorDate, } commit, err := repo.CreateCommitFromIds("", &committer, &committer, request.Message, tree, ours.Id(), theirs.Id()) if err != nil { return fmt.Errorf("could not create merge commit: %w", err) } response := git2go.MergeResult{ CommitID: commit.String(), } if err := response.SerializeTo(os.Stdout); err != nil { return err } return nil }