Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a file to the index in a git pre-commit hook

Tags:

git

githooks

I've looked around for duplicates and while some of them have similar titles, I haven't found anyone having the same issue as I am, so here goes.

I've written a script that runs on pre-commit and uses the output of git status --porcelain to compile any LESS file in my project that has changed. This part works fine. But I want the .css files to be included in the current commit. So in addition to running the compiler, my script runs git add <filename>. And here's where things get tricky.

The file is added to the index, but it's not the index of the current commit. So if I modify style.less, and run git commit -a (or manually git add style.less) the compiler should generate style.css and style.min.css and add them to the current commit. But the behavior I've noticed is only style.less is committed, despite the two .css files being added to the index for the next commit.

So my question is: is there a way to add files to a commit in a pre-commit hook so that they take effect for that commit? Note that before the pre-commit hook is run, those two .css files aren't modified, so I can't just add them before that. I also know I can exit the hook with a non-zero status so the commit is cancelled but the files are added, but I hope to avoid that. Any better ideas?

like image 372
Jimmy Sawczuk Avatar asked Feb 24 '12 19:02

Jimmy Sawczuk


People also ask

What is add to index in git?

If for any file git calculates SHA-1 sum then basically adding to index means that it calculates SHA-1 sum and add file to the staging area.

How do I commit a git hook file?

Once the terminal windows is open, change directory to . git/hooks . Then use the command chmod +x pre-commit to make the pre-commit file executable.

How do I update my git hooks?

update. This hook is invoked by git-receive-pack on the remote repository, which happens when a git push is done on a local repository. Just before updating the ref on the remote repository, the update hook is invoked. Its exit status determines the success or failure of the ref update.


1 Answers

I am unable to reproduce your problem. My initial guess was that the GIT_INDEX_FILE environment variable was being unset by your pre-commit hook. However, when I tried unsetting GIT_INDEX_FILE from pre-commit, I got a different problem (Git complained that .git/index was locked).

Here's an example script showing that Git functions as you expect and that something else must be wrong. This script initializes a new test repository, creates a pre-commit hook that emulates what your hook does, and makes a few test commits:

#!/bin/sh

# initialize the test repository
rm -rf testrepo
git init testrepo
cd testrepo

# create the pre-commit hook
cat <<\EOF >.git/hooks/pre-commit
#!/bin/sh
git status --porcelain | while IFS= read -r line; do
    # todo: handle renames and deletions of a *.less file
    f=${line#???}
    case ${f} in
        *.less)
            fb=${f%.less}
            echo bar >>"${fb}".css
            echo baz >>"${fb}".min.css
            git add "${fb}".css "${fb}".min.css
            ;;
    esac
done
EOF
chmod +x .git/hooks/pre-commit

# create foo.less, commit it
echo foo >foo.less
git add foo.less
git commit -m "add foo.less"

# modify foo.less, commit it
echo foo2 >>foo.less
git commit -a -m "modify foo.less"

If you run git log -p in the test repository and look at the resulting commits, you'll see that foo.css and foo.min.css were modified whenever foo.less was modified.

Here's why I thought your problem was caused by changing/unsetting the GIT_INDEX_FILE environment variable:

When git commit -a is run, Git makes a temporary index file and uses that instead of the default .git/index to create the commit. In order for operations like git add to work from within a pre-commit hook, Git sets the GIT_INDEX_FILE environment variable to the name of the temporary index it created before running pre-commit. If your hook unsets GIT_INDEX_FILE, or sets it to .git/index, then all Git operations from within your hook will try to modify the original index, not the temporary index that is used to generate the commit.

However, the temporary index file also acts as a lock on the original index file. If a hook tries to modify the original index, and the temporary index exists, then Git will abort with an error.

like image 174
Richard Hansen Avatar answered Oct 21 '22 06:10

Richard Hansen