简体   繁体   English

使用 husky hook 强制推送到另一个远程分支

[英]force push to another remote branch using husky hook

I would like to run我想跑

git push origin --force CURRENT_BRANCH_NAME:sandbox

in a pre-push hook.在预推钩中。

How do I get如何得到

CURRENT_BRANCH_NAME 

as part of the above command?作为上述命令的一部分?

I understand I can have git branch --show-current to return the current branch name.我知道我可以让git branch --show-current返回当前分支名称。 Just not sure how to use its output with the above-mentioned git command.只是不确定如何将其输出与上述 git 命令一起使用。

First, I'll answer the question you actually asked:首先,我将回答您实际提出的问题:

  • To get the current branch name, use git branch --show-current or git symbolic-ref --short HEAD or git rev-parse --abbrev-ref HEAD .要获取当前分支名称,请使用git branch --show-currentgit symbolic-ref --short HEAD git rev-parse --abbrev-ref HEAD git symbolic-ref --short HEADgit rev-parse --abbrev-ref HEAD Note that these three commands do slightly different things!请注意,这三个命令的作用略有不同! See details below.请参阅下面的详细信息。

  • In POSIX-compatible shells, to substitute the output of a command in place inside another command as an argument, use either backquotes or $( and ) .在 POSIX 兼容的 shell 中,要将一个命令的输出替换为另一个命令内部的适当位置作为参数,请使用反引号或$() I prefer the $(...) sequence as it nests properly: that is, you can put another $(...) inside the $(...) and it Just Works since parentheses nest.我更喜欢$(...)序列,因为它可以正确嵌套:也就是说,您可以在$(...)放置另一个$(...)并且它可以正常工作,因为括号嵌套。 This is not true of backquotes (they can be made to work but it is trickier).反引号并非如此(它们可以起作用,但更棘手)。

Next, I'll note that you should not bother to do this.接下来,我会注意到你不应该费心这样做。 The reason is simple: you have to pick one of the above three items and two of them are probably wrong, and this is all unnecessary.原因很简单:你必须选择的一个以上的三个项目,其中两个都可能是错误的这是所有不必要的。 Simply use:只需使用:

git push --force origin HEAD:sandbox

or, for strict correctness in the case where two of the items are probably wrong:或者,在其中两项可能错误的情况下,为了严格正确:

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

This variant uses a fully qualified reference, refs/heads/sandbox , to refer to the branch name sandbox in the remote Git, regardless of the result of an attempt to turn HEAD into a Git commit hash ID.此变体使用完全限定的引用refs/heads/sandbox来引用远程 Git 中的分支名称sandbox ,无论尝试将HEAD转换为 Git 提交哈希 ID 的结果如何。

Why this works为什么这有效

The git push command pushes commits (not files, not branches, just commits and other supporting Git objects) to the other Git. git push命令将提交(不是文件,不是分支,只是提交和其他支持 Git 对象)推送到另一个 Git。 Once the commits (and/or other supporting Git objects) have made it to that other Git and are ready to be used there, then git push ends by asking (non-forced push) or commanding (forced push) the other Git to create, delete, or update some name(s) in their repository.一旦提交(和/或其它支撑GIT中的对象)都了它对其它GIT中并准备在那里被使用,那么git push通过询问(非强制推入)或命令(强制推)的其他GIT中创建、删除或更新存储库中的某些名称。

To achieve this sequence of events, git push needs:为了实现这一系列事件, git push需要:

  • the raw hash ID(s) of some commit(s) and/or other supporting Git objects it should send if / as needed;如果/根据需要,它应该发送的某些提交和/或其他支持 Git 对象的原始哈希 ID;
  • the names it should ask / command the other Git to set or delete, along with the operation to do (set vs delete);名字应该问/与操作指令的其他的Git来设置或删除,一起做(集VS删除); and
  • the force flag (which can be a simple off/on, or one of the more complicated "with lease" style options). force 标志(可以是简单的关闭/打开,或者更复杂的“带租赁”样式选项之一)。

Your Git—your software, sending from your repository, to the other Git that's software receiving into a target repository—gets these three items from:你的 Git——你的软件,从你的存储库发送到另一个 Git,它的软件接收到目标存储库——从以下位置获取这三个项目:

  • flags like --force or the + in +HEAD:refs/heads/sandbox or the --delete in git push --delete , which go in the obvious positions;标志像--force++HEAD:refs/heads/sandbox--deletegit push --delete ,其走在明显的位置;
  • for the raw hash ID(s) that should be sent , from the left side of the src : dst pair;对于应该发送的原始哈希 ID,从src : dst左侧src : dst对;
  • for the name to update , from the right side of this same pair.对于要更新名称,从同一对的右侧开始

Git calls the pair itself, with or without the optional + force flag, a refspec . Git 调用对本身,有或没有可选的+ force 标志,一个refspec So feature:sandbox is a refspec, and HEAD:sandbox is also a refspec.所以feature:sandbox是一个 refspec, HEAD:sandbox也是一个 refspec。 In fact, even the degenerate form:事实上,即使是退化形式:

git push origin main

for instance, uses a refspec: it's just one in which the colon is missing, so that you provide only a src part.例如,使用 refspec:它只是缺少冒​​号的一个,因此您只提供一个src部分。 This is a partial refspec and in this case, Git uses the same name for the target as you supplied for the source (for git push that is—while git fetch also works with refspecs, its treatment of partial refspecs is different).这是一个部分refspec,在这种情况下,Git 为目标使用与您为源提供的名称相同的名称(对于git push即——虽然git fetch也适用于 refspec,但它对部分 refspec 的处理是不同的)。

Since you already plan to use a full refspec, with the colon in it, the item on the left is not required to be a name .由于您已经计划使用包含冒号的完整refspec,因此左侧的项目不需要是name The name that your Git will send to the other Git comes from the right hand side of the refspec.你的Git会发送到其他的Git的名字来自的Refspec的右手边。

Now, there's a small hitch here: how does the sending Git (ie, yours) know whether to ask the receiving Git to set a branch name ( refs/heads/moo ), or a tag name ( refs/tags/moo ), or perhaps some other kind of name ( refs/for/moo for Gerrit for instance) if you give your Git an unqualified name like moo ?现在,这里有一个小问题:发送 Git(即你的)如何知道是否要求接收 Git 设置分支名称refs/heads/moo )或标签名称( refs/tags/moo ),如果你给你的 Git 一个像moo这样的不合格名称,或者也许是其他类型的名称(例如refs/for/moo代表 Gerrit )? The answer is that your Git and/or their Git will do their best to guess which kind of name you mean, but in general, when you are doing this—providing a full refspec , that is—it's wise to provide a full ref on the right, so that you know for sure what you intend to ask the other Git to set (or delete).答案是你的 Git 和/或他们的 Git 会尽力猜测你的意思,但一般来说,当你这样做时——提供完整的refspec ,也就是说——提供完整的参考是明智的正确的,以便您确定您打算要求其他 Git 设置(或删除)什么。 This is especially true from scripts, which may operate without a human overseer.脚本尤其如此,脚本可能在没有人工监督的情况下运行。

Hence there is a general rule here因此这里有一个一般规则

When you, as a human, are running:当你作为一个人跑步时:

git push origin feature3 v1.2

you know that feature3 is your own local branch name, and v1.2 is your own local tag name, so you know that this is really refs/heads/feature3:refs/heads/feature3 and refs/tags/v1.2:refs/tags/v1.2 .您知道feature3是您自己的本地分支名称,而v1.2是您自己的本地标签名称,所以您知道这实际上是refs/heads/feature3:refs/heads/feature3refs/tags/v1.2:refs/tags/v1.2 But in scripts , which are generally write-once run-many-times, it's wiser to be explicit.但在脚本中,通常一次编写多次运行,明确表示更明智。

Coda: the three different commands Coda:三个不同的命令

Git has two "modes" for HEAD: attached and detached . Git 有两种 HEAD 的“模式”: attacheddetached (Note: Git calls the latter detached HEAD mode; I made up the name attached HEAD mode as the obvious counterpart, but it's not officially a Git name.) In the attached-HEAD mode, the name HEAD is a symbolic reference to a branch name . (注意:Git 称后者为分离的 HEAD 模式;我将名称附加的 HEAD 模式作为明显的对应物,但它不是正式的 Git 名称。)在附加的 HEAD 模式中,名称HEAD是对分支符号引用名字 1 In the detached mode, however, HEAD holds a raw commit hash ID. 1然而,在分离模式下, HEAD持有原始提交哈希 ID。

The command git branch --show-current will show the name to which HEAD is attached when you are in attached-HEAD mode, but will silently print nothing and exit with a successful status when you are in detached-HEAD mode.命令git branch --show-current将在您处于附加 HEAD 模式时显示HEAD附加到的名称,但在您处于分离 HEAD 模式时将静默打印任何内容并以成功状态退出

The command git symbolic-ref HEAD prints the full name of the branch to which HEAD is attached when in attached-HEAD mode, and produces an error message, no standard output, and a nonzero exit code when in detached-HEAD mode.命令git symbolic-ref HEAD在附加 HEAD 模式下打印HEAD附加到的分支的全名,并在分离 HEAD 模式下生成错误消息、无标准输出和非零退出代码 It prints the short version of the branch name with --short but still produces the same no-output-but-error-instead when detached.它使用--short打印分支名称的简短版本,但在分离时仍会产生相同的 no-output-but-error- 。

The command git rev-parse --abbrev-ref HEAD prints the shortened name of the current branch when in attached-HEAD mode, and prints the word HEAD when in detached-HEAD mode.命令git rev-parse --abbrev-ref HEAD在 attach-HEAD 模式下打印当前分支的缩写名称,并在 detached-HEAD 模式下打印单词HEAD

There's one more mode worthy of mention here, although it's quite rare: when you are on an "orphan" or "unborn" branch (Git uses both terms to refer to this state), the name HEAD is a symbolic ref to a branch name that does not exist.这里还有一种模式值得一提,尽管它非常罕见:当您处于“孤儿”或“未出生”分支时(Git 使用这两个术语来指代这种状态),名称HEAD是对分支名称的符号引用那不存在。 In this state, git branch --show-current and git symbolic-ref HEAD both succeed (and print the nonexistent branch name), but git rev-parse --abbrev-rev HEAD fails.这种状态下, git branch --show-currentgit symbolic-ref HEAD git branch --show-current git symbolic-ref HEAD都成功(并打印不存在的分支名称),但git rev-parse --abbrev-rev HEAD失败。

To test which mode you're in and get the commit hash ID:要测试您处于哪种模式并获取提交哈希 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

After executing these five lines, $detached holds whether HEAD is detached (as a simple boolean result), $branch holds the branch name if HEAD is not detached, and $unborn contains the result of testing whether there is currently a commit, or making a new commit will create the current branch.执行完这五行后, $detached保存HEAD是否被分离(作为一个简单的布尔结果),如果HEAD没有分离, $branch保存分支名称, $unborn包含测试当前是否有提交,或者使新提交将创建当前分支。 (The need for $unborn is rare.) (对$unborn的需求很少见。)


1 In ancient, primeval Git, this was implemented with symlinks: ln -s refs/heads/master HEAD for instance. 1在古老的原始 Git 中,这是通过符号链接实现的:例如ln -s refs/heads/master HEAD Git had to drop this particular shortcut when it was ported to Windows, which lacked symlinks.当它被移植到缺少符号链接的 Windows 时,Git 不得不放弃这个特殊的快捷方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM