如何检测强制更新

时间:2012-04-25 15:47:16

标签: git

当在遥控器上更改分支历史记录时,通常会获得

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

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

我们的想法是编写一个检测它的别名并提示用户进行操作。

3 个答案:

答案 0 :(得分:23)

我有类似的问题,我想出来了。

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


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

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选项将它们推送到远程!
  4. 按下时,使用标准输入调用钩子预接收脚本。 stdin参数的格式在githooks(5)描述。

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

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

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

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

    另见

答案 1 :(得分:6)

一种方法是使用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

答案 2 :(得分:3)

你可以使用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