Suppose git status
gives this:
# On branch X
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: file1.cc
# modified: file1.h
# modified: file1_test.cc
# modified: SConscript
#
# 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)
# (commit or discard the untracked or modified content in submodules)
#
# modified: file1.cc
# modified: tinyxml2 (untracked content)
#
In this case, only some of the changes made to file1.cc have been staged/indexed for the next commit.
I run a pre-commit script to do run a style checker:
#!/bin/bash
git stash -q --keep-index
# Do the checks
RESULT=0
while read status file
do
if python ~/python/cpplint.py "$file"; then
let RESULT=1
fi
done < <(git diff --cached --name-status --diff-filter=ACM | grep -P '\.((cc)|(h)|(cpp)|(c))$' )
git stash pop -q
[ $RESULT -ne 0 ] && exit 1
exit 0
As suggested by here, I stash unstaged files before I run my style checks, and pop them afterwards. However, in the case where only some of the changes in a file were staged, this causes a merge conflict when I pop the stash at the end of the pre-commit hook.
What is a better way to do this? I want to run a style check against the staged version of the files about to be committed.
How to gate commits without stashing
We use this
.git/hooks/pre-commit
for checking an atom syntax packageKey bits
git checkout-index -a --prefix={{temp_dir}}
It may/may not be far slower/take more space than stashing, but automation which messes with the index seems inherently brittle. Perhaps there needs to be a git contrib script which makes a soft-/hard-link tree, minimum space read-only, temporary index checkout, facilitating better/faster
.git/hooks/pre-commit
(or, say,.git/hooks/pre-commit-index
) scripts so that a full second copy of the working dir isn't needed, just the working-dir->index changes.I'd avoid using
git stash
automatically in hooks. I found that it is possible to usegit show ':filename'
to get contents of stashed file.Instead I used next approach:
Replace
git stash -q --keep-index
with:...and
git stash pop -q
with:This will save the diff to a temporary file and reapply it using
git apply
at the end. The changes are still redundantly saved to the stash (which is later dropped), so that if something goes wrong with the reapplying, you can inspect them usinggit stash show -p
without having to look for the temp file.