# 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 .../` 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 ```