命令1做什么命令2没有?
@foreach(var item in Model)
" HEAD:refs / heads /"?
的含义是什么?答案 0 :(得分:15)
VonC's answer是正确的(并且被赞成),但我认为另一种看待这种情况的方式可能更有意义。
请注意,所有这一切都假设您使用git push
的四字形式,即git push remote refspec
。这里的 remote
部分通常只是名称origin
。我们稍后会更好地定义 refspec
。
git push
做什么 git push
需要做什么(因此确实如此)是在另一台机器上调用另一个Git实例, 1 然后给那个其他Git一组引用(通常是分支名称,有时是标记名称)要更新。 引用只是一个名称,例如master
或v1.2
,理想情况下应该是完全限定的(refs/heads/master
或{{ 1}})这样我们就可以确定 kind 的引用是什么 - 分支,标记或其他。
为了让其他Git更新Git移交的引用,你的Git必须也移交一些丑陋的SHA-1哈希:每个引用一个。换句话说,你的Git会要求他们的Git将他们的 refs/tags/v1.2
设置为refs/heads/master
。 (此时 - 实际上,在这一点之前,真的 - 你的Git和他们的Git谈论了你想要发送它们的对象,以及它们已经拥有的对象,所有这些都是由这些丑陋的哈希ID完成的。两个Gits同意将要发送的内容,您的ed4f38babf3d81693a68d06cd0f5872093c009f6
和counting objects
然后向他们发送对象。现在,请设置一些名称&#34 ;部分几乎发生在最后。)
请注意,Git的请求有两个部分:(1)完全限定的引用,以及(2)big-ugly-hash。 (事实上,还有第三部分,compressing objects
标志,但这部分很简单,我们可以忽略它。)但是你的 Git在哪里得到这些?
如果你写:
--force
您已经发送 Git两条信息:名称git push origin somename
,您的Git用来查找网址,名称origin
。你的Git使用它来计算全名。 somename
是一个标签吗?如果是,则完整名称为somename
。 refs/tags/somename
是一个分支吗?如果是,则完整名称为somename
。无论哪种方式都有效。当然,您也可以自己写出全名 - 如果名称是分支和标记,您可能想要这样做,而不是让Git为你挑一个。 2
那么,你的Git在哪里获得了大丑陋的哈希?答案是:来自同一个名字。名称refs/heads/somename
,无论是分支还是标记,只是命名某个特定的Git对象。如果你想自己看哈希,你可以随时做到:
somename
会告诉你。事实上,这是我如何得到git rev-parse somename
:我去了Git的Git存储库并做了ed4f38babf3d81693a68d06cd0f5872093c009f6
并打印出了这个哈希,因为git rev-parse v2.1.1
是任何完整的有效标记自2.1.1版本发布以来Git存储库的副本。
请注意,当您执行时使用此表单 - 此v2.1.1
表单 - Git会在您的<中查找 git push remote name
参数/ em>存储库用于两个目的:找出它的全名,并获取它的哈希值。 name
所在的位置,只有该全名所指的内容并不重要。
HEAD
的第四个参数称为 refspec ,其语法实际上允许用冒号分隔两个部分:
git push
在这种情况下, git push origin src:dst
部分提供名称,但dst
部分提供哈希。 Git运行src
部分到src
并生成哈希。所以你可以:
git rev-parse
使用您的分支git push origin mybranch:refs/tags/v42
标识的任何提交哈希在其他Git存储库中创建标记v42
。
mybranch
包含分支名称在Git中,HEAD
总是命名当前提交。 通常它通过命名分支,并让分支命名提交来实现。因此,通常HEAD
包含一个分支名称,如HEAD
,分支名称始终会为您提供该分支的提示(这就是Git 的方式定义&#34; tip commit&#34 ;;参见the Git glossary中分支的定义。但是总是, 3 master
可以变成提交:
HEAD
因为$ git rev-parse HEAD
2b9288cc90175557766ef33e350e0514470b6ad4
是分支名称(然后是提示提交),或者你有一个&#34;分离的HEAD&#34;,在这种情况下,Git直接将当前提交ID存储在{ {1}}。
请记住,为了推送,Git需要获取这两个信息:哈希和(完整)名称。当HEAD
不是&#34; &#34;分离&#34;时,Git可以从中获取两者:HEAD
有一个分支名称 - 以全名形式,实际上 - 分支名称具有哈希值。但当你在&#34;分离的HEAD&#34;模式,HEAD
只有一个哈希。 Git 无法在HEAD
中找到分支名称。可能没有是一个:您可能已经通过ID签出了提交,或者您可能已按标签名称签出,如:
HEAD
让你进入这个&#34;分离的HEAD&#34;模式。
在这种情况下,Git要求您提供源哈希HEAD
- 您仍然可以使用名称$ git checkout v2.1.1
来获取它 - 和 {{1}目的地名称。而且,如果您使用src
作为来源,Git确实需要你来拼出完整的目的地,因为Git现在无法告诉它是否应该是分支(HEAD
)或标记(dst
)。 4
HEAD
您可以使用较少的参数运行refs/heads/dst
,例如:
refs/tags/dst
甚至只是:
git push
这里发生的是,如果没有 git push
,Git会首先咨询您的git push origin
设置。通常这是git push
(自Git 2.0版以来的默认值)。在这种情况下,Git只是使用refspec
来确定要推送的内容 - 当然,只有当push.default
没有分离时才能工作。这正是我们上面所描述的。
(其他三个设置也使用simple
。其中一个 - 在Git 2.0版之前默认的那个 - 没有,但是这个特定的设置证明太容易出错,这就是为什么默认你可能不应该使用它,至少除非你是Git大师,否则你不应该使用它。)
(并且,如果你忽略了 HEAD
,Git会再次使用HEAD
来确定推送到哪里,如果需要,默认为{{1} }。)
您还可以推送多个refspec:
HEAD
在这种情况下,每个refspec都以通常的方式处理:如果需要,获取其完全限定名称,这样你的Git每次都可以给他们的Git一个完全限定的名字;如果您没有使用remote
表单(或者如果 使用HEAD
表单,请查找其哈希ID,查找origin
& #39;而不是ID。
您可以在refspecs中使用通配符:
git push origin branch1 branch2 tag1 HEAD:refs/tags/tag2
(有些贝壳会吃掉,fold, spindle, or mutilate src:dst
,所以你可能需要使用引号,如本例所示;其他贝壳赢了 - 或者至少通常赢了# 39;但是引用它并没有什么坏处。这将推动所有您的分支,或者至少尝试。这往往过于热情,推动所有临时工作和实验分支,可能不是你想要的,但它是Git在2.0版之前默认做的。
而且,您可以使用空的src:dst
:
src
这是一种特殊情况的语法,意思是&#34;让我的Git让他们的Git 删除该引用&#34; (删除标签,拼出标签)。与分离的HEAD一样, 侧缺少完全限定名称意味着您应该完全限定他们的方面的名称。 (再次见脚注4)。
如果在git push origin 'refs/heads/*:refs/heads/*'
命令中添加*
,Git会将此标记传递给他们的Git。先生,请你将src
设置为git push origin :refs/heads/deleteme
吗?&#34; - 你的Git会将其作为一个相当坚持的要求发送给你,而不是一个礼貌的请求 - &#34;他们的Git仍然可以拒绝任何一种方式,但默认情况下,即使它不合理,他们的Git也会这样做。
Refspecs允许您更紧密地控制此标志。单个refspec中的强制标志是前导加号--force
。例如,假设您有git push
和refs/heads/master
分支的新提交,以及ed4f38babf3d81693a68d06cd0f5872093c009f6
的一组新的重新提交的提交,其他人都已同意你被允许强行推进。
你可以这样做:
+
但你可以将它们全部组合成一个大推力:
master
develop
上的前导experiment
使 一个命令(&#34;更新git push origin develop master; git push -f origin experiment
!&#34;),同时将其他命令保留为礼貌请求(&#34;请先生,如果您愿意,请更新git push origin develop +experiment master
和+
&#34;)。
(这对于experiment
来说有点深奥,但实际上你每天都经常使用experiment
,它使用带有develop
标志的refspec来创建和更新你的远程 - 跟踪分支。)
1 如果&#34;其他回购&#34;在您的同一台计算机上,您使用基于master
或本地路径的网址,这不是真的,但原则是相同的,操作也是一样的。
2 更好的是,首先不要让自己处于这种状况。让一个名称既是分支名称又是一个标记名称,这是非常令人困惑的。 (由于Git的缩写习惯,有类似的令人困惑的情况要避免:例如,不要使用类似于远程名称的名称来命名分支.Git会很好地处理它们,但你可能没有。:-))
3 实际上,这条规则有一个例外,大多数人都不会注意到:当push
命名一个&#34;未出生的分支时,#34;。大多数情况下,这发生在一个新的存储库中,它根本没有提交。显然,如果没有提交,则没有git fetch
可以命名的提交ID。当您使用+
创建新的孤儿分支时也会发生这种情况。
4 如果您使用不合格的名称,他们的Git会查找名称以使其符合资格。这意味着您可能不知道您尝试更新或删除的名称类型。无论如何,这通常不是一个好主意。
答案 1 :(得分:7)
正确的分支(意思不是detached HEAD)是存储在由HEAD
直接引用的引用名称中的提交。
这意味着HEAD
is a symbolic ref到refname
(其中包含实际提交),或直接提交(detached HEAD)。另请参阅“HEAD: current commit”。
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)
git push origin aBranch
将推动分支HEAD(此处为Z)或原点,从而产生;
--x--Y--W--Y--Z (FEAD, abranch, origin/abranch)
但是如果你直接签出一个新的abranch提交:
git checkout abranch~2
(HEAD)
|
--x--Y--W--Y--Z (abranch)
|
(origin/abranch)
然后使用第二种语法推送,您将仅将远程跟踪分支更新为W
提交:
git push origin HEAD:refs/heads/abranch
(HEAD)
|
--x--Y--W--Y--Z (abranch)
|
(origin/abranch)
尽管HEAD没有引用git push origin aBranch
, abranch
仍会推动完整的分支。
答案 2 :(得分:1)
第一个命令显式推送具有给定名称的分支。例如,如果你有一个与你的某个分支名称相同的标记,那么第二个命令就不明确了。