Files
simplegit/gitcmd/merge.go
T
2026-07-15 11:06:48 -04:00

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
}