【问题标题】:How to detect a forced update如何检测强制更新
【发布时间】:2012-05-06 08:11:09
【问题描述】:

当远程上的分支历史发生变化时,您通常会得到

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

有没有办法使用脚本获得这种(强制更新)状态?

这个想法是编写一个别名来检测它并提示用户采取行动。

【问题讨论】:

  • man githooks 提到update,可用于阻止强制更新(或类似的事情)。
  • 您可以使用receive.denyNonFastForwards 配置选项来防止 强制更新...但我不确定是否可以从 git 挂钩中检测到此类更新。
  • 谢谢,但我只需要检测一下,操作可能与阻止不同。
  • 十一月2018:在 GitHub 上,现在更容易了:stackoverflow.com/a/53343686/6309
  • @larsks 这对服务器端来说是一个很好的提示,但问题是关于客户端的。

标签: git


【解决方案1】:

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

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


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

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

通常,我们从标准输入中提取两个提交对象 sha1 - oldrev 和 newrev。 oldrev 是 老树的 HEAD,newrev 是 新树的 HEAD

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

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

如果此命令显示没有提交,则新树已正常更新,因此不会发生强制更新。很简单。

另见

【讨论】:

【解决方案2】:

一种方法是使用git reflog,它会记录对分支的更改。

使用 reflog,您可以在 pull/fetch 之前获取分支指向的位置(如果它是脚本化的,我会使用 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 reflog origin/master | head -1 | grep forced-update
【解决方案3】:

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

对于快进更新,oldrevnewrev 的共同祖先必须指向 oldrev。将示例代码放入 pre-receive 钩子以阻止非快进:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-26
    • 2019-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-28
    • 2013-10-10
    • 1970-01-01
    相关资源
    最近更新 更多