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>
104 lines
3.5 KiB
Markdown
104 lines
3.5 KiB
Markdown
# 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
|
|
```
|