Repository navigation
Re-stage formatted files in the pre-commit hook under POSIX sh - #537
Merged
thomasmny merged 1 commit intoSep 30, 2026
Merged
Conversation
The hook runs as /bin/sh, and `read -d` is a bash extension: under dash (Debian and Ubuntu's /bin/sh) the loop failed on its first read, so no file Spotless reformatted was ever re-staged and commits kept the unformatted content. Command substitution also dropped the NUL bytes the -z list relied on. Pipe the staged list straight into `xargs -0` instead, which keeps odd paths intact and works in any POSIX shell.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The pre-commit hook runs as
#!/bin/sh, but its re-stage loop usesread -d '', which is a bash extension. Where/bin/shis dash (Debian, Ubuntu, WSL) the loop fails on its first read:The hook still exits 0, so the commit goes through with the unformatted content, while the formatted version stays behind as an unstaged change. In addition,
staged=$(git diff --cached --name-only -z)loses the NUL separators, because command substitution drops NUL bytes.This change pipes the staged list straight into
xargs -0 sh -c 'for f do …; done' sh. It keeps odd paths intact and works in any POSIX shell. The early exit usesgit diff --cached --quiet, and--diff-filter=ACMRskips deleted paths. Behaviour is otherwise unchanged: only files that were already staged and that Spotless modified are re-staged.Tested under dash with a stub
gradlewthat appends to*.java:read: Illegal option -d, commit contains the unformatted fileUnrelated, but hit at the same time:
palantirJavaFormat("2.92.0")fails on JDK 25+ withNoSuchFieldError: … JCCompilationUnit does not have member field 'EndPosTable endPositions', so the hook only works when Gradle runs on JDK 21. 2.100.0 works on JDK 25 but reformats a few files, so I left that for you to decide.