我正在尝试在我的工作流程中使用this gist post-merge
和post-checkout
git hooks。
#!/usr/bin/env bash
# MIT © Sindre Sorhus - sindresorhus.com
# git hook to run a command after `git pull` if a specified file was changed
# Run `chmod +x post-merge` to make it executable then put it into `.git/hooks/`.
changed_files="$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)"
check_run() {
echo "$changed_files" | grep --quiet "$1" && eval "$2"
}
# Example usage
# In this example it's used to run `npm install` if package.json changed
check_run package.json "npm install"
如果package.json
文件发生更改,则声明只运行npm install。
然而,在我尝试过的所有机器上。无论package.json是否已更改,npm install命令都会运行。
为了测试这个,我在我当前的提交中创建了一个新分支,然后将其检出,从而触发post-checkout
git钩子。我不希望npm install
运行,因为package.json
未更改。
Visual Proof(注意npm警告文字):
答案 0 :(得分:2)
ORIG_HEAD
应该替换为HEAD@{1}
,如此question ORIG_HEAD
中所述,这是一种较旧的,不太可靠的方式,可以获得先前的HEAD状态。就我而言,它没有被设定。
答案 1 :(得分:1)
使用不同的结帐后挂钩,使用$1
代替ORIG_HEAD
。 (或者,检查参数的数量以决定是否将其作为post-checkout或post-merge钩子调用,以获得相同的效果。或者,如果您知道reflog总是被启用,请使用HEAD@{1}
来获取前一个值HEAD
。)
在合并后的钩子中使用ORIG_HEAD
是有道理的,因为git merge
将ORIG_HEAD
设置为合并前的当前提交。 (如果合并是真正的合并,而不是快进,则由MERGE_HEAD
标识的提交和HEAD^1
标识的提交必然相同。但是,如果合并是快进的,则,只有MERGE_HEAD
并且reflog将能够找到合并前存储在HEAD
中的先前提交哈希。)
在 post-checkout 挂钩中使用ORIG_HEAD
是明显错误的,因为git checkout
不设置ORIG_HEAD
。这意味着如果ORIG_HEAD
甚至存在,它实际上指向一些随机提交。 (当然,它实际上解析为上次更新它的任何命令留在其中的任何提交:git merge
,git rebase
或写入ORIG_HEAD
的任何其他命令。但这里的重点是它与结账前的当前提交没有任何关系。)A post-checkout hook:
给出了三个参数:ref的 之前的HEAD,新HEAD的参考(可能有也可能没有 改变),以及表明结账是否是分支的标志 checkout(更改分支,flag = 1)或文件签出(检索a 来自索引的文件,flag = 0)。这个钩子不能影响结果 git checkout 。
(最后一句话不太正确。虽然post-checkout钩子无法阻止检查更新索引和工作树,但可以覆盖各种工作树或索引内容,并且如果它产生故障退出状态,它会导致git checkout
本身也产生故障退出状态。)
这一切意味着你需要在post-checkout钩子中采取不同的动作:使用第一个参数$1
来获取前一个HEAD
的哈希ID。请注意,在特殊情况下, 1 后结帐挂钩在初始git clone
上运行,因此$1
可以是null-ref。 (我现在很好奇当你使用git checkout --orphan
时它是什么,然后也不创建新的分支。似乎$1
也可能是null-ref。 )
1 在git clone
上运行post-checkout挂钩的唯一方法是让git clone
安装post-checkout挂钩。这通常是不可能的,但可以通过将Git指向您自己的模板目录来完成,这些目录具有实际的钩子而不仅仅是示例钩子。
答案 2 :(得分:1)
Torek提到:
This hook cannot affect the outcome of git checkout.
最后一句话不太正确。
尽管检出后钩子无法停止检出更新索引和工作树的操作,但是它可以覆盖各种工作树或索引内容,并且如果产生失败退出状态,则会导致git checkout本身也产生故障退出状态。
现在(3年后的2020年第四季度)正式发布在With Git 2.29中:
请参见commit 3100fd5的Junio C Hamano (gitster
)(2020年8月27日)。
(由Junio C Hamano -- gitster
--在commit 2f1757e中合并,2020年9月3日)
doc
:阐明如何使用post-checkout
挂钩的退出状态
因为钩子在主要检出操作完成后运行,所以它不会影响哪个分支将成为当前分支,在工作树中更新哪些路径等,这被描述为“不会影响'检出'的结果” “。
但是,挂钩的
exit
状态被用作'exit
'命令的checkout
状态,任何产生'checkout
'的人都可以观察到,这是文档中缺少的内容。
解决这个问题。
githooks
现在包含在其man page中:
此钩子不会影响
git switch
或git checkout
的结果, 除了挂钩的退出状态变为这两个命令的退出状态。