git 如何检测强制更新
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10319110/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to detect a forced update
提问by Olivier Refalo
When a branch history is changed on the remote, you typically get
当远程更改分支历史记录时,您通常会得到
o [email protected]:XXXXX/Project.git
+ efe2e8b...cda0ee7 HEAD -> Ant_Config_processing (forced update)
Is there any way to get this (forced update) status using scripting ?
有什么方法可以使用脚本获得这个(强制更新)状态?
The idea is to write an alias that detects it and prompt the user for actions.
这个想法是编写一个别名来检测它并提示用户采取行动。
回答by kyanny
I have a similar problem and I figured out it.
我有一个类似的问题,我想通了。
I want to detect forced update within hook script in remote (bare) repository, So my answer might not be suitable for original question, but I hope to be useful my answer for future visitors.
我想检测远程(裸)存储库中钩子脚本中的强制更新,所以我的回答可能不适合原始问题,但我希望我的回答对未来的访问者有用。
How to detect forced update or not from in Git hooks script
如何在 Git 钩子脚本中检测是否强制更新
https://github.com/kyanny/git-hooks-detect-force-update
https://github.com/kyanny/git-hooks-detect-force-update
This is a sample git pre-receive hook script for learning about how to detect forced update.
这是一个示例 git pre-receive 钩子脚本,用于了解如何检测强制更新。
Conclusion
结论
$ git rev-list oldrev ^newrev
How to test
如何测试
$ rake -T
rake forced_push # git hooks test detect forced update
rake normal_push # git hooks test
Step-by-Step introduction
分步介绍
Firstly, I describe a syntax of git-rev-list(1).
首先,我描述了git-rev-list(1)的语法。
In this case, we assume within a Git working repository that has this straight history.
在这种情况下,我们假设在具有这种直接历史的 Git 工作存储库中。
1 --- 2 --- O --- X --- 3 --- 4 --- N
General usage of git-rev-list
is below.
的一般用法git-rev-list
如下。
$ git rev-list N
This command will show all of commits reachable from commit N (note: git-rev-list
shows commits reverse chronological order)
此命令将显示从提交 N 可到达的所有提交(注意:git-rev-list
显示提交逆时间顺序)
git-rev-list
accepts multiple arguments.
git-rev-list
接受多个参数。
$ git rev-list N O
This command will show same output as git rev-list N
, because commit O is an ancestor of commit N.
此命令将显示与 相同的输出git rev-list N
,因为提交 O 是提交 N 的祖先。
Then, git-rev-list
allows you to exclude commits from output.
然后,git-rev-list
允许您从输出中排除提交。
$ git rev-list N ^O
^O means that to exclude commits reachable from O, so this command will show N, 4, 3, X (note: O is excluded)
^O 表示排除从 O 可达的提交,因此该命令将显示 N, 4, 3, X (注意:O 被排除在外)
Since we are learned about git-rev-list
, I describe a case about forced update occured.
由于我们了解了git-rev-list
,我描述了一个关于发生强制更新的案例。
In this case, we assume within a Git working repository that has this complex history.
在这种情况下,我们假设在一个具有复杂历史的 Git 工作存储库中。
* --- B --- * --- O ($oldrev)
\
* --- X --- * --- N ($newrev)
- In old tree, we had 4 commits (*, B, *, O) and pushed them to remote.
- We checkout a new branch from commit B, it's new tree.
- In new tree, we had 4 commits (*, X, *, N) and pushed them to remote with --force option!
- 在老树中,我们有 4 个提交(*、B、*、O)并将它们推送到远程。
- 我们从提交 B 中检出一个新分支,它是新树。
- 在新树中,我们有 4 个提交(*、X、*、N)并使用 --force 选项将它们推送到远程!
When pushed, hook pre-receive script invoked with standard input. The format of stdin parameter is described at githooks(5).
推送时,挂钩预接收脚本使用标准输入调用。标准输入参数的格式在githooks(5) 中描述。
Typically, we extract two commit object sha1 from stdin - oldrev and newrev. oldrev is HEAD of old tree, newrev is HEAD of new tree.
通常,我们从标准输入中提取两个提交对象 sha1 - oldrev 和 newrev。oldrev 是老树的HEAD,newrev 是新树的 HEAD。
In this situation, we can detect forced push by git-rev-list
output.
在这种情况下,我们可以通过git-rev-list
输出检测强制推送。
git rev-list oldrev ^newrev
shows the commits reachable from oldrev but not reachable from newrev. This shows the commits existed only old tree.
If this command show any commits, old tree was replaced with new tree, so forced update was occured. This is what we want!
git rev-list oldrev ^newrev
显示可从 oldrev 访问但无法从 newrev 访问的提交。这表明提交只存在于 old tree。如果此命令显示任何提交,则旧树被新树替换,因此发生强制更新。这就是我们想要的!
If this command show none of commits, new tree was normally updated, so forced update was not occured. Simply.
如果此命令显示没有提交,则新树通常已更新,因此不会发生强制更新。简单地。
See Also
也可以看看
回答by KurzedMetal
One way to do it would be using git reflog
, it keeps a record of the changes to the branch.
一种方法是使用git reflog
,它会记录对分支的更改。
With reflog, you can get where your branch pointed before the pull/fetch (i'd use a fetch if it is scripted, since it doesn't automatically merge) and check if that commit is reachable from the new remote's "tip" of the branch.
使用 reflog,您可以在 pull/fetch 之前获取分支指向的位置(如果它是脚本化的,我会使用 fetch,因为它不会自动合并)并检查该提交是否可从新远程的“提示”访问分支。
Using bash you can try this:
使用 bash 你可以试试这个:
$ git rev-list remotename/branchname | grep $(git rev-parse remotename/branchname@{1})
$ echo $?
1
If it returns a hash (or exit status 0) it means that it found our previous tip of the branch in the branch history, so it was a fast forward merge. If it returns nothing (or exit status 1), it was forced update.
如果它返回一个散列(或退出状态 0),则意味着它在分支历史记录中找到了我们之前的分支尖端,因此它是一个快进合并。如果它什么都不返回(或退出状态 1),则它被强制更新。
You can check the git reflog remotename/branchname
output to see if branchname got a forced update.
您可以检查git reflog remotename/branchname
输出以查看 branchname 是否进行了强制更新。
$ git reflog remotename/branchname
dc2afab refs/remotes/remotename/branchname@{0}: fetch rewrite: forced-update
4603c2c refs/remotes/remotename/branchname@{1}: fetch rewrite: forced-update
回答by FiNo
You can use git-merge-base
command, it finds nearest common ancestor for two commits.
您可以使用git-merge-base
命令,它会为两次提交找到最近的共同祖先。
For fast-forward update, common ancestor for oldrev
and newrev
must point to oldrev
. Sample code to be put into pre-receive hook to block non fast-forward:
对于快进更新,公共祖先 foroldrev
和newrev
must 指向oldrev
. 要放入预接收钩子以阻止非快进的示例代码:
mergebase=`git merge-base $oldrev $newrev`
if [ "$oldrev" != "$mergebase" ]; then
echo "Non fast-forward update not allowed for $refname, from ${oldrev:0:16} to ${newrev:0:16} merge base ${mergebase:0:16}"
exit 1
fi