Implement the core data layer that everything else builds on: walking a parent directory for Git repositories and snapshotting each repository's state via porcelain commands. Domain model (pkg/status): - RepoStatus enum with zero value = StatusUnknown (invalid/unset), covering clean / modified / ahead / behind / diverged / detached / bare / error - RepoInfo snapshot: path, name, remote URL, branch, detached flag, staged / modified / untracked file lists, ahead/behind counts, stash count, error - ScanResult with computed Summary counters and NeedsAttention filter Git wrapper (internal/git): - Executor built with functional options (binary, timeout, env), defaults to "git" with a 10s per-command timeout so a hung repository can never stall a scan; context cancellation honoured via exec.CommandContext - Status() validates with rev-parse --is-bare-repository (bare repos are reported as StatusBare and skipped), then parses `git status --porcelain=v2 --branch -z` - Parsing uses the NUL-separated v2 format so paths with spaces, quotes, and tabs survive verbatim (no C-quoting to decode); rename records (type 2) and ahead/behind lines (# branch.ab) are handled, unknown tokens are ignored for forward compatibility - Best-effort remote URL (git config --get-regexp) and stash count Discovery (internal/scanner/discover.go): - WalkDir-based traversal that never descends into .git internals - Detects working trees via .git directory or .git pointer file (linked worktrees, submodule checkouts) and bare repos via a *.git directory carrying its own HEAD/objects/refs - WithExclude glob patterns (matched against full path and base name) and WithMaxDepth depth limiting as functional options - Walk errors (e.g. permission denied) are aggregated and returned alongside partial results via errors.Join; cancellation is propagated Scanner (internal/scanner/scanner.go): - Concurrent status scanning with a bounded worker pool (errgroup + SetLimit, default 8 workers) - Per-repo failures become StatusError entries instead of aborting the pass; a cancelled context aborts the whole scan Testing: - Table-driven parser tests with canned NUL-separated porcelain output - Integration tests against a real git binary (clean / modified / staged / stashed / detached / bare / non-repo) - Discovery tests over a fixture tree with nested repos, a bare repo, a linked worktree, and an exclusion target - Scanner tests for mixed success/failure, bounded concurrency, and cancellation; everything runs under -race Note: LastFetch from the original plan was dropped — the only reliable source is a reflog of the remote-tracking ref, which does not exist on fresh clones, so it would always be misleading. The model remains extensible if a fetch-history feature is wanted later. |
||
|---|---|---|
| .github/workflows | ||
| cmd/gitflow | ||
| internal | ||
| pkg/status | ||
| .gitignore | ||
| .golangci.yml | ||
| go.mod | ||
| go.sum | ||
| implementation.md | ||
| Makefile | ||
| readme.md | ||
git flow is CLI app writen go.
App will explore [] all git repos leaving on our machine. it will ask for parent directory. will scan status of our repos and present it to the user. app will scan repos in set interval [and present findings, integrated ai agent will suggest next steps/actions]