Files
small-scripts/specs/git-status-report.spec.md
Paul O'Reilly 5230e54236 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>
2026-03-13 11:13:59 +13:00

3.5 KiB

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 " 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