Skip to content

Fix entire cli hanging on prepare-commit-msg git hook#561

Open
sbalay wants to merge 1 commit intoentireio:mainfrom
sbalay:improve-perf-of-getStagesFiles
Open

Fix entire cli hanging on prepare-commit-msg git hook#561
sbalay wants to merge 1 commit intoentireio:mainfrom
sbalay:improve-perf-of-getStagesFiles

Conversation

@sbalay
Copy link

@sbalay sbalay commented Feb 28, 2026

Problem

Reported this in Discord earlier. After setting up the entire cli in my project, I wasnt able to commit anymore. git commit would just hang.

After some quick research, I found that the root cause for the hang was the entire cli hook: entire hooks git prepare-commit-msg, it just hangs.

Proposed solution

Disclaimer: This solution was written by claude code. I think it makes sense, that's why I'm sending this PR but my knowledge around how the entire cli works is limited

  • Fix prepare-commit-msg hook hanging on large repos by replacing go-git's worktree.Status() with native git diff --cached --name-only in getStagedFiles()
    • worktree.Status() scans the entire working tree (O(all files)) — computing hashes, reading .gitignore, comparing with the index — all in pure Go. On repos with deep node_modules or many packages (like stilla-server), this takes 20+ seconds or hangs indefinitely
    • git diff --cached --name-only only lists staged files (O(staged files)), completing in under a second

The codebase already uses exec.CommandContext(ctx, "git", ...) extensively, so this fix reuses and existing pattern, it is not creating a new one:

  • paths.WorktreeRoot() — git rev-parse --show-toplevel
  • HardResetWithProtection() in common.go — git reset --hard
  • CheckoutBranch() in git_operations.go — git checkout
  • getUntrackedFiles() in common.go — git ls-files --others
  • HasUncommittedChanges() in git_operations.go — git status --porcelain

Test plan

  • All existing TestPrepareCommitMsg tests pass
  • Full test suite passes (go test ./...)
  • Manual test: I built the CLI locally and tested it in my project. It no longer hangs and completes in less than a second

Replace go-git's worktree.Status() with `git diff --cached --name-only`
in getStagedFiles(). worktree.Status() scans the entire working tree
(O(all files)), which hangs on large repos with deep node_modules.
The native git command only lists staged files (O(staged files)) and
completes in under a second.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sbalay sbalay requested a review from a team as a code owner February 28, 2026 14:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant