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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-19 06:50:08  来源:igfitidea点击:

How to detect a forced update

git

提问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-listis below.

的一般用法git-rev-list如下。

$ git rev-list N

This command will show all of commits reachable from commit N (note: git-rev-listshows commits reverse chronological order)

此命令将显示从提交 N 可到达的所有提交(注意:git-rev-list显示提交逆时间顺序

git-rev-listaccepts 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-listallows 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)
  1. In old tree, we had 4 commits (*, B, *, O) and pushed them to remote.
  2. We checkout a new branch from commit B, it's new tree.
  3. In new tree, we had 4 commits (*, X, *, N) and pushed them to remote with --force option!
  1. 在老树中,我们有 4 个提交(*、B、*、O)并将它们推送到远程。
  2. 我们从提交 B 中检出一个新分支,它是新树。
  3. 在新树中,我们有 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-listoutput.

在这种情况下,我们可以通过git-rev-list输出检测强制推送。

git rev-list oldrev ^newrevshows 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/branchnameoutput 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-basecommand, it finds nearest common ancestor for two commits.

您可以使用git-merge-base命令,它会为两次提交找到最近的共同祖先。

For fast-forward update, common ancestor for oldrevand newrevmust point to oldrev. Sample code to be put into pre-receive hook to block non fast-forward:

对于快进更新,公共祖先 foroldrevnewrevmust 指向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