Skip to content

Bug: parallel worktree commits cause stash cross-contamination — commits bypass PR review #1684

Description

@mrveiss

Problem

When committing across multiple git worktrees in parallel (e.g., 5 parallel git commit calls in separate worktrees), pre-commit hooks' git stash push/git stash pop operations corrupt branch state because git stash is shared across all worktrees.

What happened (session 2026-03-14)

5 worktrees were created from origin/Dev_new_gui for issues #1667, #1663, #1571, #1564, #1517. All 5 commits were launched in parallel. Result:

Root cause

Git worktrees share the same .git/objects, .git/refs, and critically, .git/refs/stash. Pre-commit hooks call git stash push --include-untracked before validation and git stash pop after. When multiple worktrees run pre-commit hooks simultaneously:

  1. Worktree A stashes its changes
  2. Worktree B stashes its changes (pushing A's stash down)
  3. Worktree A pops — gets B's stash instead of its own
  4. Changes leak across branches

Why branch guard (#1670) didn't help

The branch guard hook checks if the current branch name changed between pre-commit and commit time. In this case, the branch names didn't change — the stash contamination caused commits to include wrong content but on the "right" branch. The commits were then pushed to remote branches that happened to be fast-forwardable into Dev_new_gui.

Impact

Critical — Commits bypass PR review process and land directly on the integration branch. This defeats code review, CI gating, and change tracking.

Mitigation (immediate)

Added to MEMORY.md and CLAUDE.md:

NEVER commit worktrees in parallel. Always commit sequentially.

Proposed fix

  1. Lock file per worktree: Pre-commit hook acquires a repo-wide lock (flock /path/to/.git/pre-commit.lock) before stashing, ensuring only one worktree runs pre-commit at a time
  2. Disable stash in hooks: Configure pre-commit to skip stash (--no-stash flag) — requires all files to be staged before commit (already enforced by policy)
  3. Worktree-scoped stash: Git doesn't natively support this, but a wrapper script could use per-worktree temp branches instead of stash

Discovered during

Team-implement session fixing #1667, #1663, #1564, #1571, #1517

Related issues

Activity

  1. mrveiss commented on Mar 14, 2026

    @mrveiss
    OwnerAuthor

    ✅ Implemented in PR #1696

    Changes:

    • New autobot-infrastructure/shared/scripts/hooks/inject-flock-wrapper — idempotent flock injection script
    • Updated scripts/hooks/post-checkout — calls inject-flock-wrapper after every checkout/worktree creation
    • Live .git/hooks/pre-commit patched for immediate protection

    How it works:

    • flock -x 200 acquires exclusive lock on ${git-common-dir}/pre-commit.lock
    • Serializes pre-commit execution across all worktrees sharing the same .git
    • fd 200 inherited by exec'd pre-commit, auto-released on exit
    • Self-healing: post-checkout re-injects after pre-commit install regenerates the hook

    Verification:

  2. added a commit that references this issue on Mar 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions