Skip to content

fix(pre-commit): scope dotnet format to staged files only

ff80f08
Select commit
Loading
Failed to load commit list.
Open

Add optional pre-commit hook for code formatting #5178

fix(pre-commit): scope dotnet format to staged files only
ff80f08
Select commit
Loading
Failed to load commit list.
@sentry/warden / warden completed May 4, 2026 in 1m 8s

6 issues

High

`set -e` with `grep` causes hook to fail when no C# files are staged - `.githooks/pre-commit:6-11`

With set -e enabled, the pipeline git diff ... | grep '\.cs will terminate the script when grepfinds no matches (exit code 1), before the[ -z "$STAGED" ] check runs. As a result, commits containing no C# files will fail the pre-commit hook instead of exiting cleanly with the intended "No C# files staged" message, blocking unrelated commits. | tr ... will terminate the script when �CODE2� finds no matches (exit code 1), before the �CODE3� check runs. As a result, commits containing no C# files will fail the pre-commit hook instead of exiting cleanly with the intended "No C# files staged" message, blocking unrelated commits.

Also found at:

  • .githooks/pre-commit:17-26
Hook auto-modifies files, contradicting documented "check-only" design - `.githooks/pre-commit:13-18`

The PR description states "Hook verifies formatting but doesn't auto-fix (explicit, matches CI behavior)", but the command invokes dotnet format without --verify-no-changes, which actively rewrites files on disk. The hook then detects the modifications via git diff --quiet. This causes unintended side effects: developer's working tree is mutated on every commit attempt, and any pre-existing unstaged edits will be conflated with formatter output, making it hard to recover the original state.

Medium

Unquoted `$STAGED` breaks on filenames containing spaces - `.githooks/pre-commit:6-14`

$STAGED is built by joining filenames with spaces and passed unquoted to --include $STAGED. Any C# file path containing whitespace will be split into multiple arguments, causing dotnet format to receive incorrect (likely nonexistent) paths and either skip files silently or error out. While uncommon in C# projects, this is a latent correctness issue.

Hook formats working-tree files, not the staged content being committed - `.githooks/pre-commit:13-15`

The hook collects staged .cs files via git diff --cached but then runs dotnet format against the on-disk (working-tree) versions of those files. When a file is partially staged (some hunks staged, others left unstaged), the formatting check is performed against content that is not what will be committed. This can cause the hook to pass commits whose staged content is actually misformatted, or to fail commits whose staged content is fine because of unstaged edits — defeating the hook's purpose.

Also found at:

  • .githooks/pre-commit:17

Low

`dotnet format` errors are silently swallowed - `.githooks/pre-commit:13-15`

dotnet format is invoked with > /dev/null 2>&1, suppressing both stdout and stderr. Combined with set -e at the top of the script, if dotnet format exits non-zero (e.g., build failure, invalid project, missing SDK), the hook aborts the commit with no diagnostic output, leaving the developer unable to determine why their commit was blocked.

Unquoted `$STAGED` breaks on filenames with spaces or special characters - `.githooks/pre-commit:6-14`

STAGED is built by joining filenames with spaces (tr '\n' ' ') and is later interpolated unquoted into the dotnet format --include $STAGED command. Any staged C# file whose path contains spaces, globs, or other shell-significant characters will be word-split incorrectly, causing dotnet format to receive wrong arguments and either fail or silently skip files. Although uncommon in C# codebases, this still allows misformatted code to slip past the hook.

4 skills analyzed
Skill Findings Duration Cost
code-review 3 54.0s $0.62
find-bugs 3 55.3s $1.31
gha-security-review 0 21.5s $0.31
security-review 0 16.3s $0.45

Duration: 2m 27s · Tokens: 292.1k in / 6.0k out · Cost: $2.72 (+extraction: $0.01, +merge: $0.00, +consolidate: $0.00, +dedup: $0.01)