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 }