例如,当我执行git pre-commit钩子时,我得到了奇怪的结果git diff --name-only在终端中似乎给出了不同的结果在.git / hooks / pre-commit中执行时
所以我的问题是:
我问这个,因为我尝试了2到3次:我修改文件,我手动运行脚本,它打印出来
#! /bin/sh -xv
files=$(git diff --name-only)
+ git diff --name-only
+ files=path/to/file.h
echo $files
+ echo path/to/file.h
path/to/file.h
...
当我执行git commit -am“ eh”时,输出将不同
#! /bin/sh -xv
files=$(git diff --name-only)
+ git diff --name-only
+ files=
echo $files
+ echo
- 我可以在git hooks中调用git吗?
是的,但是您必须谨慎,因为环境中设置了很多东西,并且您正在做的事情正在完成中:
GIT_DIR
被设置为Git目录的路径。GIT_WORKTREE
可以设置为工作树的路径(来自git --work-tree
)。GIT_NO_REPLACE_OBJECTS
。((如果继续使用当前存储库,则应保留这些设置;如果使用different存储库,请清除它们。)
- 如果1.可以:如果我执行git commit -am“ bla”,则何时调用预提交钩子?特别是git是否先进行登台,然后再调用预提交钩子?
这很复杂。
git commit
内部使用三种“模式”。 (对此没有任何保证,但是这已经实现了很多年,因此这三种模式似乎很稳定。)这些模式是:
git commit
,不带-a
,--include
,--only
和/或任何命令行指定的文件名。这是默认或正常模式。基本的实现细节不会显示出来。
git commit
with -a
或带有命令行指定的文件名。这分为两个子模式:
--include
的提交,或--only
的提交。至此,基础实现得以显示。
这里的基本实现细节涉及Git调用的各种内容,分别是index,staging area和(现在很少)cache,它们通常以文件形式实现名为$GIT_DIR/index
(其中$GIT_DIR
是关于点1的注释中的环境变量)。通常,只有以下一项:the索引。它保存您打算提交的内容。1运行git commit
时,Git会将<< [in索引中的任何内容打包为下一次提交。
git commit
期间,最多可能有三个个索引文件。对于普通的git commit
,只有一个索引,您的预提交钩子可以使用它甚至可以更新它。 (我建议不要对其进行更新,出于稍后我们将要看到的原因。)
git commit -a
或git commit --include file.ext
,则现在有two个索引文件。已经准备好要提交的内容-常规索引-和
一个extra索引,它是原始索引加上在git add
或所有文件上执行file.ext
的结果(相当于git add -u
)。因此,现在有two个索引文件。在此模式下,Git保留常规索引文件as常规索引文件。该文件照常位于$GIT_DIR/index
中。具有附加内容的second
索引文件位于$GIT_DIR/index.lock
中,并且环境变量GIT_INDEX_FILE
设置为保留该路径。如果提交失败,Git将删除index.lock
文件,一切将好像您根本没有运行git commit
。如果提交成功,Git会将index.lock
重命名为index
,释放锁并一次更新the(标准,常规)索引。最后,有third模式,例如,当您运行git commit --only file.ext
时会得到。在这里,现在有三个
索引文件:$GIT_DIR/index
:标准索引,保留其通常的功能。$GIT_DIR/index.lock
:file.ext
被编辑到的标准索引的副本。git add
:$GIT_DIR/indexsuffix
-ed的HEAD
提交file.ext
指向此第三索引。如果提交成功,Git会将git add
文件重命名为GIT_INDEX_PATH
,以使其成为theindex.lock
文件,以便索引返回到开始之前的状态。 (无论哪种情况,Git都会删除已达到其目的的第三个索引。)请注意,从预提交钩子中,您可以检测到index
是标准提交(index.lock
未设置或设置为git commit
)还是两种特殊模式之一。在标准模式下,如果要更新the索引,则可以照常进行。在两种特殊模式下,可以使用GIT_INDEX_FILE
修改$GIT_DIR/index
命名的文件,这将修改提交内容。如果您使用的是git add
样式提交,那么这也会修改成功时将成为标准索引的内容。但是,如果您处于GIT_INDEX_FILE
模式,则修改建议的提交
dosn't
会影响标准--include
,nor将[标准索引的--only
。 考虑一个具体的例子,假设用户这样做:index
使得标准索引与index.lock
匹配,但git add file1 file2
和HEAD
除外。然后用户运行:file1
以使建议的提交是添加了,如果此提交成功,Git将用其中file2
的git commit --only file3
的副本,和
HEAD
,file3
和file1
全部添加(但由于file2
将与新的file3
提交匹配,因此在新索引中仅文件1和2将被[[modified)。现在假设您的提交挂钩运行file3
,并且整个过程成功(成功完成了新提交)。HEAD
步骤会将git add file4
的工作树版本复制到临时索引中,以便提交将同时更新git add
和
file4
。然后,Git将重命名file3
文件,以便file4
与新的index.lock
提交匹配。但是file3
中的HEAD
从未更新过,因此它[[不会与file4
提交匹配。用户似乎会以某种方式恢复index.lock
! HEAD
将显示对其的暂挂更改,已暂存以提交,而file4
将显示git status
与索引之间的差异是git diff --cached
已更改回以匹配HEAD
中的file4
]。您可以对此模式进行预提交挂钩测试,并在此模式下拒绝file4
文件,以避免出现此问题。 (或者,您甚至可以使用第二个HEAD~1
命令将git add
偷偷添加到file4
!)通常最好让钩子拒绝提交,并建议用户执行任何index.lock
本身,这样您就不必一开始就知道所有这些实现秘密。1索引还包含一些额外的信息:缓存数据 aboutgit add
更新的。2未指定Git是否通过以下等效的内部副本进行复制:git add
或其他某种方式(例如git commit
的内部等效方式),但是由于总是在过程结束时才删除此特定副本,所以这无关紧要:工作树的任何缓存信息都变得无关紧要。
是的,更改似乎已经被缓存。使用git add
列出要提交的文件。