简体   繁体   中英

Find out staged files in git `pre-commit` hook when using `git commit -a`

I'm using a git pre-commit hook to automatically format all of my staged files. I'm determining the staged files via git diff --name-only --cached and then call a script on those files. This all works well in the standard use case, however it doesn't work when I commit via

git commit -a ..

because the files are not yet staged.

Is there some way to:

  1. Run the -a effect (add files to staging area) before the pre-commit hook?

  2. Find out that the pre-commit runs in a -a commit?

There must be a way to handle this.

because the files are not yet staged

This actually isn't quite true. But it's not quite false either.

Here is a (silly, meant for illustration only) pre-commit hook to demonstrate the problem:

$ cat .git/hooks/pre-commit
#! /bin/sh
echo \$GIT_INDEX_FILE = $GIT_INDEX_FILE
git diff-index --cached --name-only HEAD
exit 1

This hook uses the correct (from a reliability perspective anyway) command, git diff-index --cached HEAD , to find the names of staged files. First, though, it prints the name of the index that is being used to commit the files. (Last, it prevents the commit, since I don't really want to commit any of this.)

I made this executable (in a Git repository for Git itself), and modified a few files without git add ing them:

$ git status --short
 M Makefile
 M wt-status.c

(note that the M s are in the second column). Then:

$ git commit
$GIT_INDEX_FILE = .git/index
$ git commit -a
$GIT_INDEX_FILE = [redacted]/.git/index.lock
Makefile
wt-status.c

The first hook invocation's echo tells us that we're using the real (main) index, and its git diff-index produces no output.

The second invocation tells us that we're using an alternate index file, named .git/index.lock (I trimmed away my source path). It shows two staged files.

Let's go on to do one more thing: I'll git add the modified Makefile and make a second change to Makefile . Now we have:

$ git status --short
MM Makefile
 M wt-status.c

The first line shows us that HEAD:Makefile (in the commit, frozen) differs from :Makefile (in the index, staged) which differs from Makefile (in the work-tree, unstaged), and indeed, we can see the three files are different:

$ git show HEAD:Makefile | head -2
# The default target of this Makefile is...
all::
$ git show :Makefile | head -2
#
# The default target of this Makefile is...
$ head -2 Makefile
# different
# The default target of this Makefile is...

Running git commit vs git commit -a now produces:

$ git commit
$GIT_INDEX_FILE = .git/index
Makefile
$ git commit -a
$GIT_INDEX_FILE = [redacted]/.git/index.lock
Makefile
wt-status.c

If I had not prevented the non- -a version of git commit , what would have been committed by git commit is the version of Makefile in the (main / real / .git/index ) index, not the version in the work-tree. Hence, if you want to inspect files that would be committed, you should look in the index. You can use git checkout-index to extract files from the index, but be careful not to clobber work-tree versions, which may differ.

What would have been committed by git commit -a is the version of the Makefile in the work-tree, which Git already added to the (non-standard, temporary) .git/index.lock index. Once the git commit -a finished, that non-standard temporary index would become the real index, destroying my intermediate, special staged copy of Makefile . Again, to inspect files that would be committed, look in the index—using the redirected index, as Git will automatically, for both git diff-index and git checkout-index .

(Since I don't know quite what your script needs, I can't make particular recommendations for exactly how to use git checkout-index to extract the files of interest. Consider using --work-tree= and a temporary directory, though.)

(See also my answer to Skip past (full) staging area and commit file or patch directly? , which discusses just what -a , --only , and --include really do internally.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM