gitomb
Turn forgotten Git branches and stashes into a cleanup list you can review.
gitomb scans local repositories, combines Git evidence with optional TypeSafe Jev assessments, and helps you decide what to keep. You select the items to remove. gitomb backs them up before deletion and can restore them by batch.
No API key is required for Git-only scans.
| Command | Purpose | Changes Git refs? |
|---|---|---|
gitomb scan |
Scan repositories and save a report | No |
gitomb show |
Inspect a saved report or a local diff | No |
gitomb clean |
Select, confirm, back up, and remove items | Yes, unless --dry-run |
gitomb batches |
List cleanup batches | No |
gitomb restore |
Restore a cleanup batch | Yes |
Quick start
Requires Python 3.11+, Git, uv, and macOS or Linux. Windows is not supported yet because cleanup uses POSIX file locks.
1. Install
uv tool install gitomb
gitomb --help
gitomb scan /path/to/your/repo --no-ai
Replace /path/to/your/repo with a repository you want to inspect. If your shell cannot find gitomb, run uv tool update-shell and restart the terminal.
To upgrade, run uv tool upgrade gitomb. To uninstall, run uv tool uninstall gitomb.
Scanning does not delete, fetch, or check out anything. It saves a report for subsequent show and clean commands.
2. Enable Jev assessments (optional)
Get an API key from TypeSafe. Create or edit .env in the directory where you will run gitomb:
TYPESAFE_API_KEY=your-api-key
Then scan with Jev:
gitomb scan /path/to/your/repo --ai
An existing TYPESAFE_API_KEY environment variable takes precedence over .env. The default .env is read from the directory where you run the command, not from each scanned repository. Use --env-file /path/to/.env for a different location.
Keep .env out of version control. The gitomb source repository already ignores it; configure your own repository accordingly. Do not commit your key. Jev calls use your own TypeSafe account quota.
| Mode | Behavior |
|---|---|
| Default | Use Jev when a key is available; otherwise use Git rules |
--no-ai |
Use local Git evidence only; make no Jev requests |
--ai |
Require a key; individual API failures still fall back to Git rules |
Install from source instead
git clone https://github.com/PaulChen79/gitomb.git
cd gitomb
uv sync --locked
uv tool install .
gitomb scan /path/to/your/repo --env-file /path/to/gitomb/.env
After updating the source checkout, reinstall with uv tool install --reinstall .. The examples below use the standalone gitomb command.
Usage
Scan one or more repositories
gitomb scan ~/projects ~/work --no-ai
gitomb scan /path/to/repo --base develop
gitomb scan /path/to/repo --ai --include-diff
Without a path, gitomb scans the current directory. Discovery searches six directory levels by default, deduplicates linked worktrees, skips directories such as .git, .venv, and node_modules, and does not follow directory symlinks.
Example report, simplified for readability. IDs and data are illustrative:
# ID Repository / item Age Action Evidence / Jev
1 a1b2c3d4e5f6 billing / branch: fix/log 90d cleanup-candidate merged; no unique commits
2 b2c3d4e5f6a1 portal / branch: experiment 120d review 3 unique commits
3 c3d4e5f6a1b2 infra / stash: stash@{0} 45d review stash contents require review
Scan: 20260923T080000Z-abcd1234
Saved: .../gitomb/scans/20260923T080000Z-abcd1234.json
Review the report and diffs
gitomb show
gitomb show ITEM_ID --diff
gitomb show ITEM_ID --scan SCAN_ID --diff
Replace ITEM_ID with an ID from the report; unique prefixes are accepted. show --diff displays the full diff locally without sending it to Jev.
show and clean use the latest saved scan, not a fresh scan of the current directory. Specify --scan SCAN_ID to use a particular report.
Select and confirm cleanup
gitomb clean
Enter comma-separated row numbers, such as 1,3. Review the selected items, then type clean 2 to confirm two deletions. An empty selection cancels. Protected branches and branches in use by a worktree cannot be removed.
For explicit selection, use item IDs. Preview the operation first:
gitomb clean --ids ITEM_ID ANOTHER_ID --dry-run
gitomb clean --ids ITEM_ID ANOTHER_ID
Branches with commits not reachable from the comparison branch require an additional flag:
gitomb clean --ids ITEM_ID --allow-unmerged
--allow-unmerged does not bypass branch protection, worktree checks, or confirmation. Stashes always require your review, but do not use the branch-specific --allow-unmerged flag.
--dry-run validates eligibility without creating backups or deleting anything. Actual cleanup checks the state again. Noninteractive cleanup requires both explicit --ids and --yes.
Restore a batch
gitomb batches
gitomb restore BATCH_ID
Use the batch ID printed by clean. Restoration recreates branches and adds stashes back to the stash list. It does not apply stashes to your working tree.
Interrupted or partially successful operations also appear in batches. Use the same batch ID to restore any items with valid backups.
How it works
Local repositories
|
v
Git evidence + optional Jev assessments
|
v
Saved report -> Your selection -> State checks -> Backup -> Cleanup
|
v
Batch restoration
Git provides facts: commit age, ancestry, unique commits, upstream refs, worktree usage, file names, and diff statistics. Jev handles narrower semantic questions about the changes:
| Question | Primitive | Result |
|---|---|---|
| What is the purpose of this work? | Choice | temporary-debug, experiment, feature-or-fix, maintenance, or unknown |
| Does the evidence show unfinished work? | Noul | Probability from 0 to 1 |
| Is the context insufficient to determine the purpose? | Noul | Probability from 0 to 1 |
The application combines these answers with Git rules. Jev can influence review order and suggest keeping unfinished work; it never authorizes deletion.
| Recommendation | Meaning |
|---|---|
cleanup-candidate |
Git confirms the branch is merged into the comparison branch with no unique commits; selection is still manual |
review |
Unique work, a stash, or evidence that needs your judgment |
keep |
Protected or checked-out branch, or model evidence of unfinished work |
Percentages describe model probabilities about purpose, not deletion safety or the author's intent to abandon work. Confidence is stored separately in the report JSON. Thresholds are initial policy choices, not a calibration established on your repositories.
The comparison branch defaults to the locally recorded origin/HEAD, then local main, master, or develop. Override it with --base. Missing comparison branches are not treated as proof of a merge. Remote-tracking refs may be stale because gitomb does not fetch.
Squash merges are not considered proven ancestry merges. Age is time since the last commit, not the last checkout, edit, or review.
Data sent to Jev
When enabled, gitomb assesses items that are not protected, checked out, or already proven merged. Each item gets one request containing all three questions. Requests run with bounded concurrency, four at a time by default.
By default, requests contain names, commit messages, age, Git evidence, file names, and diff statistics. gitomb does not add the repository's absolute path or patch bodies to the request.
--include-diff additionally sends filtered excerpts from up to 20 files, capped at 12,000 characters. Common sensitive paths are excluded and recognizable credential patterns are redacted. This is best-effort filtering, not a guarantee that all secrets are detected. Names, messages, paths, and source code can contain private information; choose the appropriate mode for your repositories.
Untracked stash files are listed, but their contents are not currently included in Jev patch excerpts. show --diff is local only.
Assessments are cached by model name and input. Use --refresh to bypass the cache, including after the jev-latest alias changes, or use --model to select a specific version. Reports record the actual model returned by the API. API failures appear beside the affected item, with Git rules still available.
Configuration
gitomb scan --config gitomb.example.toml
gitomb scan ~/projects --no-ai --json > scan.json
gitomb --state-dir .gitomb scan /path/to/repo --no-ai
gitomb --state-dir .gitomb clean
Configuration files are loaded only when supplied through --config. See gitomb.example.toml.
| Setting / flag | Default | Meaning |
|---|---|---|
roots / positional paths |
Current directory | Discovery roots |
base / --base |
Automatic | Comparison branch for this scan |
protect / --protect |
Built-in patterns | Additional protected globs; quote *; the flag can be repeated |
stale_days / --stale-days |
90 |
Age annotation threshold, not a deletion threshold |
max_depth / --max-depth |
6 |
Discovery depth; 0 checks only the roots |
model / --model |
jev-latest |
Model name or version |
--workers |
4 |
Concurrent Jev requests, from 1 to 16; CLI only |
--refresh |
Off | Bypass the Jev cache; CLI only |
--env-file |
.env in the current directory |
Key file; the environment variable takes precedence |
--include-diff |
Off | Send filtered patch excerpts; requires Jev and a key |
--json |
Off | Report JSON on stdout; progress on stderr |
--state-dir |
See below | Global option; place it before the subcommand |
CLI arguments override configuration values; protected patterns are combined. Use separate scans and scan IDs when repositories need different comparison branches.
State lives in $XDG_STATE_HOME/gitomb, or ~/.local/state/gitomb when unset:
| Directory | Contents |
|---|---|
scans/ |
Saved evidence and assessments |
cache/ |
Reusable Jev assessments |
batches/ |
Cleanup and recovery journals |
Data files are created with owner-only read/write permissions. Keep both the journals and the original repositories' .git directories for recovery.
Recovery behavior and limitations
main,master,develop,development,release, andrelease/*are protected, along with a scan's local comparison branch and symbolic branch refs. Add patterns with--protect.- Cleanup rechecks branch tips, comparison refs, and worktrees. Branch deletion compares the expected object ID before removing the ref.
- Before deleting each item, gitomb creates
refs/gitomb/<batch>/<item>and persists a journal. These refs keep reachable Git objects alive through garbage collection, including stash index and untracked-file parents. - Each stash is located again by object ID before deletion. Ambiguous duplicate object IDs are rejected.
- gitomb operations on the same repository are locked against each other. External Git commands do not share this lock. Avoid concurrent checkouts, worktree changes, or stash push/drop operations during cleanup.
- Batches can partially succeed. Failures are reported per item; operations across repositories are not atomic.
- Restoration will not overwrite a branch name now pointing to a different commit. Restored stash positions can change. Retrying a restored batch does not duplicate its stashes.
- Branch tips and reachable contents are retained; old branch reflog history is not. Local branch configuration is left in place for restoration.
- Backup refs remain after restoration. There is no automatic backup pruning, so cleanup may not reclaim disk space.
- gitomb does not delete remote branches, push changes, or discover bare repositories.
Troubleshooting
| Symptom | What to do |
|---|---|
| Key not found | Check the current directory or use --env-file; use --no-ai for local-only operation |
Jev unavailable |
Check the reported error class, key, network, or quota, then rescan with --refresh |
| No comparison branch | Set scan --base develop or another explicit branch |
| Branch or comparison branch changed | Scan again and review the new result before cleaning |
| Branch checked out in a worktree | Keep it; gitomb will not switch or remove worktrees for you |
Squash-merged branch remains review |
Inspect its diff; ancestry alone does not prove the merge |
| Restore reports a conflicting branch name | Resolve the name conflict, then retry the same batch |
Development
Clone the repository and run these commands from the checkout. To run source changes without reinstalling the standalone tool, use uv run gitomb ....
uv sync --locked
uv run pytest -q
uv run ruff check src tests
uv run ruff format --check src tests
uv build
Tests use temporary Git repositories for cleanup, restoration, untracked stash contents, garbage collection, worktrees, changed state, interrupted operations, and name conflicts. SDK contract tests use the real TypeSafe SDK with a mock HTTP transport. They do not require an API key or spend API credits.
Contributing
Contributions are welcome! Bug reports, feature ideas, documentation fixes, usability feedback, and pull requests all help.
Use Issues to report a problem or discuss an idea. Include your OS, Python/Git/gitomb versions, reproduction steps, expected behavior, and sanitized output.
For a pull request, fork the repository, create a focused branch from main, make your change, and run the checks above. Small fixes can go straight to a PR; discuss larger behavior or design changes in an issue first. Explain the problem, resulting behavior, and validation in the PR description.
Useful areas to contribute include terminal interaction, squash-merge evidence, Jev assessment quality, platform support, and examples. Please keep each PR focused and include behavior tests for changes to cleanup or recovery.
License
Licensed under the MIT License.
Metadata
Release files for gitomb 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| gitomb-0.1.0.tar.gz | 39.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| gitomb-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 62.1 kB
Release files / gitomb-0.1.0.tar.gz
| Download URL | gitomb-0.1.0.tar.gz |
|---|---|
| Size | 39.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0e1a76b21de6bad958b8b18d92a859c0168e4a0ca0eaa1820df90355867d4bf6
|
|
BLAKE2b-256 checksum How to use checksums |
410b50b59ed975c65790b2a3d177919f1aee5732e402e0c79c2a8337a8dd0ae5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / gitomb-0.1.0-py3-none-any.whl
| Download URL | gitomb-0.1.0-py3-none-any.whl |
|---|---|
| Size | 22.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7d3cba2ba218b9db53fee04c244c30e74bfaa335aef1cfc967ddb0ef14372f3a
|
|
BLAKE2b-256 checksum How to use checksums |
c8c9006a4f71d614fd7fa8b89103143d4ad14952f4fc0aed637fb992a07abedb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|