Git 如何检测强制更新

Git 如何检测强制更新,git,Git,在远程上更改分支历史记录时,通常会 o git@git.server.com:XXXXX/Project.git + efe2e8b...cda0ee7 HEAD -> Ant_Config_processing (forced update) 有没有办法使用脚本获取此(强制更新)状态 其思想是编写一个别名来检测它并提示用户进行操作。一种方法是使用git reflog,它会记录分支的更改 使用reflog,您可以在拉/取之前获得分支指向的位置(如果它是脚本化的,我将使用取,因为它不会自

在远程上更改分支历史记录时,通常会

o git@git.server.com:XXXXX/Project.git
 + efe2e8b...cda0ee7 HEAD -> Ant_Config_processing (forced update)
有没有办法使用脚本获取此(强制更新)状态


其思想是编写一个别名来检测它并提示用户进行操作。

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

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

使用bash,您可以尝试以下操作:

$ git rev-list remotename/branchname | grep $(git rev-parse remotename/branchname@{1})
$ echo $?
1
如果它返回一个散列(或退出状态0),则表示它在分支历史记录中找到了我们以前的分支提示,因此它是一个快进合并。如果不返回任何内容(或退出状态1),则强制更新

$ 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 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

我有一个类似的问题,我发现了

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


如何在Git hooks脚本中检测强制更新或不强制更新

这是一个git预接收钩子脚本示例,用于学习如何检测强制更新

$ 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工作存储库中有这样的直接历史记录

1 --- 2 --- O --- X --- 3 --- 4 --- N
git版本列表的一般用法如下所示

$ git rev-list N
此命令将显示从commit N可访问的所有提交(注意:
git rev list
按逆时间顺序显示提交)

git rev list
接受多个参数

$ git rev-list N O
此命令将显示与git rev list N相同的输出,因为commit O是commit 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参数的格式如所述

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

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

    git rev list oldrev^newrev
    显示可从oldrev访问但不能从newrev访问的提交。这表明提交只存在于旧树中。 如果此命令显示任何提交,则旧树将替换为新树,因此发生强制更新。这就是我们想要的

    如果此命令不显示任何提交,则新树通常会更新,因此不会发生强制更新。很简单

    另见

    您可以使用
    git merge base
    命令,它为两次提交查找最近的公共祖先

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

    man-githooks
    提到了
    update
    ,它可以用来阻止强制更新(或类似的事情)。你可以使用
    receive.denynonfastforts
    配置选项来阻止强制更新…但我不确定是否可以从git-hook检测到这样的更新。谢谢,但我只需要检测,该操作可能与blocking.Nov不同。2018年:在GitHub上,现在更容易了:@larsks这对服务器端来说是一个很好的提示,但问题是关于客户端。这是个好主意,让我在不同的场景中尝试一下,应该可以工作
    git reflog origin/master | head-1 | grep forced update
    Hey@kyanny,也许你能添加最后1-2行?(我不确定如何检查
    git rev list oldrev^newrev
    脚本中是否存在空白。)