penguin02007
penguin02007

Reputation: 79

git pre-commit not working with git commit

I have the following snippet saved in .git/hooks/pre-commit.

When running git commit, it works as expected. However, when running with git commit -a -m. it bypasses the hook, any suggestion?

[US25020018:ansible]$ git commit
junos.yml
13:2 error syntax error: expected <block end>, but found '<block sequence start>'

yamllint failed
US25020018:ansible]$ git commit -a -m 'lint test'
[lchan_git_hook 423aada] lint test
1 file changed, 1 insertion(+), 1 deletion(-)
---
# pre-commit
RED='\033[1;31m'
GREEN='\033[0;32m'
NC='\033[0m'
FILES=$(git diff --name-only)

function preq(){
yamllint --version &> /dev/null
if [ "$?" -ne 0 ]; then
printf "\n${NC}yamllint missing, suggested action:"
printf "\n\t${NC}pip3 install yamllint --user"
printf "\n\n"
exit 1
fi
}

function run_yamllint(){
if [[ "$FILES" = "" ]]; then
exit 0
fi
# Run yamllint and get the output and return code
for FILE in $FILES
do
yamllint "$FILE"
if [ "$?" -ne 0 ]; then
printf "\n${RED}yamllint failed\n"
exit 1
else
printf "${GREEN}yamllint passed\n"
fi
done
}

preq
run_yamllint

Upvotes: 1

Views: 1441

Answers (2)

torek
torek

Reputation: 488453

TL;DR

You have the wrong git diff. You want git diff --staged or git diff --cached (these are synonyms).

Long

Your pre-commit hook contains this line:

FILES=$(git diff --name-only)

Look at the documentation for git diff. Near the top, it says, in part:

DESCRIPTION

Show changes between the working tree and the index or a tree, changes between the index and a tree, changes between two trees, changes between two blob objects, or changes between two files on disk.

This part has a fair amount of jargon in it: the index, a tree or trees, and blob objects. It's important to know what these mean:

  • The index is a somewhat complicated thing, but absolutely crucial for using Git. Except for the easiest cases, you can't get anything done in Git unless you know what the index is, and a little bit about how to use it.

  • The word tree is pretty badly overloaded, in Git in particular and in computing in general. Here, it means both a collection of files stored in directories/folders on your computer, as ordinary files and a collection of files stored inside the Git repository itself, typically inside a commit.

  • The phrase blob object refers to an individual file stored inside the Git repository. The difference between an ordinary file on your computer and a file stored inside Git has to do with these blob objects. For git diff, though, the difference isn't really relevant.1

This thing that Git calls the index has multiple names: the index, the staging area, and (rarely these days) the cache.2 A good, though not perfect, short description of the index is that it is what you plan to commit, once you get around to running git commit. You git add files—or stage them, hence the name staging area—to the index to replace the old index copy, making the new version of the file ready to be committed. When you use git commit -a, Git automatically adds to the index as if you had run git add -u,3 then does the commit.

So, in the end, what you want is to have git diff compare:

  • on the left: the HEAD (current) commit, or rather its stored tree, vs
  • on the right: the index / staging-area.

For whatever files that are in both and are the same, git diff says nothing. For files that are in both but different, git diff says something. (In your case, you want it to say the file's name.) For files that are in the left-side tree and not in the right-side, Git says something—normally it says deleted—and for files that are not in the left but are in the right, Git says something, normally added.

Using git diff --cached --name-only tells Git: compare HEAD on the left with the index/staging-area on the right, and instead of showing file differences or saying deleted or added, just list file names.


1For completeness, a Git blob object stores the content of a file, shorn of its file name and executable-mode flag. The content has a header shoved in front of it, and then is zlib-compressed. The uncompressed data—including the blob header—are hashed with a cryptographic checksum algorithm. The compressed data are stored under the resulting hash ID.

Once any object has its hash ID, that object is frozen for all time. Nothing can change it, not even one bit. The reason is that if you did uncompress it, change one bit, and re-compress it, the re-compressed data must be stored under whatever hash ID you get by hashing the altered data. So the original object remains, and all you did was add a new object, with a different hash ID, or—if you came up with the same data as some previous existing object—re-use the earlier object.

Blob objects, and other Git objects, may be later packed into a pack file, compressing them even further.

(Commit objects are forced to become unique by adding date-and-time stamps, so that even if one person makes two commits with the same parents and snapshot and log message and so on, the times will be different, resulting in two commits. If you somehow make these two otherwise-identical commits at the same time, you just get one commit, but that's OK: you made absolutely, totally, 100% identical commits, twice within one second, so why do you care if you get the same one twice?)

2Long ago, Git tried to distinguish between "index" and "cache", and a few commands, such as git apply, still make a distinction here.

3This, too, is not quite right technically. A git commit -a actually makes a second index, runs git add -u on this second (and temporary) index, and commits from that. If all goes well, this second index becomes the index. If the commit fails, Git quietly removes the second index, and it is as though you never ran git commit -a at all: the files aren't added after all.

Upvotes: 1

anthony sottile
anthony sottile

Reputation: 69964

You want to use git diff --staged --name-only instead of git diff --name-only

the former will check the files which are about to be committed whereas the latter only checks the unstaged (not to be committed) files

Upvotes: 0

Related Questions