命令1做什么命令2没有?
1. git push <projectpath> HEAD:refs/heads/<branch>
2. git push <projectpath> <branch>
Run Code Online (Sandbox Code Playgroud)
"HEAD:refs/heads /"是什么意思?
tor*_*rek 17
VonC的答案是正确的(并且被赞成),但我认为另一种看待这种情况的方式可能更有意义.
请注意,所有这一切都假设您使用的是四字形式git push,即.这里的部分通常只是名称.我们马上就会更好地定义.git push remote refspecremoteoriginrefspec
git push呢有什么git push需要做的(因此不)是调用了另一个Git的实例另一台机器上,1然后给其他Git的一组引用(通常分支名称,有时标记名称)来更新.一个参考是一个简单的名称,如master或v1.2,在理想情况下应该是完全限定(refs/heads/master或refs/tags/v1.2),这样我们就可以知道是什么样的呢引用分支,标签,或什么的.
为了让其他Git更新你的Git移交的引用,你的Git 也必须移交一些丑陋的SHA-1哈希:每个引用一个.换句话说,你的Git会要求他们的Git设置他们 refs/heads/master的,比如说ed4f38babf3d81693a68d06cd0f5872093c009f6.(此时 - 实际上,在这一点之前,真的 - 你的Git和他们的Git谈论了你想要发送它们的对象,以及它们已经拥有的对象,所有这些都是由这些丑陋的哈希ID完成的.两个控释同意这是怎么回事要送过来,你做的counting objects和compressing objects,然后将它们的对象.在"现在,请设置一些名字"的一部分发生了近即止.)
请注意,Git的请求有两个部分:(1)完全限定的引用,以及(2)big-ugly-hash.(事实上,还有第三部分,--force旗帜,但这部分很容易,我们可以忽略它.)但是你的 Git 在哪里获得这些?
如果你写:
git push origin somename
Run Code Online (Sandbox Code Playgroud)
你已经给你的 Git两条信息了:origin你的Git用来查找URL的名字和名字somename.你的Git使用它来计算全名.是somename标签吗?如果是这样,全名是refs/tags/somename.是somename分支吗?如果是这样,全名是refs/heads/somename.无论哪种方式都有效.当然,您也可以自己写出全名 - 如果名称既是分支又是标记,您可能想要这样做,而不是让Git为您选择一个.2
那么,你的Git在哪里获得了大丑陋的哈希?答案是:来自同一个名字.名称somename,无论是分支还是标记,只是命名一些特定的Git对象.如果你想自己看哈希,你可以随时做到:
git rev-parse somename
Run Code Online (Sandbox Code Playgroud)
会告诉你.事实上,这就是我得到的结果ed4f38babf3d81693a68d06cd0f5872093c009f6:我去了Git的Git存储库并且确实git rev-parse v2.1.1打印出了这个哈希,因为v2.1.1版本2.1.1出现后,它是Git存储库的任何完整副本中的有效标记.
需要注意的是,当你做使用这种形式,这种形式,Git会查找起来的说法在你的资料库有两种用途:找出它的全名,并获得它的哈希值.你的位置并不重要,只有全名所指的.git push remote namenameHEAD
第四个参数git push叫做refspec,它的语法实际上允许用冒号分隔两个部分:
git push origin src:dst
Run Code Online (Sandbox Code Playgroud)
在这种情况下,该dst部件提供名称,但该src部件提供哈希.Git运行src部分git rev-parse并生成哈希.所以你可以:
git push origin mybranch:refs/tags/v42
Run Code Online (Sandbox Code Playgroud)
v42使用分支mybranch标识的任何提交哈希在其他Git存储库中创建标记.
HEAD包含分支名称在Git中,HEAD 始终为当前提交命名. 通常它通过命名分支,并让分支命名提交来实现.因此,通常HEAD包含一个分支名称master,并且分支名称总是为您提供该分支的提示(这就是Git 定义 "tip commit"的方式;请参阅Git词汇表中分支的定义).但总是,3 HEAD可以变成提交:
$ git rev-parse HEAD
2b9288cc90175557766ef33e350e0514470b6ad4
Run Code Online (Sandbox Code Playgroud)
因为HEAD是分支名称(然后是提示提交),或者你有一个"分离的HEAD",在这种情况下,Git直接存储当前的提交ID HEAD.
请记住,为了推送,Git需要获取这两个信息:哈希和(完整)名称.当HEAD 不是 "分离"时,Git可以从中获取它们:HEAD具有分支名称 - 实际上是全名形式 - 并且分支名称具有散列.但是当你处于"超级HEAD"模式时,HEAD只有一个哈希值.Git的不能找到一个分支的名字HEAD.有可能不会是一个:你可能已签出由ID提交,或者你签出的标记名称,如:
$ git checkout v2.1.1
Run Code Online (Sandbox Code Playgroud)
这使你处于这种"独立的HEAD"模式.
在这种情况下,Git会要求您提供两个源哈希src-你仍然可以使用名称HEAD来获得它- 和在dst目的地名称.并且,如果你使用它HEAD作为源,Git真的需要你拼出完整的目的地,因为Git在这一点上无法分辨它是否应该是branch(refs/heads/dst)或tag(refs/tags/dst).4
git push您可以git push使用较少的参数运行,例如:
git push origin
Run Code Online (Sandbox Code Playgroud)
甚至只是:
git push
Run Code Online (Sandbox Code Playgroud)
这里发生的是没有a refspec,Git push.default首先咨询你的设置.通常这是simple(自Git 2.0版以来的默认值).在这种情况下,Git只是HEAD用来确定推送什么 - 当然,只有在HEAD没有分离的情况下才能工作.这正是我们上面所描述的.
(其他三个设置也可以使用HEAD.其中一个 - 在Git 2.0版之前默认的那个 - 没有,但是这个特定的设置证明太容易出错,这就是默认改变的原因.你可能不应该使用它,至少除非你是Git大师.)
(并且,如果你遗漏了remote,Git再次HEAD用来计算推送到哪里,默认,如果需要的话origin.)
您还可以推送多个refspecs:
git push origin branch1 branch2 tag1 HEAD:refs/tags/tag2
Run Code Online (Sandbox Code Playgroud)
在这种情况下,每个refspec都以通常的方式处理:如果需要,获取它的完全限定名称,这样你的Git每次都可以给他们的Git一个完全限定的名字; src:dst如果您没有使用该src:dst表单,则查找其哈希ID (或者如果您确实使用了表单,请查找其srcID).
您可以在refspecs中使用通配符:
git push origin 'refs/heads/*:refs/heads/*'
Run Code Online (Sandbox Code Playgroud)
(有些炮弹会吃,修改,增加倍,主轴,或毁坏的*太您可能需要使用引号,因为在这个例子中,其他贝壳不需额外或至少通常不需额外,但它不伤害引用).这会推动你所有的分支机构,或至少尝试.这往往过于热情,推动所有临时工作和实验分支,可能不是你想要的,但这是Git在2.0版之前默认做的.
而且,您可以使用空的src:
git push origin :refs/heads/deleteme
Run Code Online (Sandbox Code Playgroud)
这是一种特殊情况的语法,意思是"让我的Git让他们的Git 删除该引用"(删除标签,拼出标签).与一个分离的头,缺少一个完全合格的名字你方指你应该完全限定名称的一面.(再次见脚注4)
如果你添加--force到你的git push命令,你的Git将这个标志传递给他们的Git.而不是一个礼貌的请求 - "拜托,先生,你愿意设置你refs/heads/master的ed4f38babf3d81693a68d06cd0f5872093c009f6吗?" - 你的Git将把它作为一个相当坚持的要求发送.他们的Git仍然可以拒绝任何一种方式,但是默认情况下他们的Git会做它,即使它不合理.
Refspecs允许您更紧密地控制此标志.单个refspec中的强制标志是一个主要的加号+.例如,假设您有两个master和develop分支的新提交,以及一组新的重新提交experiment,其他人都同意您可以强制推送.
你可以这样做:
git push origin develop master; git push -f origin experiment
Run Code Online (Sandbox Code Playgroud)
但是你可以将它们组合成一个大推动:
git push origin develop +experiment master
Run Code Online (Sandbox Code Playgroud)
龙头+上experiment,使这一个命令("更新experiment!"),同时保留其他有礼貌的请求("请,先生,如果你喜欢,更新develop和master").
(这有点深奥push,但实际上是你每天经常使用的东西git fetch,它使用带有+标志的refspec 来创建和更新你的远程跟踪分支.)
1如果"其他repo"在同一台机器上并且您使用的是file://基于本地路径的URL,则情况并非如此,但原理相同且操作方式相同.
2更好的是,首先不要让自己陷入这种境地.有一个名称既是分支名称又是标记名称,这是非常令人困惑的.(由于Git的缩写习惯,有类似的令人困惑的情况要避免:例如,不要使用类似于远程名称的名称来命名分支.Git会很好地处理它们,但你可能不会.:-))
3实际上,这个规则有一个例外,大多数人都不会注意到:当HEAD一个名字是"未出生的分支"时.大多数情况下,这发生在一个新的存储库中,它根本没有提交.显然,如果没有提交,则没有HEAD可以命名的提交ID .当您用于git checkout --orphan创建新的孤立分支时也会发生这种情况.
4如果您使用不合格的名称,他们的Git将查找该名称以使其符合条件.这意味着您可能不知道您尝试更新或删除的名称类型.无论如何,这通常不是一个好主意.
正确的分支(意思不是分离的HEAD)是存储在直接引用的refname中的提交HEAD.
这意味着HEAD是一个符号REF到refname(其又包含实际的提交),或直接向提交(分离HEAD).另请参阅" HEAD:当前提交 ".
HEAD:refs/heads/<branch>是一个refspec,其中<src>:<dst>,<src>通常是你想要推送的分支的名称,但它可以是任意"SHA-1表达式",例如master~4或HEAD,并<dst>告诉远程端的哪个ref用这个推送更新.
如果您具有以下状态:
git checkout abranch
--x--Y--W--Y--Z (HEAD abranch)
|
(origin/abranch)
Run Code Online (Sandbox Code Playgroud)
A git push origin aBranch将推动分支HEAD(此处为Z)或原点,从而产生;
--x--Y--W--Y--Z (FEAD, abranch, origin/abranch)
Run Code Online (Sandbox Code Playgroud)
但是如果你直接签出一个新的abranch提交:
git checkout abranch~2
(HEAD)
|
--x--Y--W--Y--Z (abranch)
|
(origin/abranch)
Run Code Online (Sandbox Code Playgroud)
然后使用第二种语法推送,您将仅将远程跟踪分支更新为该W提交:
git push origin HEAD:refs/heads/abranch
(HEAD)
|
--x--Y--W--Y--Z (abranch)
|
(origin/abranch)
Run Code Online (Sandbox Code Playgroud)
git push origin aBranch尽管HEAD没有引用,但仍然会推动整个分支abranch.
| 归档时间: |
|
| 查看次数: |
8323 次 |
| 最近记录: |