git push --force / -f - 如何获取每个分支

时间:2015-02-24 19:47:04

标签: git github hook githooks

这与使用git< git的push.default matching设置有关。 2.0。此外,在此特定实例中分支回购不适用。我们在工作中使用github,因为它不允许pre-receive钩子,我们必须尝试通过pre-push钩子来缓解这个问题(如果你问我,有点像半个小节,但这是一些东西)。

无论如何,我正在尝试编写一个pre-push钩子,以防止有人意外强制更新我们的master分支(或我们想要的任何分支)。但是,当我尝试进行一个试图获取分支名称的简单测试时,我似乎只能获得当前已检出的分支。我已经使用这三个git“方法”来做到这一点:

  1. $(git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
  2. $(git symbolic-ref HEAD)
  3. $(git rev-parse --abbrev-ref HEAD)
  4. 所有这三个都给了我相同的结果。这是一个例子:

    [dude (master)] $ git rebase -i head^
    # reword a commit to get into a force-push state
    [dude (master)] $ git checkout test3
    [dude (test3)] $ git push 
    branch 2>: test3 # output by the hook
    symbolic-ref: refs/heads/test3 # output by the hook
    rev-parse: test3 # output by the hook
    --- pre-push: nothing to check # output by the hook
    To git@github.com:dude/stuff.git
     ! [rejected]        master -> master (non-fast-forward)
    error: failed to push some refs to 'git@github.com:dude/stuff.git'
    hint: bla bla bla
    

    现在应用强制更新:

    [dude (test3)] $ git push -f
    branch 2>: test3 # output by the hook
    symbolic-ref: refs/heads/test3 # output by the hook
    rev-parse: test3 # output by the hook
    --- pre-push: nothing to check # output by the hook
    Counting objects: 1, done.
    Writing objects: 100% (1/1), 185 bytes | 0 bytes/s, done.
    Total 1 (delta 0), reused 0 (delta 0)
    To git@github.com:dude/stuff.git
     + 060fa0b...763516d master -> master (forced update)
    

    如您所见,仅引用test3分支。我想知道什么时候git即将推送master分支。有谁知道强制更新在幕后做了什么?

1 个答案:

答案 0 :(得分:1)

Git确实只有“一个当前分支”的概念,即HEAD中存储的任何符号引用(如果有的话)。 (如果你处于“超级HEAD”模式,那么你根本就不在任何分支上,所以完整的答案是在git中,你“在”上根本没有分支,或者一个分支存储在HEAD中。)

然而,push命令采用用户指定的任意一组“refspecs”。从宽松的角度来说,refspec只是一个源和目标引用对,例如master:masterrefs/heads/master:refs/heads/master。如果在push命令中指定 no refspecs,git会使用一些默认值,正如您所观察到的那样,它已经随着时间的推移发生了变化(以前是matching,现在它是{ {1}},但可以使用simple配置以及push.default和更多项目进行更改。 1

Refspecs可以使用前导remote.name.push进行扩充,仅为该refspec设置+,或者您当然可以在推送命令行上使用--force为所有refspec设置它。并且,对于--force,refspec的“source”端可以是任意提交标识符(例如git push或原始SHA-1),或者对于“delete”操作为空;并且“目标”方面不需要完全限定(git通常会自行计算分支与标记)。

我认为重现HEAD使用的规则要困难得多,尤其是在预推钩中。而且,不幸的是,推送前挂钩不会为您提供git push全局设置每个refspec --force - 或来自全球的力量的副本旗。但是,它会在标准输入(以及作为参数的远程名称和URL)上为您提供建议更新的完整列表。因此:

+

为了将(根本)推送到服务器上的#! /bin/sh # sample pre-push hook, not tested case "$1" in origin) ;; *) echo "pushing to $1, not doing any checking" 1>&2 exit 0;; # allow the push esac STATUS=0 disallow() { echo "pre-push hook: stopping your push" 1>&2 echo "reason: $@" 1>&2 STATUS=1 } # pushing to remote named "origin": do some simple tests while read localref localsha remoteref remotesha; do case $remoteref in refs/heads/master) disallow "push goes to master" ;; # add more tests here as desired esac done exit $STATUS ,可以简单地将master远程复制到另一个名称,然后再复制origin。或者,您可以使用loganfsmyth's comment中的脚本来尝试猜测是否在命令行上给出了git push Xorigin master:master(或加号)。

另一种可能性是在推送过程中使用--force更新您的信息,以便在推送过程中联系远程(可能是通过URL进行URL推送,但这会使一切变得复杂)它的提交图,然后尝试发现提议的标签移动是否实际上是快进。我不确定这是否会起作用(当你正在提出更新推送时,git是否允许读取远程存储库?它可能会这样做,但我不知道),并且它有点棘手,它仍然无法判断用户是否明确要求强制 -push,但它可以解决大部分问题。


1 从技术上讲,“匹配”和“简单”都不是 refspec。相反,这些是git计算refspec的规则。这当然是问题的一部分:在命令行输入命令的点和各种数据传输开始的点之间有很多内部魔法。在计算refspecs之后,但在你的git开始向遥控器发送更新之前,会调用pre-push hook。