我成功运行了2个命令。所以它让我认为上游分支不一定是远程分支。那么本地上游分支有什么用呢?
$ git branch local_branch5 --set-upstream origin/branch5
Branch local_branch5 set up to track remote branch branch5 from origin.
$ git branch local_branch6 --set-upstream local_branch3
Branch local_branch6 set up to track local branch local_branch3.
我的分支看起来像这样:
$ git branch -vv
local_branch3 a758e52 Initial commit
* local_branch4 db11990 Update README.md
local_branch5 ce0762c [origin/branch5] change on local_branch2
local_branch6 a758e52 [local_branch3] Initial commit
master 064aa08 [origin/master: ahead 1] change on local master
正如我测试的那样,似乎所谓的upstream
只是在2个分支/命名提交之间创建关系。这些分支可以是本地分支,也可以是本地远程分支。只需要注意,当推送到本地上游时,repo需要是.
。
答案 0 :(得分:2)
您是对的,本地分支机构可以将其他本地分支作为其上游设置。我改写了你的" ADD 1 "部分说它是设置的远程部分,必须是.
,上游才是另一个普通的,即本地分支。
有关相关问题和各种答案,请参阅how do I get git to show me which branches are tracking what?。
您可以忽略以下所有内容。它不是答案的真正部分,它只是解释了我们如何到达这里,以及为什么有些怪癖他们是这样的。
还值得注意的是,仅本地分支具有上游,并且该上游设置以非常低的级别配置为两部分。但是,这两个中的一个使用第三部分,即使在正常设置中,这第三部分几乎是不可见的。其原因具有历史意义,可追溯到2007年之前使用的Git版本。
如果您查看每个存储库配置 - 文件.git/config
或git config --list --local
的输出 - 您将看到如下文字:
$ git config --list --local
[snip]
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
[snip]
branch.master.remote=origin
branch.master.merge=refs/heads/master
这意味着(本地)分支master
具有origin/master
作为其上游。这两部分是branch.master.remote
,告诉Git使用远程,以及branch.master.merge
,它似乎再次引用您自己的本地主服务器。那是什么?
答案在于,Git的远程跟踪分支本身并非早期史前存在,因为它是Git。回到过去的糟糕时光,你的 Git不记得你其他一些Git存储库的状态。
当你连接到其他(上游)Git并从中提取提交时,你实际上会从他们的 master
分支获取提交。事实上,这仍然是今天发生的事情。您的Git会将此信息放入文件.git/FETCH_HEAD
中,并说:&#34;当我查看<url>
时,我找到了一个名为master
的分支,其中包含b06d364...
& #34 ;.你的Git今天仍然这样做。但是你的Git只会停止: FETCH_HEAD
这些东西就是你所拥有的。
所以,此时你有两个 master
- s:你的,以及他们的。两者都名为master
。在您的FETCH_HEAD
内容被任何其他不同的上游结果覆盖之前,您的Git必须立即重新提交或合并您的提交。这意味着你的Git需要知道,当你想要重新绑定或与你的上游合并时,它应该获得他们的master
,然后使用master
中的信息重新绑定或合并你的.git/FETCH_HEAD
名称为master
。
因此,branch.master.*
设置分为两部分:remote = origin
- 这曾经只是一个原始网址 - 然后是merge = master
。当时的假设是,现在仍然是,行动应该是合并,即使rebase可以说是更好的默认。 pull
脚本将从URL获取,然后使用.git/FETCH_HEAD
的内容获取合并的提交哈希:
$ head -3 .git/FETCH_HEAD | sed 's,git://.*,<url>,'
b06d3643105c8758ed019125a4399cb7efdcce2c branch 'master' of <url>
95d67879735cfecfdd85f89e59d993c5b4de8835 not-for-merge branch 'maint' of <url>
4ebf3021692df4cb51da8d806fbb8b909ee7e111 not-for-merge branch 'next' of <url>
请注意其中一些 - 实际上除了一个之外 - 其中包含字符串not-for-merge
。这是对原始git pull
脚本的提示:只有master
行才能用于合并。
早期的Git用户很快就会明白,使用比完整网址更短的名称是很好的,特别是如果你有几个不同的其他Git存储库,你经常会从中获得好的工作。您可以只说protocol://some.university.ac.uk/long/path/to/brians/repo
。
brian
这种情况的确切机制显然是一种竞赛,或者是以不同的方式多次独立发明的。我自己并没有参与这段历史,但是traces linger even today in the git fetch
documentation, under the section named remotes:
可以使用以下某个名称而不是URL作为
<repository>
参数:
Git配置文件中的遥控器:
$GIT_DIR/config
,
$GIT_DIR/remotes
目录中的文件或
$GIT_DIR/branches
目录中的文件。
第一个选项&#34;赢了&#34;是人们今天真正使用的东西。 (其他两个仍然受到支持。我不知道为什么 - 他们似乎已经被弃用,然后在不久前被弃用。)
因为第一个选项赢了,我们可以转到the configured remote-tracking branches section of this same documentation:
您经常通过定期重复从中获取相同的远程存储库。为了跟踪这种远程存储库的进度,git fetch允许您配置
remote.<repository>.fetch
配置变量。通常这样的变量可能如下所示:
[remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/*
这(以及本节的其余部分)定义远程跟踪分支名称的工作方式。这个想法的核心是,嘿,那里还有另一个Git:我们运行git fetch brian
来获得Brian的东西。我们不能记得:这是Brian的Git说他有的东西,我们最后一次打电话给他的Git ?
当然,我们可以:我们会通过将Brian的master
更改为brian/master
来实现这一目标。我们存储在我们自己的Git中的映射,从Brian的分支名称到我们的远程跟踪名称,来自此fetch = ...
行,我们控制。每个fetch
行 - 可以有多个 - 具有+src:dst
形式,其中前导加号 - 与--force
相同,或多或少 - 是可选的但几乎总是现在,结肠的左侧和右侧给出了他们的名字&#34;和#34;我们的名字&#34;对于我们打算复制的每个参考文献。
对于远程 R , src
部分只是refs/heads/*
和的情况几乎总是如此dst
部分以refs/remotes/
开头,然后列出远程名称 R 本身。因此,当我们有一个名为brian
的遥控器时,fetch
设置为+refs/heads/*:refs/remotes/brian/*
。
两个星号相匹配:Brian有(refs/heads/*
)强制复制(+
)到我们自己的存储库的任何分支,但重命名为我们的< em>远程跟踪分支名称空间(refs/remotes/)
。我们添加了另一个字词,以确保 Brian 分支机构位于我们的refs/remotes/brian/
下,并且在我们的refs/remotes/nadia/
下与 Nadia的分支发生冲突。然后我们只是复制Brian(或者Nadia&#39; s,或者来源&#39) ; s)分支名称,它成为此分支的远程跟踪分支名称。
大多数本地分支都有远程跟踪分支作为其上游设置。 (正如这个问题所指出的那样,实际上不需要,这只是通常情况。)但是,当本地分支 B
&#34; track&#34; -ie,作为其上游远程跟踪分支refs/remotes/origin/B
,配置条目只是说branch.B.remote
是origin
和branch.B.merge
是 B
。那里根本没有明确的refs/remotes/origin/B
!
这都是因为上面曲折的历史(扭曲?)。在根本没有任何远程跟踪分支之前,Git的配置列出了在远程上找到的分支的名称。分支 B
&#34;与&#34;合并分支 origin
的B
版本。由于 在2005年左右拼写,因此Git要求今天仍拼写。然后Git接受旧的拼写并将其映射到fetch =
行以找出正确的远程跟踪分支。
例如,假设您有上游test
的分支origin/master
。也就是说,git config --list --local
将包括:
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
(通常和正常的模式)和:
branch.test.remote=origin
branch.test.merge=refs/heads/master
考虑到所有Git都将远程名称origin
与master
的{{1}}部分串在一起,得到branch.test.merge=refs/heads/master
,可以原谅。但实际上,事情并非如此。让我们制作另一个遥控器,然后更改其origin/master
行:
fetch
现在我们将运行git remote add weird <url>
git config remote.weird.fetch '+refs/heads/*:refs/remotes/twisty/*'
:
git fetch weird
请注意,他们没有转到$ git fetch weird
From <url>
* [new branch] maint -> twisty/maint
* [new branch] master -> twisty/master
* [new branch] next -> twisty/next
* [new branch] pu -> twisty/pu
* [new branch] todo -> twisty/todo
,而是转到weird/*
。我们现在可以创建一个跟踪(作为其上游)twisty/*
:
twisty/master
遥控器为$ git checkout -b test --track twisty/master
Branch test set up to track remote branch master from weird.
Switched to a new branch 'test'
$ git rev-parse --symbolic-full-name test@{upstream}
refs/remotes/twisty/master
$ git config --list --local
[snip]
branch.test.remote=weird
branch.test.merge=refs/heads/master
,而weird
从未提及merge
,但上游确实 twisty
。
由于我真的不想要测试分支和奇怪的扭曲设置,让我们清理它们:
twisty/master
我们需要在此完成所有操作:$ git checkout master
...
$ git branch -D test
Deleted branch test (was 8b2efe2a0).
$ git remote remove weird
删除所有git remote remove weird
远程跟踪分支,因为它也遵循twisty/*
配置行。