我想运行
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
命令将提交(不是文件,不是分支,只是提交和其他支持Git的对象)推送到其他Git。一旦提交(和/或其他支持Git对象)已经到其他Git并准备在那里使用,则git push
通过请求(非强制推送)或命令(强制推送(forced push))其他Git在其存储库中创建、删除或更新某些名称来结束。
为了实现这一事件序列,git push
需要:
- 如果需要,它应该发送一些提交和/或其他支持Git对象的原始哈希ID
- 名称它应该请求/命令其他Git设置或删除,以及要做的操作(设置与删除);以及
- 强制标志(可以是简单的关闭/打开,也可以是更复杂的"租赁"风格选项之一)
你的Git——你的软件,从你的存储库发送到另一个Git,该Git是接收到目标存储库的软件——从获得以下三项
- 标志,如
+HEAD:refs/heads/sandbox
中的--force
或+
或git push --delete
中的--delete
,它们位于明显的位置 - 对于应当发送的原始散列ID,从
src:dst
对的左侧 - 对于要更新的名称,从同一对的右侧
Git调用该对本身,无论是否带有可选的+
强制标志,一个refspec。所以feature:sandbox
是refspec,HEAD:sandbox
也是refspec。事实上,即使是简并形式:
git push origin main
例如,使用refspec:它只是一个缺少冒号的部分,因此您只提供src
部分。这是部分refspec,在这种情况下,Git对目标使用与您为源提供的相同的名称(对于git push
,即git fetch
也与refspec一起使用,但它对部分refspec的处理方式不同)。
由于您已经计划使用带有冒号的完整参考规范,因此左侧的项不需要是名称。您的Git将发送到另一个Git的名称来自refspec的右侧。
现在,这里有一个小问题:如果你给你的Git一个不合格的名称,比如moo
,那么发送Git(即你的)如何知道是要求接收Git设置分支名称(refs/heads/moo
),还是标记名称(refs/tags/moo
),或者其他类型的名称(例如,Gerrit的refs/for/moo
)?答案是,你的Git和/或他们的Git会尽最大努力猜测你指的是哪种名称,但通常情况下,当你这样做时——提供完整的参考规范,也就是说——明智的做法是在右边提供完整的参考,这样你就可以确定你想让其他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:附加和分离。(注意:Git调用后一个分离的HEAD模式;我将附加的HEAD模型作为明显的对应名称,但它不是正式的Git名称。)在附加的HEA德模式中,名称HEAD
是对分支名称的符号引用1然而,在分离模式中,HEAD
保存原始提交哈希ID。
当您处于附加HEAD模式时,命令git branch --show-current
将显示HEAD
所附加的名称,但当您处于分离HEAD模式下时,命令将无提示打印任何内容并以成功状态退出。
命令git symbolic-ref HEAD
在附加HEAD模式下打印HEAD
所附加的分支的全名,并在分离HEAD模式时产生错误消息、无标准输出和非零退出代码。它使用--short
打印分支名称的短版本,但在分离时仍然产生相同的无输出但错误。
命令git rev-parse --abbrev-ref HEAD
在附加HEAD模式下打印当前分支的缩写名称,在分离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时不得不放弃这个特定的快捷方式,因为Windows缺乏符号链接。