【发布时间】:2021-12-14 20:13:53
【问题描述】:
我想跑步
git push origin --force CURRENT_BRANCH_NAME:sandbox
在预推钩中。
如何获得
CURRENT_BRANCH_NAME
作为上述命令的一部分?
我知道我可以让git branch --show-current 返回当前分支名称。只是不确定如何将其输出与上述 git 命令一起使用。
【问题讨论】:
我想跑步
git push origin --force CURRENT_BRANCH_NAME:sandbox
在预推钩中。
如何获得
CURRENT_BRANCH_NAME
作为上述命令的一部分?
我知道我可以让git branch --show-current 返回当前分支名称。只是不确定如何将其输出与上述 git 命令一起使用。
【问题讨论】:
首先,我将回答您实际提出的问题:
要获取当前分支名称,请使用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(您的软件,从您的存储库发送到另一个将软件接收到目标存储库的 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。但在 脚本 中,通常是一次写入多次运行,更明智的是明确。
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 时,它不得不放弃这个特定的快捷方式。
【讨论】: