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 \0 // renamed/copied 时是 XY \0\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 }