我有类似的问题,我想通了。
我想在远程(裸)存储库中检测挂钩脚本中的强制更新,所以我的回答可能不适合原始问题,但我希望我的回答对未来的访问者有用。
如何在 Git hooks 脚本中检测是否强制更新
https://github.com/kyanny/git-hooks-detect-force-update
这是一个示例 git pre-receive 挂钩脚本,用于了解如何检测强制更新。
结论
$ git rev-list oldrev ^newrev
如何测试
$ rake -T
rake forced_push # git hooks test detect forced update
rake normal_push # git hooks test
分步介绍
首先,我描述一个git-rev-list(1)的语法。
在这种情况下,我们假设在 Git 工作存储库中具有此直接历史记录。
1 --- 2 --- O --- X --- 3 --- 4 --- N
git-rev-list 的一般用法如下。
$ git rev-list N
此命令将显示从提交 N 可到达的所有提交(注意:git-rev-list 显示提交时间倒序)
git-rev-list 接受多个参数。
$ git rev-list N O
此命令将显示与git rev-list N 相同的输出,因为提交 O 是提交 N 的祖先。
然后,git-rev-list 允许您从输出中排除提交。
$ git rev-list N ^O
^O 表示排除 O 可达的提交,因此该命令将显示 N, 4, 3, X (注意:排除 O)
由于了解git-rev-list,我描述了一个发生强制更新的案例。
在这种情况下,我们假设在一个具有复杂历史的 Git 工作存储库中。
* --- B --- * --- O ($oldrev)
\
* --- X --- * --- N ($newrev)
- 在旧树中,我们有 4 个提交(*、B、*、O)并将它们推送到远程。
- 我们从提交 B 签出一个新分支,它是新树。
- 在新树中,我们有 4 个提交(*、X、*、N)并使用 --force 选项将它们推送到远程!
推送时,挂钩使用标准输入调用的预接收脚本。 stdin 参数的格式在githooks(5) 有描述。
通常,我们从标准输入中提取两个提交对象 sha1 - oldrev 和 newrev。 oldrev 是 老树的 HEAD,newrev 是 新树的 HEAD。
在这种情况下,我们可以通过git-rev-list输出检测强制推送。
git rev-list oldrev ^newrev 显示可从 oldrev 访问但无法从 newrev 访问的提交。这显示了提交只存在于老树。
如果此命令显示任何提交,则旧树被新树替换,因此发生了强制更新。这就是我们想要的!
如果此命令显示没有提交,则新树已正常更新,因此不会发生强制更新。很简单。
另见