You've already forked agentic-coding-workflow
48 lines
1.1 KiB
Go
48 lines
1.1 KiB
Go
package git
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
)
|
|
|
|
// Status 返回 git status --porcelain=v1 的结构化解析。空 worktree 返回空切片。
|
|
func (r *DefaultRunner) Status(ctx context.Context, dir string) ([]FileStatus, error) {
|
|
ctx, cancel := withCtx(ctx, r.cfg.OpsTimeout)
|
|
defer cancel()
|
|
out, _, err := r.exec(ctx, dir, nil, "status", "--porcelain=v1", "-z")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return parsePorcelainV1(out), nil
|
|
}
|
|
|
|
// parsePorcelainV1 解析 -z 输出(NUL 分隔,不转义)。
|
|
// 每条记录格式:XY <SP> <path>\0
|
|
// renamed/copied 时是 XY <SP> <to>\0<from>\0;本实现把 to 当 path,丢弃 from。
|
|
func parsePorcelainV1(buf []byte) []FileStatus {
|
|
var out []FileStatus
|
|
for len(buf) > 0 {
|
|
nul := bytes.IndexByte(buf, 0)
|
|
if nul < 0 {
|
|
break
|
|
}
|
|
rec := buf[:nul]
|
|
buf = buf[nul+1:]
|
|
if len(rec) < 4 {
|
|
continue
|
|
}
|
|
x, y := rec[0], rec[1]
|
|
// rec[2] 是空格
|
|
path := string(rec[3:])
|
|
out = append(out, FileStatus{Path: path, IndexX: x, WorktreeY: y})
|
|
// renamed/copied:跳过 from 段
|
|
if x == 'R' || x == 'C' {
|
|
nul = bytes.IndexByte(buf, 0)
|
|
if nul >= 0 {
|
|
buf = buf[nul+1:]
|
|
}
|
|
}
|
|
}
|
|
return out
|
|
}
|