我在教程中看到一个人使用git push origin master
,但远程分支名为o/master
。没有名为origin
的远程,只有o
。这是他犯的错误还是origin
有特殊意义?
This is the tutorial.(如果弹出窗口,请单击红色按钮)。键入级别,转到“远程”选项卡,然后在第二行,单击第4个按钮,显示推送参数。继续进行直到你进行第一次视觉演示。
答案 0 :(得分:4)
这不是问题的答案。如果我使用评论中的链接转到页面,并通过NoScript允许足够的东西让脚本运行等,它似乎从一个中等复杂的git rebase
操作的演示开始,我&# 39; m在高级项目中迅速丢失,而不是从一开始就开始。但是,如果问题被重新定义,我们就会得到......
A"遥控"只是一个名称,如origin
或upstream
或bob
,它作为"远程"进入.gitconfig
或.git/config
文件。部分:
[remote "bob"]
url = git://name.in.some.domain/path/to/bob.git
fetch = +refs/heads/*:refs/remotes/bob/*
远程名称是双引号中的东西。 url
行提供了fetch
和push
操作的网址。 fetch =
行也非常重要;我们几乎马上回来。
当您第一次运行git clone
时,clone
命令会设置一个"远程"部分。默认情况下,它使用的名称为origin
,但您可以选择-o
或--origin
的其他名称。
所有git的引用 - 分支,标记和"远程分支" - 实际上是本地的,因为它们是>本地存储您自己的.git
目录。分支和标签是您可能已经熟悉的东西,"远程分支"看起来也很简单。但是这里有一两个转折点。
当您第一次克隆某个存储库时,源存储库有一堆分支。好吧,它至少有一个分支。例如,某些存储库只有master
分支。 (你甚至可以拥有一个根本没有分支的存储库; git clone
会给出一个警告,但允许它。)
为了讨论,我们假设原始来源中有两个分支,称为master
和develop
。在任何情况下,git都会复制所有远程分支。但它不仅仅是使它们成为普通的本地分支,即使它必须在本地存储它们。它使他们成为远程分支"。
我们也说您没有使用-o
更改任何名称,因此您的克隆有一个名为origin
的遥控器。在这种情况下,git clone
将要做的是命名"远程分支" origin/master
和origin/develop
。
它是如何获得这些名字的?这就是fetch =
行所在的位置。
fetch =
行的内容是" refspec"。 refspec是第二最简单的,只是一对用冒号分隔的引号,例如master:master
或develop:develop
。但是,请问,首先究竟什么是ref-name?
引用名称只是一个人类可读的名称,如master
或origin/master
;但每个都有几种形式。有一个"全名"表格,通常以refs/
开头,"短"形式如master
。简称master
只是撰写全名refs/heads/master
的便捷方式。全名不仅包含名称本身,还包含" name-space"该名称,它真正告诉你它是什么 kind 。 refs/heads/
名称空间是您所有常规分支所在的位置。 refs/tags/
名称空间包含您的所有标记,refs/remotes/
包含所有远程跟踪分支。
这几乎就是它的全部内容: A" local" branch是refs/heads/
中的引用名称,以及" remote" branch是refs/remotes/
中的一个。远程分支的目的,git在本地存储在您自己的存储库中,是为了跟踪"分支在哪里在遥控器上,我最后一次(git)有机会看到遥控器并看到。"
fetch =
行包含refspec 同样,refspec的一个简单形式只是ref:ref
- 一个左侧的refname和一个右侧的refname。 fetch =
行使用此行,但添加了几个星号和一个加号:+refs/heads/*:refs/remotes/origin/*
。
加号有一个相对简单的含义:它是" force"旗。我们会回到这一点。
星号也很明显。我们上面说过,当我们克隆存储库时,原始文件有master
和develop
。这些是本地分支,实际上是refs/heads/master
和refs/heads/develop
。星号匹配它可以的一切,所以左侧refs/heads/*
最终匹配这两个分支。在右侧,星号表示"放入左侧匹配的任何内容"。
换句话说,这匹配refs/heads/master
(左侧)并生成refs/remotes/origin/master
(右侧)。它还匹配refs/heads/develop
并生成refs/remotes/origin/develop
。
在前面,加号表示"强制"或"强制更新"。即使更新不是"快进"这也告诉git更新引用。 (我在这个答案中只是方便地忽略了快进:-))。所有这一切的作用是,每当您运行git fetch
时,make git fetch
始终更新远程跟踪分支。这维护了我们想要的属性:git连接到远程存储库,与该服务器上的gitty对应方交谈,并找到所有分支的位置,所以现在它应该更新我们的远程分支"副本。
(等一下,我们是如何从git clone
转到git fetch
的?好吧,clone
实际上只是第一次获取:它初始化了一个存储库,添加了它的第一个& #34;远程",并进行提取,所有这些都是一回事。所以它遵循与git fetch
相同的规则,在这里。)
当您签出与远程跟踪分支同名的(新的,本地)分支时,git会使您的新本地分支在与远程跟踪分支相同的提交时启动,并设置本地分支以引用远程分支,以便git status
可以打印1 ahead, 3 behind
之类的内容。令人困惑的是,一些git文档喜欢说这个本地分支"跟踪"远程分支,而其他git文档调用"远程分支" a"远程跟踪分支"并注意到这个分支"跟踪"遥控器。 (实际上,每当我们将本地git发送到联系遥控器时,它就会更新。)
首先,重命名的原因有点模糊。但是,一旦你使用git一段时间,它就变得很明显了。让我们假设您克隆该存储库,然后在分支master
或develop
或两者上自行提交一些提交。然后,您执行与远程联系的操作,并更新远程分支。如果git要更改您自己的(本地)master
和/或develop
,那么这将失去您已经完成的工作。所以它只更新远程跟踪分支。
在上面的示例中,我有[remote "bob"]
,然后是fetch = +refs/heads/*:refs/remotes/bob/*
。但是fetch =
行不会拥有在其refspec的右侧使用与远程相同的字符串。如果fetch
行显示为+refs/heads/*:refs/remotes/robert/*
,则远程bob
的所有远程分支最终都会被命名为robert/branch
。
[那个(显然)是原始难题的答案:无论出于何种原因(显然,窗口的宽度),教程作者已设置origin
' s fetch =
包含refs/remotes/o/*
的行。但是,让我们用其他东西来完成这个更大的答案。]
git push
的这些参数是什么?经典示例推送命令为git push origin develop
或git push origin master
。但是,如果你检查the git push
documentation,你会发现这两个参数显示为" repository"和" refspec"。 origin
如何成为存储库,当它是遥控器的名称时,master
如何在没有冒号且因此没有左右两侧时成为refspec?
第一部分的答案是git push
随着时间的推移而演变。在一些古老版本的git中可能不允许使用remote-as-repository参数origin
。相反,您必须编写实际的URL,现在存储在远程定义中的url =
行中。您今天仍然可以这样做,因此文档不能将该参数限制为只是 a" remote"名称。所以在git push origin
中,origin
部分是远程的名称,这是编写完整的URL的简短方法。 (就此而言,您实际上可以在配置文件中列出单独的" pushurl"以便获取到一个URL并推送到另一个URL。)
对于第二部分,好吧,当我说refspec是一对用冒号分隔的ref-names时,我还说这是第二个 - 最简单的形式。最简单的形式只是一个引用名称!以这种方式编写时,git push
将其视为在中间用冒号重复的引用名称。所以在这里,master
只意味着master:master
。 (由于各种原因,git fetch
handles no-colon refspecs differently。)
如果你最终设法"得到"为什么git重命名git fetch
上的引用,这只会引发另一个问题。
master:master
和develop:develop
?使用fetch
,我们会更新远程跟踪分支,origin/master
(或者o/master
),依此类推。为什么不更新"推送跟踪分支"在服务器上?例如,我可以将我的工作推到refs/me/master
。
实际上,我们可以这样做;有些系统可以处理这类事情(某些类型的拉取请求和某些类型的自动化测试系统使用推送到refs/for/...
等)。但git"开箱即用"没有做到。我们只是直接推到遥控器上的原始分支。
这意味着git push
的最后一个参数 - master
中的git push origin master
- 将我们的 master
直接推送到他们的< / em> master
。这种推动需要是一个快速前进的&#34;否则它会被拒绝&#34; (或者我们必须使用强制标记,--force
或 - 您应该从fetch
行 - 加号git push origin +master:master
)识别出来。
[这也导致一些轻微的缺陷 - 最近修复,实际上是git,对于&#34;安全撤回&#34;工作,包括&#34;倒带&#34;以人们可以处理的方式发布分支机构。强制标志是全有或全无,但在某些情况下,能够告诉远程服务器很好:&#34;我认为您的参考<ref>
位于<raw commit ID>
;如果是,请将其更改为<new ID>
。&#34;从本质上讲,这是ref-names的比较和交换:它实现了原子更新的形式,否则是不可能的。但这是另一个话题,这个答案已经花了太长时间才能写出来。 :-)]
答案 1 :(得分:2)
远程名称不必出现在refname中的任何位置。
.git/config
中完全有效的部分可能看起来像
[remote "origin"] url = https://github.com/pcottle/learnGitBranching.git fetch = +refs/heads/*:refs/remotes/o/*
确实在o/master
中将远程分支显示为git log --decorate
等,但仍然使用origin
作为远程名称。
换句话说,您看到的o
不是远程名称。