Skip to content

Commit 2d89ebd

Browse files
committed
chore(dev): make pre-commit formatter safe
1 parent f583bd1 commit 2d89ebd

File tree

1 file changed

+22
-56
lines changed

1 file changed

+22
-56
lines changed

.husky/pre-commit

Lines changed: 22 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,34 @@
11
#!/bin/sh
2-
# Exit on any error
32
set -e
43

5-
# Check if there are any staged files
6-
if [ -z "$(git diff --cached --name-only)" ]; then
4+
STAGED_FILES="$(git diff --cached --name-only --diff-filter=ACMR)"
5+
if [ -z "$STAGED_FILES" ]; then
76
echo "No staged files to format"
87
exit 0
98
fi
109

11-
# Store the hash of staged changes to detect modifications
12-
STAGED_HASH=$(git diff --cached | sha256sum | cut -d' ' -f1)
13-
14-
# Save list of staged files (handling all file states)
15-
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACMR)
16-
PARTIALLY_STAGED=$(git diff --name-only)
10+
# Stash unstaged tracked changes so we format the staged snapshot of each file.
11+
# Note: if unstaged changes touch the same lines formatting changes, stash pop may conflict. In that
12+
# case we abort the commit and leave the stash for manual resolution.
13+
STASHED=0
14+
if ! git diff --quiet; then
15+
git stash push --quiet --keep-index --message "pre-commit-stash"
16+
STASHED=1
17+
fi
1718

18-
# Stash unstaged changes to preserve working directory
19-
# --keep-index keeps staged changes in working tree
20-
git stash push --quiet --keep-index --message "pre-commit-stash" || true
21-
STASHED=$?
19+
# Format only staged files (avoid rewriting unrelated files).
20+
git diff --cached --name-only --diff-filter=ACMR -z | xargs -0 bun x ultracite fix
2221

23-
# Run formatter on the staged files
24-
bun x ultracite fix
25-
FORMAT_EXIT_CODE=$?
22+
# Restage in case the formatter changed them.
23+
git diff --cached --name-only --diff-filter=ACMR -z | xargs -0 git add --
2624

27-
# Restore working directory state
28-
if [ $STASHED -eq 0 ]; then
29-
# Re-stage the formatted files
30-
if [ -n "$STAGED_FILES" ]; then
31-
echo "$STAGED_FILES" | while IFS= read -r file; do
32-
if [ -f "$file" ]; then
33-
git add "$file"
34-
fi
35-
done
36-
fi
37-
38-
# Restore unstaged changes
39-
git stash pop --quiet || true
40-
41-
# Restore partial staging if files were partially staged
42-
if [ -n "$PARTIALLY_STAGED" ]; then
43-
for file in $PARTIALLY_STAGED; do
44-
if [ -f "$file" ] && echo "$STAGED_FILES" | grep -q "^$file$"; then
45-
# File was partially staged - need to unstage the unstaged parts
46-
git restore --staged "$file" 2>/dev/null || true
47-
git add -p "$file" < /dev/null 2>/dev/null || git add "$file"
48-
fi
49-
done
50-
fi
51-
else
52-
# No stash was created, just re-add the formatted files
53-
if [ -n "$STAGED_FILES" ]; then
54-
echo "$STAGED_FILES" | while IFS= read -r file; do
55-
if [ -f "$file" ]; then
56-
git add "$file"
57-
fi
58-
done
25+
if [ "$STASHED" -eq 1 ]; then
26+
if ! git stash pop --quiet; then
27+
echo ""
28+
echo "pre-commit: failed to re-apply unstaged changes (stash pop conflicted)."
29+
echo "Resolve conflicts, then run:"
30+
echo " git stash list"
31+
echo " git stash pop"
32+
exit 1
5933
fi
6034
fi
61-
62-
# Check if staged files actually changed
63-
NEW_STAGED_HASH=$(git diff --cached | sha256sum | cut -d' ' -f1)
64-
if [ "$STAGED_HASH" != "$NEW_STAGED_HASH" ]; then
65-
echo "✨ Files formatted by Ultracite"
66-
fi
67-
68-
exit $FORMAT_EXIT_CODE

0 commit comments

Comments
 (0)