我的 Gitlab 项目有一个远程分支在终端中处于活动状态。当我运行git checkout branch
时,它会already on branch
回来。
但是,在 Atom 的 Git 选项卡中,分支选项卡仅列出了我当前七个分支中的三个。在命令行中,运行git branch -r
将返回十个分支,其中包括已删除和/或合并的分支。
运行git fetch
回报
From gitlab.com:zeesy/project
* [new branch] branch -> origin/branch
这是怎么回事?我希望能够在 Atom 中编辑我的文件,然后推送到 Git。
跑步git branch -a
回报
* branch
baby-steps-demo
lit-html-demo
master
webapp
working-demo
archaeological-record
remotes/origin/HEAD -> origin/master
remotes/origin/branch
remotes/origin/archaeological-record
remotes/origin/baby-steps-demo
remotes/origin/js
remotes/origin/lit-html-demo
remotes/origin/master
remotes/origin/split-pages
remotes/origin/webapp
remotes/origin/working-demo
请注意,baby-steps-demo
不再存在于 GitLab 项目中。
运行git pull && git checkout branch
结果
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.
git pull <remote> <branch>
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream-to=origin/<branch> branch
这表明没有远程分支。但是,该分支完全可以从Gitlab访问。
TL;博士
您可能只需要运行git checkout branch
(我猜您已经这样做了),然后重新启动Atom(完全关闭它;它倾向于继续运行,以便快速启动并轻松打开窗口)。 我实际上没有使用过 Atom,所以这是一个猜测——它的插件可能假设只有插件执行任何与 Git 相关的操作,因此在您执行命令行操作后它永远不会重新扫描。
不过,对实际发生的事情进行长篇描述可能会有所帮助。
长
我将在这里讨论git fetch
和 Git 的命名系统。
请注意,
baby-steps-demo
不再存在于 GitLab 项目中......
这很正常:默认情况下,git fetch
不会删除远程跟踪名称,只会创建或更新它们。
这里有几个部分。 你有你的Git 存储库,服务器有它的Git 存储库,每个仓库都有自己的分支名称。 但是你的 Git 存储库也需要记住其他Git 存储库的名称。 因此,除了您的(本地)分支名称之外,您的 Git 存储库还有一组远程跟踪名称,这些名称对应于其他 Git 存储库拥有的名称,或者上次您的 Git 与他们的 Git 交谈时拥有的名称。
如果您从命令行运行,它可能有助于您可视化正在发生的事情:
git ls-remote origin
这向您展示了git fetch origin
(或origin
git fetch
的前几个步骤)的作用:
- 无论
git config --get remote.origin.url
说什么,都可以调用另一个 Git。 从他们那里获取他们所有引用的列表(一个涵盖分支和标签的技术术语;还有其他术语,但你的 Git 不会关心任何东西,除了他们的分支和标签名称)和他们相应的哈希 ID 值。
对于我的 Git 存储库,当我运行
git ls-remote origin,
时,前几行是:3e5524907b43337e82a24afbc822078daf7a868f HEAD fc54c1af3ec09bab8b8ea09768c2da4069b7f53e refs/heads/maint 3e5524907b43337e82a24afbc822078daf7a868f refs/heads/master 61856ae69a2ceb241a90e47953e18f218e4d5f2f refs/heads/next
例如。
一旦你的git fetch
有了这些信息,它就会确定它要引入哪些分支(它们的maint
、master
等等——它们的分支),所以它会检查你是否有提交fc54c1a...
、3e55249...
等等。
无论您没有提交什么,您的 Git 都会要求他们的 Git 以及完成您的存储库所需的任何其他对象。 这一切都发生在一个相当快速的"我有X,但我需要Y"交换中,之后他们的Git构建了一个包文件来发送给你:
remote: counting objects ...
remote: compressing objects ...
一旦他们向您发送了所有内容,您的Git 就会将这些对象移走,并通过它们的哈希 ID 在您的数据库中进行索引。 除非你(或你的 Git,真的)在某个时候把它们扔掉,否则现在你有了这些对象,你永远不需要再次检索它们。
最后,你的 Git 必须设置一些或几个名称来记住这些对象,或者更具体地说,它们的哈希 ID。 如果你的 Git 不知道为什么它有这些对象——如果它没有可以找到它们的名字——它最终会把它们扔掉。 它存储哈希 ID 的一个位置是特殊的FETCH_HEAD
文件。 每个新的获取都会用它提取的任何内容覆盖该文件,因此您获得的内容至少会保留到下一个git fetch
。 但对于你的目的来说,更重要的一个 - 因为它持续的时间更长 - 是你的 Git重命名他们的分支名称:
refs/heads/master
变得refs/remotes/origin/master
refs/heads/next
变得refs/remotes/origin/next
然后,您的 Git 会创建或更新此集右侧的名称。 这些是您的远程跟踪名称。
不过,出于显示目的,Git会缩短这些内容,至少删除refs/
,通常还会删除下一个斜杠分隔的单词。git fetch
命令以缩写哈希 ID 作为所有这些前缀:
aaaaaaa..bbbbbbb master -> origin/master
它告诉您您的 Git 根据他们的refs/heads/master
更新了您的refs/remotes/origin/master
,同时,您的refs/remotes/origin/master
曾经命名提交aaaaaaa
,现在命名提交bbbbbbb
。 或:
* [new branch] branch -> origin/branch
它告诉你,你的 Git 刚刚根据在git ls-remote
列表中看到refs/heads/branch
创建了你的refs/remotes/origin/branch
。
请注意,您的origin/baby-steps-demo
- 全名实际上是refs/remotes/origin/baby-steps-demo
;它只是为了显示而缩短 - 是您的远程跟踪名称,而不是分支名称。1分支名称是完整版本以refs/heads/
开头的名称。
现在我们可以回到这句话:
请注意,
baby-steps-demo
不再存在于 GitLab 项目中......
这意味着当您的 Git 调用他们的 Git 时,他们不会列出refs/heads/baby-steps-demo
。
您的 Git 使用他们的baby-steps-demo
来创建您的origin/baby-steps-demo
。 你的 Git 现在应该删除你的origin/baby-steps-demo
吗? 如果您希望 Git,可以告诉您的 Git 使用其所有分支的完整列表来修剪您的远程跟踪名称。 您可以使用git fetch --prune
执行此操作,或者在 Git 配置中将fetch.prune
设置为true
,以使git fetch
默认执行此操作。
命令行命令git branch -r
专门显示这些远程跟踪名称。
命令行命令git branch
(不带-r
)专门显示分支名称。 这些不依赖于远程跟踪名称的存在(反之亦然)。
每个(本地)分支可以有一个上游,但只能有一个。基于远程跟踪名称(如origin/master
)创建的分支(如master
)的上游通常会将远程跟踪名称设置为其上游,但你可能必须告诉 Git 进行设置,具体取决于您创建(本地)分支名称的确切方式。
某些操作(包括git pull
)使用上游设置来确定要git fetch
的内容,以及git fetch
完成后要git merge
的内容。 如果您的分支没有上游集,则它们不能或不会假定某些默认值。
在您的情况下,您当前的分支branch
没有将origin/branch
设置为其上游(因为它根本没有设置上游)。 如果运行:
git branch --set-upstream-to=origin/branch branch
您将告诉您的 Git 将origin/branch
设置为名为branch
的分支的上游。 如果在此之前它有其他上游设置,则会用这个新设置替换旧的上游设置。
上游设置实际上只是一对名称;git branch --set-upstream-to
确保名称存在且有效,然后设置它们,git branch --unset-upstream
完全删除它们(这样分支就不再有上游了,如果你出于任何原因想这样做的话)。
1这组短语显然还有很多不足之处。 如果分支是您可以使用git checkout
获得"onto"的东西,那么远程跟踪名称或远程跟踪分支名称不是分支,因为git checkout origin/master
或类似名称使您处于分离的HEAD模式。 此外,远程跟踪(分支)名称实际上是您自己的 Git 存储在本地的东西! 但有些人喜欢将远程跟踪名称视为分支名称,并且它们确实具有"分支"行为。