从git pre-commit hook

时间:2017-08-16 19:34:27

标签: git githooks

我有一个git pre-commit钩子,在提交之前对任何修改过的文件进行一些样式检查。

实现无关紧要,但首先是调用git diff。这是(repo)/.git/hooks/pre-commit中的内容。

#!/bin/sh


echo "=== Running script..."
git diff
echo "=== Done running script..."

# Other stuf
# ....

# Always exit with 1 so pre-commit hook always fails.
# Useful for testing
exit 1

当我实际尝试提交某些内容时,pre-commit挂钩正确触发,但git diff命令不输出任何内容(肯定有修改过的文件)

> git commit --all -m "foo"
=== Running script...
=== Done running script...

但是,如果我直接/手动运行pre-commit挂钩脚本, 工作

> ./.git/hooks/pre-commit
=== Running script...
(... outputs git diff ...)
=== Done running script...

git调用钩子与我手动调用它有什么不同?它以相同的方式运行(我的用户名)

我还尝试了this thread的建议,但unset GIT_DIR--git-dir=work-tree=没有解决任何问题。

谢谢!

2 个答案:

答案 0 :(得分:2)

您需要使用git diff --cached,因为更改已经暂存。

答案 1 :(得分:2)

作为ishegg said,您需要git diff --cached,但这不一定是整个故事。

这里有两个陷阱需要警惕。第一个是git diff的作用:它比较两个(或类似树的东西)。第二个与索引

这个短语有关

索引,并选择git diff

的树

通常,您区分的两棵树是与两个特定提交相关联的树:

git diff <hash1> <hash2>

(或与<hash1>..<hash2>相同,与大多数Git命令不同 - 以两点..操作描述的方式处理两个哈希the SPECIFYING RANGES section of the gitrevisions documentation)。

将两棵树中的一棵树作为工作树也很常见,这就是你跑步时会发生的事情:

git diff HEAD
例如:

HEAD命名的提交 - 即当前的分支提示提交 - 与当前工作树进行比较。

使用:

git diff --cached

告诉Git将HEAD提交与索引所代表的树进行比较。 Git的索引,也称为临时区域缓存,是Git构建下一个提交的地方。这就是你必须在提交之前运行git add的原因:git add命令将文件从工作树复制到索引。

使用:

git diff

没有任何参数选择索引作为第一个树,工作树作为第二个树。一旦所有内容都从工作树复制到索引中,这个特殊的差异将是空的,这就是你在这里看到的。

索引vs 索引

第二个陷阱在于你正在使用git commit --all

虽然Git谈到 索引,并且实际上有一个特定的,区别于每个工作树的索引,Git实际上允许多个索引,一次只使用一个

当您使用git commit --all或将文件名传递给git commit时,Git会在预提交过程中创建一个临时索引。为了表明存在临时索引,Git设置了环境变量GIT_INDEX_FILE。使用此临时索引而不是普通索引,直到允许和提交提交,或直到提交被拒绝为止。

如果提交被拒绝,Git只会删除临时索引,一切都会恢复到之前的状态。如果事情不是git add,那么它们仍然不是git add - 编辑。

如果提交已接受,则临时索引或多或少变为“真实”或“主要”索引。这里的事情可能变得复杂,因为您可以在真实索引中运行一些项目,运行git commit --allgit commit --include <paths>git commit --only <paths>,如果提交成功,则初始(主要或真实的)指数和临时指数很重要。

如果您计划对工作树中的文件和/或索引中的副本执行特殊操作,您可能只想拒绝任何使用临时索引的尝试,以避免这些复杂情况。但是,这将排除使用--all