82 lines
2.2 KiB
Go
82 lines
2.2 KiB
Go
package gitcmd
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os/exec"
|
|
"strings"
|
|
)
|
|
|
|
type MergeResult struct {
|
|
Base string `json:"base"`
|
|
Head string `json:"head"`
|
|
MergeCommit *Commit `json:"merge_commit,omitempty"`
|
|
FastForward bool `json:"fast_forward"`
|
|
Conflicts []string `json:"conflicts,omitempty"`
|
|
}
|
|
|
|
func (r *Repository) Merge(base, head, message, authorName, authorEmail string, noFF bool) (*MergeResult, error) {
|
|
baseSHA, err := r.refSHA("refs/heads/" + base)
|
|
if err != nil || baseSHA == "" {
|
|
return nil, fmt.Errorf("base branch %q not found", base)
|
|
}
|
|
headSHA, err := r.refSHA("refs/heads/" + head)
|
|
if err != nil || headSHA == "" {
|
|
return nil, fmt.Errorf("head branch %q not found", head)
|
|
}
|
|
|
|
if !noFF && r.isAncestor(baseSHA, headSHA) {
|
|
if err := r.updateRef("refs/heads/"+base, headSHA, baseSHA); err != nil {
|
|
return nil, err
|
|
}
|
|
hc, err := r.GetCommit(headSHA)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &MergeResult{Base: base, Head: head, MergeCommit: hc, FastForward: true}, nil
|
|
}
|
|
|
|
out, _, err := NewCommand("merge-tree", "--write-tree", "-z", "--name-only", "--no-messages").
|
|
AddDynamicArguments(baseSHA, headSHA).
|
|
WithDir(r.Path).RunStdString(r.ctx)
|
|
|
|
conflict := false
|
|
if err != nil {
|
|
var exitErr *exec.ExitError
|
|
if errors.As(err, &exitErr) && exitErr.ExitCode() == 1 {
|
|
conflict = true
|
|
} else {
|
|
return nil, fmt.Errorf("merge-tree: %w", err)
|
|
}
|
|
}
|
|
|
|
parts := strings.Split(out, "\x00")
|
|
if len(parts) == 0 || strings.TrimSpace(parts[0]) == "" {
|
|
return nil, fmt.Errorf("merge-tree: empty output")
|
|
}
|
|
mergedTree := strings.TrimSpace(parts[0])
|
|
|
|
if conflict {
|
|
var conflicts []string
|
|
for i := 1; i < len(parts); i++ {
|
|
if p := strings.TrimSpace(parts[i]); p != "" {
|
|
conflicts = append(conflicts, p)
|
|
}
|
|
}
|
|
return &MergeResult{Base: base, Head: head, Conflicts: conflicts}, nil
|
|
}
|
|
|
|
commitSHA, err := r.commitTree(mergedTree, message, authorName, authorEmail, r.Path, baseSHA, headSHA)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := r.updateRef("refs/heads/"+base, commitSHA, baseSHA); err != nil {
|
|
return nil, err
|
|
}
|
|
mc, err := r.GetCommit(commitSHA)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &MergeResult{Base: base, Head: head, MergeCommit: mc}, nil
|
|
}
|