I'm working on a pre-commit hook to reformat code, and in general, it works; it reformats and git add
s any staged files, and the resulting commit contains the reformatted code as desired.
However, it doesn't play nicely with git commit --only
(which is the variant used by JetBrains IDEs), and I'm trying to understand why. The combination of git commit --only
and the pre-commit hook results in an undesirable index/working tree state, as described in the following sequence of events:
If I make a small change with a formatting error to a file and then run git status
, this is what I see:
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: file.php
no changes added to commit (use "git add" and/or "git commit -a")
If I then commit using git commit --only -- file.php
, the pre-commit hook runs, and the changed and reformatted file.php
is committed.
However, if I then run git status
again, this is the result (arrow annotations mine):
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: file.php <-- contains original change, improperly formatted
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: file.php <-- contains original change, properly formatted (per the most recent commit)
Where are the new staged change and the change in the working tree coming from?
Can someone explain exactly how git commit --only
interacts with the index to produce the result shown above — and even better, whether there's a way to have my pre-commit hook play nicely with it?
My understanding is that git commit --only
works with the version of the file in the working tree, so I tried removing the git add
step from the pre-commit hook to see what would happen, and it resulted in the improperly-formatted version of the file being committed and the properly-formatted one in the working tree (which matches my expectations for a standard git commit
, but I wasn't sure what to expect in the context of git commit --only
).
I'm aware of the possibility of using a clean
filter to reformat the code, rather than a pre-commit hook, but there are a few situational complications introduced by that approach that would be nice to avoid if possible.
Note: This question is related to Phpstorm and pre commit hooks that modify files but is focused on addressing the problem in the context of git commit --only
. Moreover, the problem doesn't seem to have been addressed by JetBrains, as was suggested in the accepted answer to that question.