This commit is contained in:
2026-06-23 05:02:15 +08:00
commit e6f1776d4f
264 changed files with 54215 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
package git
import (
"context"
"strings"
)
// HasChanges reports whether the working tree at workspaceRoot has any
// uncommitted changes (staged, unstaged, or untracked).
func HasChanges(ctx context.Context, workspaceRoot string) (bool, error) {
out, _, err := runGit(ctx, workspaceRoot, "status", "--porcelain")
if err != nil {
return false, err
}
return strings.TrimSpace(out) != "", nil
}
// MergePreviewOpts carries options for MergePreview.
type MergePreviewOpts struct {
WorkspaceRoot string
Branch string // branch to preview-merge into HEAD
}
// MergePreviewResult holds the outcome of a preview merge attempt.
// When Clean is false, Conflicts lists the raw CONFLICT lines from git output.
// Faithful to the TS implementation: the repo is left in merge-in-progress
// state so the caller can inspect it; run `git merge --abort` to undo.
type MergePreviewResult struct {
Clean bool
Conflicts []string
Output string
}
// MergePreview runs git merge --no-commit --no-ff <Branch> in WorkspaceRoot.
// On success (no conflicts) Clean is true. On conflict, Clean is false and
// Conflicts lists the CONFLICT lines from git output.
func MergePreview(ctx context.Context, opts MergePreviewOpts) (MergePreviewResult, error) {
stdout, stderr, err := runGit(ctx, opts.WorkspaceRoot, "merge", "--no-commit", "--no-ff", opts.Branch)
combined := strings.TrimSpace(stdout + "\n" + stderr)
if err == nil {
return MergePreviewResult{Clean: true, Output: combined}, nil
}
var conflicts []string
for _, line := range strings.Split(combined, "\n") {
// git outputs "CONFLICT" in English or "冲突" in localized builds.
if strings.HasPrefix(line, "CONFLICT") || strings.Contains(line, "冲突") {
conflicts = append(conflicts, line)
}
}
return MergePreviewResult{
Clean: false,
Conflicts: conflicts,
Output: combined,
}, err
}