Question

We've got this repo for all our Puppet configs. I wrote the following to validate any changed .pp files and bail out of the commit if validation fails. The pre-commit script runs properly when triggered by git commit but git commit -a seems to skip the hook altogether. We use git commit -a exclusively so this behaviour is a bit of a deal breaker.

Am I doing something wrong? Alternatively, what could I do to duplicate git commit -a's behaviour in the pre-commit script?

#!/bin/bash
# check puppet files for errors before pushing to repo
for name in `git diff --name-only`; do
    if [[ $name == *.pp ]]; then
        path="$(pwd)/$name"
        puppet parser validate "$path"
        r=$?
        if [ $r -ne 0 ]; then exit 1; fi
    fi
done
Was it helpful?

Solution

Pre-commit hooks run on every commit, even when the -a option is specified. Confirm it by creating this script:

#!/bin/bash
echo "Running"

Put the script into .git/hooks/pre-commit, editing and staging a file, and then:

$ git commit -am "Commit"
Running
[master f042adf] Commit
 1 file changed, 1 insertion(+), 1 deletion(-)

git diff by default diffs against unstaged changes. For example, edit README.md then:

$ git diff --name-only
README.md
$ git add -A
$ git diff --name-only
$

Once the changes had been staged, they no longer appeared in git diff.

The -a option on git commit stages the changes before executing the pre-commit hook. For example, if we change our pre-commit hook to this:

#!/bin/bash
echo "Running"
git diff --name-only

Edit README.md again, then:

$ git status
On branch 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:   README.md

no changes added to commit (use "git add" and/or "git commit -a")
$ .git/hooks/pre-commit
Running
README.md
$ git commit -m "Commit"
Running
README.md
On branch master
Changes not staged for commit:
    modified:   README.md

no changes added to commit

The changes showed up in the diff output, but were not committed. But:

$ git commit -am "Commit"
Running
[master a357465] Commit
 1 file changed, 1 insertion(+), 1 deletion(-)

This time, using the -a option, the changes did not show in the diff output (because they were on the stage) but they were committed.

So add the --cached option to the git diff command:

#!/bin/bash
echo "Running"
git diff --name-only --cached

Then, after making another change toREADME.md:

$ git commit -am "Commit"
Running
README.md
[master eaab554] Commit
 1 file changed, 1 insertion(+), 1 deletion(-)

The answer is the --cached option on git diff.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top