|
1 | 1 | #!/bin/sh |
2 | | -# Exit on any error |
3 | 2 | set -e |
4 | 3 |
|
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 |
7 | 6 | echo "No staged files to format" |
8 | 7 | exit 0 |
9 | 8 | fi |
10 | 9 |
|
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 |
17 | 18 |
|
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 |
22 | 21 |
|
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 -- |
26 | 24 |
|
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 |
59 | 33 | fi |
60 | 34 | 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