Add git-status-report: recursive git repo scanner with status reporting
Scans a directory tree for git repos and produces a concise report showing uncommitted changes (with +/- character counts) and ahead/behind status per remote. Supports --dryrun to preview discovered repos without running checks. Includes OpenSpec, implementation, and 26-assertion test suite. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
103
specs/git-status-report.spec.md
Normal file
103
specs/git-status-report.spec.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# git-status-report
|
||||
|
||||
## Purpose
|
||||
|
||||
Recursively scan a directory tree for git repositories and produce a concise report showing uncommitted changes and remote sync status.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
git-status-report [OPTIONS] [DIRECTORY]
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
| Argument | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `DIRECTORY` | `.` (current directory) | Root directory to scan |
|
||||
|
||||
### Flags
|
||||
|
||||
| Flag | Short | Description |
|
||||
|------|-------|-------------|
|
||||
| `--dryrun` | `-n` | List discovered repos without running status checks |
|
||||
| `--help` | `-h` | Show usage information |
|
||||
|
||||
## Behaviour
|
||||
|
||||
1. **Discovery phase:** Walk `DIRECTORY` recursively, identifying directories that contain a `.git` folder. Stop descending into a directory once a `.git` is found (don't scan nested repos inside a git worktree).
|
||||
|
||||
2. **Status phase:** For each discovered repo:
|
||||
a. Run `git status --porcelain` to detect uncommitted changes (staged, unstaged, untracked).
|
||||
b. For each changed file, compute the character-level diff: `+N` added, `-N` removed. For untracked files, count all characters as `+N`. For deleted files, count all characters as `-N`.
|
||||
c. Run `git remote` to list remotes. For each remote, run `git rev-list --left-right --count <branch>...<remote>/<remote-branch>` to determine ahead/behind counts.
|
||||
|
||||
3. **Report phase:** Print a grouped report:
|
||||
- **Clean repos** are listed in a single summary line (count only) unless there are none.
|
||||
- **Dirty repos** get a section each, showing:
|
||||
- Repo path (relative to `DIRECTORY`)
|
||||
- Each changed file with its status and `+N / -N` character counts
|
||||
- Ahead/behind status per remote/branch
|
||||
- **Repos with remote divergence** (ahead or behind) but no local changes still get a section showing the ahead/behind status.
|
||||
|
||||
4. **Exit code:**
|
||||
- `0` — all repos clean and in sync
|
||||
- `1` — at least one repo has uncommitted changes or is out of sync
|
||||
|
||||
## Dryrun Behaviour
|
||||
|
||||
When `--dryrun` is passed:
|
||||
- Perform the discovery phase only
|
||||
- Print each discovered repo path (relative to `DIRECTORY`), one per line
|
||||
- Prefix output with `[dryrun] Would check N repositories:`
|
||||
- Do NOT run any git status or remote checks
|
||||
- Exit code is always `0`
|
||||
|
||||
## Edge Cases
|
||||
|
||||
| Scenario | Handling |
|
||||
|----------|----------|
|
||||
| No git repos found | Print "No git repositories found in <dir>" and exit 0 |
|
||||
| Repo has no remotes | Skip remote sync section for that repo, show "(no remotes)" |
|
||||
| Repo has detached HEAD | Show branch as `(detached HEAD)` and skip remote comparison |
|
||||
| Remote branch doesn't exist | Show "(no upstream)" for that remote |
|
||||
| Binary files changed | Show `(binary)` instead of character counts |
|
||||
| Permission denied on subdirectory | Skip with warning to stderr, continue scanning |
|
||||
| Nested git repos (submodules) | Stop at the outermost `.git` — don't descend further |
|
||||
| Symlinked directories | Follow symlinks during discovery |
|
||||
|
||||
## Examples
|
||||
|
||||
### Clean repos
|
||||
```
|
||||
Scanned 5 repositories in ~/dev
|
||||
|
||||
✓ All 5 repositories are clean and in sync.
|
||||
```
|
||||
|
||||
### Mixed status
|
||||
```
|
||||
Scanned 5 repositories in ~/dev
|
||||
|
||||
── dirty: project-alpha ──
|
||||
M src/main.py +42 / -17
|
||||
M README.md +5 / -0
|
||||
?? TODO.txt +120
|
||||
↕ origin/main: 2 ahead, 0 behind
|
||||
|
||||
── dirty: infra-configs ──
|
||||
D old-config.yaml -89
|
||||
↕ origin/main: 0 ahead, 3 behind
|
||||
|
||||
✓ 3 repositories are clean and in sync.
|
||||
```
|
||||
|
||||
### Dryrun
|
||||
```
|
||||
[dryrun] Would check 5 repositories:
|
||||
~/dev/project-alpha
|
||||
~/dev/project-beta
|
||||
~/dev/infra-configs
|
||||
~/dev/scripts
|
||||
~/dev/docs
|
||||
```
|
||||
Reference in New Issue
Block a user