如何检测强制更新

  • 本文关键字:更新 何检测 git
  • 更新时间 :
  • 英文 :


当远程上的分支历史记录发生更改时,您通常会得到

o git@git.server.com:XXXXX/Project.git
 + efe2e8b...cda0ee7 HEAD -> Ant_Config_processing (forced update)

有没有办法使用脚本获取此(强制更新)状态?

这个想法是编写一个别名来检测它并提示用户执行操作。

我有一个类似的问题,我想通了。

我想检测远程(裸)存储库中钩子脚本中的强制更新,所以我的答案可能不适合原始问题,但我希望对未来的访问者有用。


如何从 Git 钩子脚本中检测强制更新与否

https://github.com/kyanny/git-hooks-detect-force-update

这是一个示例 git 预接收挂钩脚本,用于了解如何检测强制更新。

结论

$ 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)
  1. 在老树中,我们有 4 个提交(*、B、*、O)并将它们推送到远程。
  2. 我们从提交 B 中签出一个新分支,它是新树。
  3. 在新树中,我们有 4 个提交(*、X、*、N),并使用 --force 选项将它们推送到远程!

推送时,钩子预接收脚本使用标准输入调用。stdin 参数的格式在 githooks(5) 中有描述。

通常,我们从 stdin 中提取两个提交对象 sha1 - oldrev 和 newrev.oldrev 是旧树的 HEAD,newrev 是新树的 HEAD

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

git rev-list oldrev ^newrev显示了可从 oldrev 访问但无法从 newrev 访问的提交。这表明提交只存在于老树上。如果此命令显示任何提交,则旧树已替换为新树,因此进行了强制更新。这就是我们想要的!

如果此命令未显示任何提交,则新树已正常更新,因此不会发生强制更新。只是。

参见

  • git-rev-list(1)
  • Git 挂钩示例:接收电子邮件后
  • git - 如何检测强制更新 - 堆栈溢出
  • githooks - Git 钩子检测推送 --mirror - 堆栈溢出
一种方法

是使用git reflog,它记录了对分支的更改。

使用

reflog,您可以在拉取/获取之前获取分支指向的位置(如果它是脚本化的,我会使用 fetch,因为它不会自动合并)并检查是否可以从分支的新远程"提示"访问该提交。

使用 bash 你可以试试这个:

$ git rev-list remotename/branchname | grep $(git rev-parse remotename/branchname@{1})
$ echo $?
1

如果它返回一个哈希(或退出状态 0),则意味着它在分支历史记录中找到了我们分支的先前提示,因此这是一个快进合并。如果它不返回任何内容(或退出状态 1),则为强制更新。

您可以检查git reflog remotename/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

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

对于快进更新,oldrevnewrev的共同祖先必须指向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

最新更新