TL;DR:只需使用git branch -r 或git branch -a(在git fetch 更新后)。完全不清楚为什么您会看到没有这些标志的远程跟踪分支(也许您一直在使用自动显示它们的 GUI?)。
但是,您的问题中至少存在一个小误解——这不足为奇; Git 的这个特殊部分一开始很棘手。
实际上,这个问题涉及三组组分支名称。
git remote show origin 显示所有分支。
不完全是。让我们稍微备份一下,定义分支的两个集合(或类,或任何你喜欢将它们分组的词)。 Git 提供:
-
您的常规、普通的本地分支机构。这些是git branch 在不带参数和标志的情况下显示的内容。
$ git branch
diff-merge-base
* master
precious
stash-exp
“分支”一词通常表示以下之一:名称,当提供给 git rev-parse 时,解析为提交 ID:
$ git rev-parse diff-merge-base
2d0cc5001c1a88995727521d4ef77f7a4acc4e14
全名以refs/heads/开头的:
$ git rev-parse --symbolic-full-name diff-merge-base
refs/heads/diff-merge-base
-
您的远程跟踪分支。这些是git branch -r 显示的内容:
$ git branch -r
origin/HEAD -> origin/master
origin/maint
origin/master
origin/next
origin/pu
origin/todo
它们之间的主要区别在于,您的本地分支是您可以随意操作的名称,而您的远程跟踪分支是 Git 自动从属于其他东西的名称。 可能你自己来操作它们,但这并不有利可图,因为它们的目的是记住一些 other Git 的分支名称(以及相应的SHA-1 值)。
请注意,将远程跟踪分支名称提供给 git rev-parse 也 可以,并且您也可以获得它的 symbolic-full-name:这只是以 refs/remotes/ 开头,后跟远程,然后是 本地 名称 如果您是运行在 on 远程 的 Git。因此:
$ git rev-parse --symbolic-full-name origin/master
refs/remotes/origin/master
表示我的 Git 的 origin/master 是我的 Git 的 内存,master 的意思是,在 origin 上,我的 Git 上次调用 origin 并获取 — 即更新——来自他们。
git remote(有时)实际上调用了远程 Git
请记住,每当您获取或推送提交时,都会涉及 两个(有时甚至更多)Git 版本控制数据库。所以你可以查看你的信息,或者你可以让你的Git通过互联网电话调用他们的Git,然后查询他们关于他们的信息。他们也可能拥有自己的本地分支机构,甚至远程跟踪分支机构。 (通常,对于这种情况,他们只有本地分支机构。)
出于说明目的,让我删除我自己的一个远程跟踪分支(这非常无害,因为我稍后会运行git fetch 来恢复它):
$ git branch -r -d origin/pu
Deleted remote-tracking branch origin/pu (was 7c79844).
现在,如果我运行 git branch -r,我将不再拥有 origin/pu:我的 Git 不再有它作为远程跟踪分支。但是他们的 Git,在origin 上,仍然有一个名为pu 的本地 分支,所以:
$ git remote show origin
* remote origin
Fetch URL: git://git.kernel.org/pub/scm/git/git.git
Push URL: git://git.kernel.org/pub/scm/git/git.git
HEAD branch: master
Remote branches:
maint tracked
master tracked
next tracked
pu new (next fetch will store in remotes/origin)
todo tracked
Local branches configured for 'git pull':
master merges with remote master
stash-exp merges with remote master
Local ref configured for 'git push':
master pushes to master (local out of date)
当我运行 git remote show origin 时,我的 Git 会调用他们的 Git(这恰好是 Git 的 Git 存储库的副本——github.com 上还有一个可能更合适的版本)并从他们那里得到一个他们所有分支的列表。我已经将它们中的大部分作为我自己的“远程跟踪分支”,但我删除了pu,所以它显示为“新”。
类似的命令git ls-remote 也调用另一个 Git 并对其进行查询,但会显示更多内容:它会显示每个分支的提交哈希(以及每个标签的对象哈希)。有很多标签,所以让我把它限制在一个分支上:
$ git ls-remote origin master
e05806da9ec4aff8adfed142ab2a2b3b02e33c8c refs/heads/master
在这两种情况下,您的 Git(或我的 Git)都会调用他们的 Git 并从他们那里获取信息,但它只是显示它,而不是保存它。要保存信息,我们必须运行git fetch。我已经有一段时间没有运行它了,所以:
$ git fetch origin
remote: Counting objects: 2064, done.
remote: Compressing objects: 100% (1294/1294), done.
remote: Total 2064 (delta 1383), reused 1118 (delta 767)
Receiving objects: 100% (2064/2064), 2.12 MiB | 2.29 MiB/s, done.
Resolving deltas: 100% (1383/1383), done.
From git://git.kernel.org/pub/scm/git/git
de2efeb..e05806d master -> origin/master
3074f94..c69c2f5 next -> origin/next
* [new branch] pu -> origin/pu
1a46792..2135c1c todo -> origin/todo
这个git fetch 和git remote show 和git ls-remote 做了同样的事情,但还做了更多的事情:它收集了我需要完成的对象 我的存储库,然后更新 my 远程跟踪分支名称以对应于 他们的 存储库中的分支名称。
这就是我重新获得origin/pu 的原因:他们还有一个pu,而我丢弃了我的,所以我得到了他们的,现在又拥有了。
这也是我更新除maint 之外的所有其他内容的原因:它们已经更新了足够长的时间。我的origin/master 以前指的是提交de2efeb,但现在它指的是e05806d,这与我们上面运行git ls-remote 时看到的ID 相同。 (这意味着他们在我输入所有这些内容的几分钟内没有更新他们的master。想象一下,十亿 纳秒已经过去了没有更新!:-))
(请注意,git remote show -n origin 跳过origin 的电话,只是向您显示您的 Git 记录的内容。其他几个 git remote 命令也可以在本地工作;请参阅文档细节。)
总结
回顾一下,这里涉及到三组组分支名称:
- 您当地的分支机构;
- 您的远程跟踪分支;和
- 他们的分支(在远程 Git 中)。
最后一组分支名称大部分时间都无关紧要。大多数时候,您在自己的存储库中工作。只涉及一个 Git,它是你的。 他们的Git,它有自己的分支,完全不在画面中。
但有时——啊,这样的时候!——有时,你必须将你的 Git 连接到 另一个 Git。 现在他们的名字很重要!这里真正棘手的是你的名字没有与他们的名字相匹配。 您的 master 必须 与他们的master 相对应没有硬性原因,但 您的 Git 会复制 他们的 em> master 到 your origin/master,所以如果你的名字和他们的名字 do 匹配,它会节省很多脑细胞。你可以解决这个问题(以多种不同的方式),但在你遇到真正需要它的情况之前不要这样做(多个遥控器使用冲突的分支名称——这几乎不会发生) .
git checkout blah 呢?
您在上面提到:
如果我在 [我在git branch 输出中看不到的他们的分支名称] 之一上执行git checkout,它会在本地拉下分支并切换到它。
假设您运行了git branch -r(而不是git remote show origin)并看到了一个名为origin/zorg 的分支。假设您还没有名为zorg 的(本地)分支。你跑:
$ git checkout zorg
你的 Git 说:
Branch zorg set up to track remote branch zorg from origin.
Switched to a new branch 'zorg'
你的 Git 没有“拉下”任何东西。它所做的是创建一个新的本地分支名称zorg,指向与origin/zorg 相同的commit——同样又大又丑的SHA-1 哈希ID。该提交已经在您的存储库中,随时可以签出,实际上您可以这样做:
$ git checkout origin/zorg
看看它——但这会给你一个 Git 所说的“分离的 HEAD”。
这里发生的事情是,在 Git 中,一个分支 name 只是一个指向 一个特定提交的可移动指针。 git checkout 命令,当以这种方式使用时,会做两件事:检查一个特定的提交(进入工作树),和,切换你的 Git 的概念“当前分支名称”。当您 git checkout 一个现有的、本地的、普通的分支名称时,Git 会检查出有问题的一个提交,并将您置于“分支上”,正如 git status 所说:
$ git status
On branch master
当你 git checkout 任何提交的东西不是一个简单的分支名称时,Git 仍然检查一个提交,但 让你离开任何分支,即, 给你一个“分离的 HEAD”。
从上面我们知道origin/master是(现在)提交e05806da9ec4aff8adfed142ab2a2b3b02e33c8c,所以:
$ git checkout origin/master
或:
$ git checkout e05806da9ec4aff8adfed142ab2a2b3b02e33c8c
两者都做同样的事情。由于origin/master 不是 本地 分支,我最终得到:
$ git status
HEAD detached at e05806d
(或有时HEAD detached at origin/master)。
因此,git checkout 所做的就是尝试将您给它的名称转换为分支名称。 如果失败,git checkout 有这个额外的内置功能:它搜索你所有的远程跟踪分支,看看是否有一个“大部分匹配”姓名。所以git checkout zorg 会检查一个名为zorg 的本地分支,但没有找到它,然后搜索所有远程跟踪分支以寻找一个也 匹配zorg 的分支。事实上确实有一个——origin/zorg——所以这会触发特殊情况代码。
特例代码简单地实现了“创建新的本地分支设置以跟踪相应的远程跟踪分支”。也就是说,创建一个本地zorg,并将其upstream(Git 现在这样称呼)设置为origin/zorg。
请注意,要使其正常工作,必须有恰好一个合适的远程跟踪分支。如果我根本没有origin/zorg,这将失败——如果我同时拥有origin/zorg 和thirdrepo/zorg,其中thirdrepo 是另一个远程,如origin,但指向某个第三个Git 存储库,它会也失败了,因为 Git 不知道我的本地 zorg 是否应该将 origin/zorg 或 thirdrepo/zorg 作为其上游。
大多数时候,您只有一个遥控器,名为origin。因此,只要您将所有 origin 的分支保存为您自己的 Git 的远程跟踪分支内存,您就可以通过 git checkout 这些名称让您的 Git 来创建它们。但有时你会发现你必须先运行git fetch,才能更新你的远程跟踪分支。