当使用`git commit -a`命令时,在`pre-commit`钩子中找出Git中的暂存文件

3
我正在使用一个gitpre-commit钩子来自动格式化我所有暂存的文件。我通过git diff --name-only --cached来确定暂存的文件,然后在这些文件上调用一个脚本。
在标准用例中,这一切都很好运行,但是当我通过提交时,它就无法运行了。
git commit -a ..

因为文件尚未暂存,所以出现该问题。

有没有办法:

  1. 在运行pre-commit钩子之前运行-a效果(将文件添加到暂存区)?

  2. 查找pre-commit是否在-a提交中运行?

必须有一种方法来处理这个问题。

1个回答

9

因为文件还没有被暂存

实际上,这并不完全正确。但也不完全错误。

下面是一个(愚蠢的,仅用于示范)pre-commit钩子来演示这个问题:

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

这个钩子使用了可靠性较高的命令git diff-index --cached HEAD来查找暂存文件的名称。但首先,它会打印出用于提交文件的索引名称。(最后,它会阻止提交,因为我并不想提交任何更改。)
我在Git自身的存储库中将其设置为可执行文件,并修改了一些文件,但没有使用git add添加它们。
$ git status --short
 M Makefile
 M wt-status.c

(请注意,M在第二列。然后:)
$ git commit
$GIT_INDEX_FILE = .git/index
$ git commit -a
$GIT_INDEX_FILE = [redacted]/.git/index.lock
Makefile
wt-status.c

第一次钩子调用的“echo”告诉我们正在使用真实(主)索引,其“git diff-index”没有产生任何输出。
第二次调用告诉我们正在使用备用索引文件,名为“.git/index.lock”(我已经删除了源路径)。它显示了两个暂存文件。
让我们再做一件事情:我将“git add”修改后的“Makefile”,并对“Makefile”进行第二次更改。现在我们有:
$ git status --short
MM Makefile
 M wt-status.c

第一行告诉我们,在提交中(已冻结),HEAD:Makefile与暂存区(已提交)的:Makefile不同,它们又与工作目录(未提交)的Makefile不同。实际上,我们可以看到这三个文件是不同的:

$ 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...

运行 git commitgit commit -a 现在会产生以下结果:
$ git commit
$GIT_INDEX_FILE = .git/index
Makefile
$ git commit -a
$GIT_INDEX_FILE = [redacted]/.git/index.lock
Makefile
wt-status.c

如果我没有阻止非-a版本的git commit,那么git commit将提交的是(主要/真实/.git/index)索引中Makefile的版本,而不是工作树中的版本。因此,如果您想检查将要提交的文件,请查看索引。您可以使用git checkout-index从索引中提取文件,但要小心不要破坏可能不同的工作树版本。 git commit -a将提交的是工作树中Makefile的版本,Git已将其添加到(非标准的临时).git/index.lock索引中。一旦git commit -a完成,该非标准临时索引将成为真正的索引,破坏了我中间的特殊暂存副本Makefile。同样,要检查将要提交的文件,请查看索引-使用重定向的索引,因为Git会自动为git diff-indexgit checkout-index
(由于我不知道您的脚本需要什么,因此无法为如何使用git checkout-index提取感兴趣的文件提供具体建议。考虑使用--work-tree=和临时目录。)
(另请参见我的答案:Skip past (full) staging area and commit file or patch directly?,其中讨论了-a--only--include在内部实际上是做什么的。)

这是一个惊人的回复,即使四年后,它仍然帮助我许多次理清事情。谢谢! - Michael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接