gitrot is a local CLI for detecting semantic decay from Git history.
It currently covers:
- Dissonance Drift: a file keeps changing while historically coupled files are left behind.
- Tangled Commit Detection: staged files in one commit have low historical cohesion.
- Context Loss (Knowledge Silo): drift is driven by authors with no historical overlap on the coupled file pair.
- Knowledge Map: quick coupling and ownership discovery for a specific file.
- Refactoring Hotspots: files with high churn and high coupling degree.
go install github.com/x0ptr/gitrot/cmd/gitrot@latestgitrot init
gitrot status [--history 2000] [--min-coupling 60] [--min-cohesion 30] [--min-shared 3] [--min-drift 2] [--max-files 30] [--ignore-tangled] [--ignore-silo] [--hide-name] [--ignore-dotfiles]
gitrot staged [--history 2000] [--min-coupling 60] [--min-cohesion 30] [--max-files 30] [--ignore-tangled] [--ignore-silo] [--hide-name] [--ignore-dotfiles]
gitrot map [--hide-name] [--ignore-dotfiles] <file_path>
gitrot hotspot [--history 2000] [--min-coupling 60] [--max-files 30] [--limit 10] [--hide-name] [--ignore-dotfiles] [path]
gitrot ack <file_path>status analyzes commit history and prints drift findings.
When enabled (default), it also evaluates staged cohesion at the end and prints a warning if the staged set looks atypical.
Unlike staged, status does not fail the process for tangled commits.
For each drift finding (A -> B):
HistoricalAuthors: authors who historically committedAandBtogether.DriftAuthors: authors from drift commits onA(includingCo-authored-byandReviewed-bytrailers).
A knowledge-transfer insight is shown only when there is no intersection between these sets.
Disable with:
gitrot status --ignore-siloUse in a Git pre-commit hook to block tangled commits.
Behavior:
- If
--ignore-tangled=true, exits0immediately. - Reads staged files from
git diff --cached --name-only. - Ignores staged files with no Git history.
- If historical staged file count
< 2, exits0. - Computes cohesion from pair coupling against
min_coupling. - If
N >= 3and cohesion< min_cohesion, prints a warning tostderrand exits1. - Otherwise exits
0silently.
Bypass once:
gitrot staged --ignore-tangledPrints a discovery view for one file:
- top historically coupled files (discovery threshold:
> 20%) - top knowledge holders by commit participation count (full
git user.name)
Use --hide-name (or [features].hide_name = true) to obfuscate developer names as deterministic IDs (usr-<8hex>).
This applies globally anywhere names are printed (including status insights).
If no historical data is available for the target, it prints:
Error: No historical data found for <file>
Prints top refactoring hotspots using only Git metadata:
- Churn: number of commits per file
- Coupling Degree: number of unique files coupled above
min_coupling - Score:
churn * coupling_degree
Files with fewer than 5 commits are ignored as low-churn noise.
Sorted by score (desc), limited by --limit (default: 10).
Optionally pass a path prefix (for example src/api) to restrict which hotspot files are shown.
Output format:
Refactoring Hotspots (High Coupling + High Churn)
Target: Entire Repository
--------------------------------------------------
...
With a path filter:
Refactoring Hotspots (High Coupling + High Churn)
Target: src/api
--------------------------------------------------
...
If no file exceeds the current thresholds:
No critical hotspots detected based on current thresholds.
gitrot init creates .gitrot.toml:
# .gitrot.toml - Configuration for gitrot
[thresholds]
history = 2000 # Number of past commits to analyze
max_files = 30 # Ignore merge commits or mass refactors touching >30 files
min_coupling = 60 # Files must have been committed together >= 60% of the time
min_shared = 3 # Files must have at least 3 shared commits to be considered coupled
min_drift = 2 # Warn if a file is left behind by >= 2 commits
min_cohesion = 30 # Minimum cohesion percentage (0-100) for staged commits
[features]
ignore_tangled = false # Set to true to disable Tangled Commit detection (`gitrot staged`)
ignore_silo = false # Set to true to disable Context Loss/Silo detection
hide_name = false # Set to true to obfuscate developer names in output
ignore_dotfiles = true # Set to true to ignore dotfiles and hidden directories in analysisBy default, ignore_dotfiles = true, so files like .gitignore, .eslintrc, and paths under hidden directories (for example .github/...) are excluded from all analyses.
Configuration precedence is:
- CLI flags provided explicitly
.gitrot.toml- Built-in defaults
gitrot ack <file_path>This writes the current HEAD hash for the file into .gitrot-state.json.


