Add optional pre-commit hook for code formatting #5178
3 issues
find-bugs: Found 3 issues (1 high, 1 medium, 1 low)
High
Pre-commit hook silently auto-formats staged files, modifying tracked content without consent - `.githooks/pre-commit:22-24`
The hook runs dotnet format without --verify-no-changes, which mutates files in the working tree. Because the hook only checks git diff (unstaged changes) afterward, any formatting fixes applied by dotnet format will modify the working tree but the original (unformatted) staged content is still what gets committed. The user is told to git add -u and recommit, but if the working tree happens to match the index after formatting (e.g., file was already formatted), the hook exits 0 and an unformatted snapshot is committed. This contradicts the PR description which claims 'check-only mode' using --verify-no-changes.
Also found at:
.githooks/pre-commit:6-10
Medium
Filenames with spaces or special characters break the --include argument list - `.githooks/pre-commit:12-15`
The loop on lines 12-15 reads staged filenames via git diff --cached --name-only and passes them to dotnet format --include. git diff --name-only does not quote special characters by default unless core.quotePath is configured, and even with proper reading, filenames with spaces will be passed correctly to --include as separate args — but newer git versions or filenames containing quotes/backslashes produce C-style quoted output (e.g., "foo\tbar.cs") which would not match real paths. This can cause the hook to either miss files or fail unexpectedly.
Low
Suppressing dotnet format output hides real errors from developers - `.githooks/pre-commit:24`
Redirecting both stdout and stderr to /dev/null on line 24 means that genuine failures of dotnet format (e.g., missing SDK, project load errors, MSBuild failures) are silently swallowed. With set -e at the top, the script will then abort with no diagnostic, leaving developers unable to understand why their commit was rejected.
Duration: 44.7s · Tokens: 50.8k in / 2.8k out · Cost: $0.62 (+merge: $0.00)
Annotations
Check failure on line 24 in .githooks/pre-commit
sentry-warden / warden: find-bugs
Pre-commit hook silently auto-formats staged files, modifying tracked content without consent
The hook runs `dotnet format` without `--verify-no-changes`, which mutates files in the working tree. Because the hook only checks `git diff` (unstaged changes) afterward, any formatting fixes applied by `dotnet format` will modify the working tree but the original (unformatted) staged content is still what gets committed. The user is told to `git add -u` and recommit, but if the working tree happens to match the index after formatting (e.g., file was already formatted), the hook exits 0 and an unformatted snapshot is committed. This contradicts the PR description which claims 'check-only mode' using `--verify-no-changes`.
Check failure on line 10 in .githooks/pre-commit
sentry-warden / warden: find-bugs
[PJD-FYR] Pre-commit hook silently auto-formats staged files, modifying tracked content without consent (additional location)
The hook runs `dotnet format` without `--verify-no-changes`, which mutates files in the working tree. Because the hook only checks `git diff` (unstaged changes) afterward, any formatting fixes applied by `dotnet format` will modify the working tree but the original (unformatted) staged content is still what gets committed. The user is told to `git add -u` and recommit, but if the working tree happens to match the index after formatting (e.g., file was already formatted), the hook exits 0 and an unformatted snapshot is committed. This contradicts the PR description which claims 'check-only mode' using `--verify-no-changes`.
Check warning on line 15 in .githooks/pre-commit
sentry-warden / warden: find-bugs
Filenames with spaces or special characters break the --include argument list
The loop on lines 12-15 reads staged filenames via `git diff --cached --name-only` and passes them to `dotnet format --include`. `git diff --name-only` does not quote special characters by default unless `core.quotePath` is configured, and even with proper reading, filenames with spaces will be passed correctly to `--include` as separate args — but newer git versions or filenames containing quotes/backslashes produce C-style quoted output (e.g., `"foo\tbar.cs"`) which would not match real paths. This can cause the hook to either miss files or fail unexpectedly.