Skip to content

fix(hooks): keep a partly staged file partly staged - #1874

Merged
danielcopper merged 2 commits into
mainfrom
fix/pre-commit-partial-staging
Sep 10, 2026
Merged

fix(hooks): keep a partly staged file partly staged#1874
danielcopper merged 2 commits into
mainfrom
fix/pre-commit-partial-staging

Conversation

@danielcopper

Copy link
Copy Markdown
Owner

The hook formats staged source files and then re-stages them, and git add stages the whole worktree file rather
than the hunks that were chosen. So a file staged in part with git add -p was committed whole: the hunks the
author deliberately left out of the index went into the commit, with nothing on stdout and nothing in the diff
review to say so.

The re-stage now skips a file that already had unstaged changes when the hook started, and names it. Its formatting
still reaches the worktree, so the next commit carries it; what is committed now is exactly what was staged. That
can be unformatted, which CI reports out loud — the failure this replaces was silent, which is the one worth
refusing.

The dirty list is taken before the formatter runs, because afterwards every file it rewrote reads as unstaged. The
three sections shared one copy of the re-stage loop each; they now share one function.

The comment above the old loop claimed it re-staged the files the formatter had modified. Its condition only tested
that the file still existed, which is a guard for a staged file deleted from the worktree and is kept.

Verified

Against a scratch repository, with the same hook the repo installs:

  • A file whose index holds one change while the worktree holds a second commits only the staged change, prints
    pre-commit: <file> has unstaged changes — leaving the index exactly as you staged it, and still has the
    formatter's fixes applied in the worktree.
  • A fully staged, badly formatted file is still formatted and re-staged: the commit carries the formatted
    content, exactly as before.
  • A staged file deleted from the worktree aborts the commit through the final ruff check. That behaviour is
    unchanged — the same scenario aborts identically on main's hook, so it is not introduced here and is out of
    scope for this cut.

docs: N/A — tooling only; the hook's own contract is stated in CLAUDE.md's Development section, updated here.

The hook formats staged source files and then re-stages them, and `git
add` stages the whole worktree file rather than the hunks that were
chosen. So a file staged in part with `git add -p` was committed whole:
the hunks the author deliberately left out of the index went into the
commit, with nothing on stdout and nothing in the diff review to say so.

The re-stage now skips a file that already had unstaged changes when the
hook started, and names it. Its formatting still reaches the worktree,
so the next commit carries it; what is committed now is exactly what was
staged. That can be unformatted, which CI reports out loud — the failure
this replaces was silent, which is the one worth refusing.

The dirty list is taken before the formatter runs, because afterwards
every file it rewrote reads as unstaged. The three sections shared one
copy of the re-stage loop each; they now share one function.

The comment above the old loop claimed it re-staged the files the
formatter had modified. Its condition only tested that the file still
existed, which is a guard for a staged file deleted from the worktree
and is kept.
@github-actions github-actions Bot added the area:architecture Code structure, refactoring label Sep 10, 2026
@danielcopper
danielcopper enabled auto-merge (squash) September 10, 2026 11:14
@sonarqubecloud

Copy link
Copy Markdown

@danielcopper
danielcopper merged commit fc3b41a into main Sep 10, 2026
16 checks passed
@danielcopper
danielcopper deleted the fix/pre-commit-partial-staging branch September 10, 2026 11:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:architecture Code structure, refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant