【问题标题】:force push to another remote branch using husky hook使用 husky hook 强制推送到另一个远程分支
【发布时间】:2021-12-14 20:13:53
【问题描述】:

我想跑步

git push origin --force CURRENT_BRANCH_NAME:sandbox

在预推钩中。

如何获得

CURRENT_BRANCH_NAME 

作为上述命令的一部分?

我知道我可以让git branch --show-current 返回当前分支名称。只是不确定如何将其输出与上述 git 命令一起使用。

【问题讨论】:

    标签: git shell


    【解决方案1】:

    首先,我将回答您实际提出的问题:

    • 要获取当前分支名称,请使用git branch --show-current 或git symbolic-ref --short HEAD 或git rev-parse --abbrev-ref HEAD。 请注意,这三个命令的作用略有不同!请参阅下面的详细信息。

    • 在与 POSIX 兼容的 shell 中,要将一个命令的输出替换为另一个命令中的某个位置作为参数,请使用反引号或 $( 和 )。我更喜欢 $(...) 序列,因为它可以正确嵌套:也就是说,您可以将另一个 $(...) 放在 $(...) 内,因为括号嵌套它就可以工作。反引号并非如此(它们可以工作,但更棘手)。

    接下来,我会指出您不应该费心去做这件事。原因很简单:你必须在上面三项中选择一项,其中两项可能是错误的,和这都是不必要的。只需使用:

    git push --force origin HEAD:sandbox
    

    或者,为了在其中两个项目可能错误的情况下严格正确:

    git push --force origin HEAD:refs/heads/sandbox
    

    此变体使用完全限定引用 refs/heads/sandbox 来引用远程 Git 中的分支名称 sandbox,无论尝试的结果如何将HEAD 转换为 Git 提交哈希 ID。

    为什么会这样

    git push 命令将 commits(不是文件,不是分支,只是提交和其他支持 Git 对象)推送到另一个 Git。一旦提交(和/或其他支持 Git 对象)已到其他 Git 并准备在那里使用,然后git push结束 通过询问(非强制推送)或命令(强制推送)其他 Git 在他们的存储库中创建、删除或更新某些名称。

    要实现这一系列事件,git push 需要:

    • 如果需要,它应该发送的一些提交和/或其他支持 Git 对象的原始哈希 ID;
    • names 它应该询问/命令其他 Git 设置或删除,以及要执行的操作(设置与删除);和
    • 强制标志(可以是简单的关闭/开启,或者是更复杂的“带租约”样式选项之一)。

    您的 Git(您的软件,从您的存储库发送到另一个将软件接收到目标存储库的 Git)从以下位置获取这三个项目:

    • 诸如--force 或+HEAD:refs/heads/sandbox 中的+ 或git push --delete 中的--delete 之类的标志,位于明显的位置;
    • 对于应该从<em>src</em>:<em>dst</em> 对的左侧发送的原始哈希ID;
    • 要更新的名称,来自同一对的右侧。

    Git 调用该对本身,带或不带可选的+ 强制标志,refspec。所以feature:sandbox 是一个参考规范,HEAD:sandbox 也是一个参考规范。事实上,即使是退化形式:

    git push origin main
    

    例如,使用 refspec:它只是缺少冒​​号的一个,因此您只提供 src 部分。这是一个部分 refspec,在这种情况下,Git 使用 same name 作为您为源提供的目标(对于git push,即git fetch也适用于 refspecs,它对部分 refspecs 的处理是不同的)。

    由于您已经计划使用 full refspec,其中包含冒号,因此左侧的项目不需要是 name。您的 Git 将发送给另一个 Git 的 name 来自 refspec 的右侧。

    现在,这里有一个小问题:发送 Git(即您的)如何知道是要求接收 Git 设置 分支名称 (refs/heads/moo),还是 tag 名称 (refs/tags/moo),或者其他类型的名称(例如,Gerrit 的 refs/for/moo)如果你给你的 Git 一个 unqualified 名称,比如moo?答案是您的 Git 和/或他们的 Git 会尽力猜测您的意思是哪种名称,但一般来说,当您这样做时——提供完整的 refspec em>,即在右侧提供完整的 ref 是明智的,这样您就可以确定您打算要求其他 Git 设置(或删除)什么。对于脚本来说尤其如此,它可以在没有人工监督的情况下运行。

    因此这里有一个一般规则

    当你作为人类在跑步时:

    git push origin feature3 v1.2
    

    你知道feature3是你自己的本地分支名,v1.2是你自己的本地标签名,所以你知道这真的是refs/heads/feature3:refs/heads/feature3和refs/tags/v1.2:refs/tags/v1.2。但在 脚本 中,通常是一次写入多次运行,更明智的是明确。

    Coda:三个不同的命令

    Git 有两种 HEAD 的“模式”:attached 和 detached。 (注意:Git 将后者称为分离的 HEAD 模式;我将 附加的 HEAD 模式命名为明显的对应物,但它不是正式的 Git 名称。)在附件中-HEAD 模式,名称HEAD 是对分支名称的符号引用。1在分离然而,在模式下,HEAD 拥有一个原始提交哈希 ID。

    命令git branch --show-current 将在您处于附加-HEAD 模式时显示HEAD 所附加的名称,但在您处于附加-HEAD 模式时将静默打印任何内容并以成功状态退出分离头模式。

    命令git symbolic-ref HEAD 在attached-HEAD 模式下打印HEAD 附加到的分支的全名,并产生错误消息、无标准输出和非零退出代码 在分离式 HEAD 模式下。它使用 --short 打印分支名称的简短版本,但在分离时仍会产生相同的 no-output-but-error-instead。

    命令git rev-parse --abbrev-ref HEAD 在attached-HEAD 模式下打印当前分支的缩短名称,在detached-HEAD 模式下打印单词HEAD。

    这里还有一种模式值得一提,虽然它非常罕见:当你在“孤儿”或“未出生”分支上时(Git 使用这两个术语来指代这种状态),名称 HEAD 是一个象征引用不存在的分支名称。在 这个 状态下,git branch --show-current 和 git symbolic-ref HEAD 都成功(并打印不存在的分支名称),但 git rev-parse --abbrev-rev HEAD 失败。

    测试你处于哪种模式并获取提交哈希 ID:

    detached=false unborn=false
    branch=$(git symbolic-ref --short HEAD 2>/dev/null) || detached=true
    if ! $detached; then
        git rev-parse -q --verify HEAD >/dev/null || unborn=true
    fi
    

    执行完这五行后,$detached 保存HEAD 是否分离(作为简单的布尔结果),$branch 保存HEAD 未分离的分支名称,$unborn 包含结果测试当前是否有提交,或者进行新的提交将创建当前分支。 (很少需要$unborn。)


    1在古老的原始 Git 中,这是通过符号链接实现的:例如 ln -s refs/heads/master HEAD。当 Git 移植到缺少符号链接的 Windows 时,它不得不放弃这个特定的快捷方式。

    【讨论】:

      猜你喜欢
      • 2022-01-15
      • 2013-05-03
      • 2020-06-09
      • 1970-01-01
      • 2017-12-18
      • 2019-03-17
      • 2013-04-16
      相关资源
      最近更新 更多