【问题标题】:In pre-push hook, get "git push" command full content?在 pre-push 钩子中,获取“git push”命令的全部内容?
【发布时间】:2017-07-16 06:44:48
【问题描述】:

当一个 Git pre-push hooks 脚本运行时,如何获取完整的git push 命令内容?

例如,当我运行:git push origin master 时,执行了预推送挂钩。
我想在这个钩子里得到origin & master

如何获取参数列表?

【问题讨论】:

    标签: git shell githooks git-push


    【解决方案1】:

    TL;DR 总结:你需要一个 while 循环

    您的钩子脚本(假设为 sh/bash)应包含以下形式的循环:

    while read localname localhash remotename remotehash; do
        ... code here using $localname etc ...
    done
    

    说明

    the githooks page 中描述了所有 Git 挂钩。 pre-push 钩子描述以:

    开头

    这个钩子由 git push 调用,可以用来防止推送发生。使用两个参数调用挂钩,提供目标远程的名称和位置,如果未使用命名远程,则两个值将相同。

    钩子的标准输入中提供了有关要推送的内容的信息,格式如下:

    <local ref> SP <local sha1> SP <remote ref> SP <remote sha1> LF
    

    例如,如果命令 git push origin master:foreign 运行,钩子将收到如下行:

    refs/heads/master 67890 refs/heads/foreign 12345
    

    虽然将提供完整的 40 个字符的 SHA-1。 ...

    第一段表示在 shell 脚本中,$1$2 是远程的名称(例如,origin)及其 URL,或者如果用户运行,则 URL 重复两次:

    git push https://some.host.name/some/path ...
    

    第二段是重要的git push 命令可以推送多个分支。例如,我可以运行:

    git push origin feature-A feature-B
    

    同时推送feature-A feature-B。您必须阅读所有输入行,一次一行,以发现要推送的内容。存储库中的当前 分支并不重要:阅读HEAD 会给你错误的答案除非用户碰巧正在推送当前分支。另一方面,大多数用户大多只是推送当前分支。这会让您产生一种错觉,即您的 hook 是 100% 可靠的,而实际上只有 92.37% 可靠。1

    如文档所述,钩子获取每个引用的全名。如果您正在推送一个分支,则该全名以refs/heads/ 开头,但您可以推送一个标签,在这种情况下,全名以refs/tags/ 开头。要编写可靠的钩子,您必须检查全名,而不是简单地剥离前两个组件。2


    1和 38.61% 的统计数据一样,这个是当场编造的。 :-)

    2有很多不好的示例钩子(不是所有的 pre-push 钩子)都在使用:

    branch=$(echo $ref | cut -d/ -f3)
    

    如果你正在推送标签v2.3,这个钩子会认为你正在推送一个名为v2.3分支。如果你正在推送一个名为bugfix/1234 的分支,它会认为你正在推送一个名为bugfix 的分支! cut 技术是错误的,但后者的快速解决方法是使用-f3-,它至少会产生bugfix/1234。最好验证 ref 的第一个组件——即,执行以下操作:

    case $ref in
    refs/heads/*) ... it's a branch ...;;
    refs/tags/*) ... it's a tag ...;;
    *) ... it's something else entirely, such as refs/notes/* ...;;
    esac
    

    一旦知道前缀,就可以使用${ref#refs/heads/}${ref#refs/tags/} 去除已知前缀并获得完整但不合格的分支或标记名称。但是,如果在很多情况下,您可以直接使用完整的参考名称。

    【讨论】:

      【解决方案2】:

      这些参数作为命令行参数传递给钩子,您可以从那里获取它们。例如:

      #!/bin/sh
      
      remote="$1"
      url="$2"
      
      echo "remote: $1 ; url $2"
      
      exit 0
      

      【讨论】:

      • 感谢 Mureinik,$1,我可以得到“origin”,$2 是远程存储库 url 地址。但我也想成为“大师”。
      【解决方案3】:

      这些参数被传递给钩子

      在钩子中你可以得到这样的分支名称:

      branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')
      

      如果您也希望在终端中查看这些设置,而不是作为脚本的一部分,请使用这些命令:

      # get the name of the tracking branches
      git branch -a -vv
      
      # or: 
      git status -b --porcelain
      
      # to get the name of the current branch:
      git symbolic-ref -q HEAD
      

      如何绕过pre-push 钩子?

      git push --no-verify
      

      【讨论】:

      • 感谢codewizard,我也想得到分支信息,例如:“master”,但是$1和$2都不是。如何获取分行信息?
      • 我更喜欢git status -b --short 而不是git status -b --porcelain。如果您启用了color.status 配置(默认),它会以更易读的方式提供相同的信息。 porcelain 选项默认禁用颜色。
      • 在这里同意 :-)
      • @SebTu: --porcelain 用于脚本,其中颜色会妨碍脚本解释输出。 --short 用于人类消费,除非您是色盲,否则颜色很有用:-)
      • -1;如果分支名称包含/,您的sed 咒语将返回错误结果。最好使用git rev-parse --abbrev-ref HEAD 直接获取当前分支名称(不带refs/heads 前缀),避免进行此类操作。
      猜你喜欢
      • 2014-02-15
      • 1970-01-01
      • 2017-09-19
      • 1970-01-01
      • 1970-01-01
      • 2016-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多