git - 使用 husky hook 强制推送到另一个远程分支
问题描述
我想跑步
git push origin --force CURRENT_BRANCH_NAME:sandbox
在预推钩中。
如何得到
CURRENT_BRANCH_NAME
作为上述命令的一部分?
我知道我必须git branch --show-current
返回当前的分支名称。只是不确定如何将其输出与上述 git 命令一起使用。
解决方案
首先,我将回答您实际提出的问题:
要获取当前分支名称,请使用
git branch --show-current
orgit symbolic-ref --short HEAD
或git rev-parse --abbrev-ref HEAD
。 请注意,这三个命令做的事情略有不同! 请参阅下面的详细信息。在与 POSIX 兼容的 shell 中,要将一个命令的输出替换为另一个命令中的某个位置作为参数,请使用反引号或
$(
and)
。我更喜欢这个$(...)
序列,因为它可以正确嵌套:也就是说,你可以$(...)
在里面放另一个$(...)
,因为括号嵌套它就可以工作。反引号并非如此(它们可以工作,但更棘手)。
接下来,我会注意到你不应该费心去做这件事。原因很简单:你必须在上面三项中选择一项,其中两项可能是错误的,这都是不必要的。只需使用:
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 创建、删除来git push
结束,或更新其存储库中的某些名称。
要实现这一系列事件,git push
需要:
- 一些提交和/或其他支持 Git 对象的原始哈希 ID,如果 / 需要,它应该发送;
- 它应该要求/命令其他 Git 设置或删除的名称,以及要执行的操作(设置与删除);和
- 强制标志(可以是简单的关闭/开启,或者是更复杂的“带租约”样式选项之一)。
您的 Git(您的软件,从您的存储库发送到另一个将软件接收到目标存储库的 Git)从以下位置获取这三个项目:
--force
像或+
in+HEAD:refs/heads/sandbox
或--delete
in之类的标志git push --delete
,它们位于明显的位置;- 对于应该发送的原始哈希 ID ,从对的左侧开始;
src:dst
- 从同一对的右侧更新名称。
Git 调用该对本身,有或没有可选的+
强制标志,一个refspec。refspec 也是如此feature:sandbox
,HEAD:sandbox
也是 refspec。事实上,即使是退化形式:
git push origin main
例如,使用 refspec:它只是缺少冒号的一个,因此您只提供src
一部分。这是一个部分refspec,在这种情况下,Git 使用与您为源提供的名称相同git push
的目标名称(因为这git fetch
也适用于 refspecs,但它对部分 refspecs 的处理是不同的)。
由于您已经计划使用包含冒号的完整refspec,因此左侧的项目不需要是name。您的 Git 将发送给另一个 Git的名称来自 refspec 的右侧。
现在,这里有一个小问题:发送 Git(即你的)如何知道是否要求接收Git设置分支名称(例如)如果你给你的 Git 一个不合格的名字,比如?答案是您的 Git 和/或他们的 Git 会尽力猜测您的意思是哪种名称,但总的来说,当您这样做时 - 提供完整的refspec,也就是说 - 提供完整的ref是明智的refs/heads/moo
refs/tags/moo
refs/for/moo
moo
在右侧,以便您确定您打算要求其他 Git 设置(或删除)什么。脚本尤其如此,脚本可能在没有人工监督的情况下运行。
因此这里有一个一般规则
当您作为人类跑步时:
git push origin feature3 v1.2
您知道这feature3
是您自己的本地分支名称,并且v1.2
是您自己的本地标记名称,因此您知道这确实是refs/heads/feature3:refs/heads/feature3
and refs/tags/v1.2:refs/tags/v1.2
。但是在通常是一次写入多次运行的脚本中,明确的做法更明智。
Coda:三个不同的命令
Git 有两种 HEAD 的“模式”:attached和detached。(注意:Git 将后者称为分离 HEAD 模式;我将附加 HEAD 模式命名为明显的对应物,但它不是正式的 Git 名称。)在附加-HEAD 模式中,名称HEAD
是对分支名称的符号引用. 1但是, 在分离模式下,会保存一个原始提交哈希 ID。HEAD
当您处于附加-HEAD 模式时,该命令git branch --show-current
将显示附加到的名称,但当您处于分离-HEAD 模式时,它将静默不打印任何内容并以成功状态退出。HEAD
该命令在 attach-HEAD 模式下打印附加git symbolic-ref HEAD
到的分支的全名,并在 detached-HEAD 模式下产生错误消息、无标准输出和非零退出代码。它打印分支名称的简短版本,但在分离时仍会产生相同的 no-output-but-error-instead。HEAD
--short
该命令git rev-parse --abbrev-ref HEAD
在 attach-HEAD 模式下打印当前分支的缩短名称,并HEAD
在 detached-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
例如。当它被移植到缺少符号链接的 Windows 时,Git 不得不放弃这个特定的快捷方式。
推荐阅读
- php - 如何在 2 个数组中打印第一个 15 天和下一个 15 天的所有日期?
- python - 如何比较两个表的 id 以及当它们相等时在另一列中添加一个值
- iframe - 如果设置了 allow-same-origin,则 amp-iframe 的来源不得等于容器
- javascript - 以形状对齐的文本
- ios - 使用带有 SKShapenode 线的 PhysicsBody。斯威夫特,iOS,SpriteKit
- alfresco - 如何使用 Alfresco 访问、打开和阅读电子邮件
- javascript - 选择tr时如何排除第一个td?CSS, jQuery
- android - PeriodicWorkRequest 触发时间
- firebase - 如何使用 firebaseui-web autoUpgradeAnonymousUsers?
- java - Java WAR 文件部署问题