为什么远程分支显示为已跟踪,即使它们未在本地进行跟踪?

时间:2021-02-23 07:53:12

标签: git

我最近从这个远程存储库克隆。 https://github.com/dave-githubber/my-first-github-repository

就在我克隆它之后,我做到了:

(base) hakan@hakan-VirtualBox:~/CompleteGitGuide/temp/my-first-github-repository$ git show-ref
1fd2ddb6f29becd8d3f3148271e230490d424f85 refs/heads/main
1fd2ddb6f29becd8d3f3148271e230490d424f85 refs/remotes/origin/HEAD
a45b41988603994aac1292ff086ba913567276e2 refs/remotes/origin/feature-1
1a6fd0202b24acb790e52a9a4dba4a26cc94a39a refs/remotes/origin/feature-2
1fd2ddb6f29becd8d3f3148271e230490d424f85 refs/remotes/origin/main
1fd2ddb6f29becd8d3f3148271e230490d424f85 refs/remotes/origin/temp

注意只有一个跟踪主分支:

(base) hakan@hakan-VirtualBox:~/CompleteGitGuide/temp/my-first-github-repository$ git branch -vv
* main 1fd2ddb [origin/main] Create hello-github.txt

但是,当我执行 git remote show origin 时,它说 feature-1、feature-2 和 temp 分支也被跟踪:

(base) hakan@hakan-VirtualBox:~/CompleteGitGuide/temp/my-first-github-repository$ git remote show origin
* remote origin
  Fetch URL: https://github.com/dave-githubber/my-first-github-repository.git
  Push  URL: https://github.com/dave-githubber/my-first-github-repository.git
  HEAD branch: main
  Remote branches:
    feature-1 tracked     <<< why?
    feature-2 tracked     <<< why?
    main      tracked
    temp      tracked     <<< why?
  Local branch configured for 'git pull':
    main merges with remote main
  Local ref configured for 'git push':
    main pushes to main (up to date)

您能解释一下为什么 feature-1feature-2temp 分支显示为在本地跟踪吗?

1 个答案:

答案 0 :(得分:1)

TL;DR

这只是意味着您的 Git 已经并且正在更新 origin/feature-1origin/feature-2origin/temp

(这也是 Git 如何严重重载各种术语的另一个例子,例如“远程”、“跟踪”和“分支”。将 未跟踪文件跟踪分支进行比较< /em> 和 git branch --set-upstream-to 选项。在糟糕的过去,我们不会说 masterorigin/master 作为其上游,而是说 master “跟踪” origin/master。同时,origin/master 是远程跟踪名称,或远程跟踪分支名称...与跟踪文件和未跟踪文件无关。)

git remote 命令是一个奇怪的命令。要了解原因,让我们先看看其他一些命令。

大多数 Git 命令纯粹在本地运行。最大的两个例外是 git fetch,它从某个 other Git 存储库获取(部分或全部)提交,以及 git push,它发送(部分或全部)提交其他一些 Git 存储库。第三个例外 git ls-remote 包括运行 git fetch 的第一部分——调用另一个 Git 存储库——然后只打印出 git fetch 将从 获得的信息< /em> 那个存储库,例如显示他们的分支和标签名称。

git pull 命令只是先运行 git fetch,然后使用第二个在本地运行的 Git 命令——通常是 git merge,但你可以将其配置为使用 git rebase—— 合并 git fetch 刚刚获取的提交。因此,虽然 pull 确实会联系其他一些 Git,但这样做只是因为它以 fetch 开头。

这三个肯定会联系其他 Git 的命令通常使用 remote 来实现,这是一个像 origin 这样的短名称。这个短名称用作键值对中键的一部分,以便您的 Git 可以获取正确的 URL 以调用其他 Git。

很容易将所有其他 Git 命令视为仅在本地运行。但是对于 git remote 命令,这只是对了一半:

  • git remote addgit remote removegit remote set-url 都是纯本地操作。请注意,这些添加或删除了远程(如 origin),或 - set-url - 更改存储的 URL。

  • git remote update 主要是拼写 git fetch 的有趣方式; git remote prune 是一种拼写 git fetch --prune 的有趣方式;并且 git remote set-head 可以(但并不总是)调用与 git ls-remote 相同的代码:当使用 git remote set-head --auto 时,您的 Git 必须弄清楚他们的 Git 有作为他们的 HEAD,这意味着调用他们的 Git 并询问他们。

  • git remote show 如果您使用 -n 选项,则联系遥控器。像其他人一样,它使用 git ls-remotegit remote set-head 在这里使用的相同代码来询问其他 Git 其各种分支名称。使用 -n,它不会那样做,只会查看您的(本地)远程跟踪名称。

其中一些东西早于遥控器的发明。在 Git 有遥控器之前,比如 origin,你每次都必须输入完整的 URL。这太可怕了。1所以人们尝试了几种方法来解决这个问题。其中只有一个工作得非常好,但今天的 Git 仍然支持其他几个;您会在 git fetchgit push 文档中看到这些内容。

远程的概念被发明时——像 origin 这样的短名称可以包含 URL——Git 发展了远程跟踪名称的概念.2 这些让你的 Git 记住 他们的 Git 的 maindevelopfeature-1 等等在。我们使用它们的方式简单而干净:我们的 Git 从它们的 origin/main 创建或更新我们的 main,因为我们运行了 git fetch origin。如果我们的 Git 看到他们当时拥有 feature-1,我们的 Git 也会创建或更新我们的 origin/feature-1。这里的精确细节随着时间的推移而改变,3 但在现代 Git 中,我们有这些远程跟踪名称。我们只需运行 git fetch 即可更新它们。4

但是,您可以选择让您自己的 Git 存储库跟踪他们的所有 (origin) 分支。如果你愿意,你可以建立一个所谓的单分支克隆。在这里,您在 origin 上选择一些您希望 Git 复制到 origin/whatever 的分支:

  • 您可以使用 git clone 选项在 --single-branch 时间执行此操作。

  • 或者,您可以使用 git remote add 选项在 -t 时间执行此操作。

您可以使用 git remote set-branches 将您拥有 Git 副本的分支更新为远程跟踪名称。这样,您可以将事情设置为“跟踪”(例如,为其创建远程跟踪名称)两个 分支,而不仅仅是一个。

git remote show 命令将读取它们的分支名称(没有 -ngit remote show 在内部运行 git ls-remote)或猜测它们的分支名称 (-n) , 并且会告诉你他们的哪个分支名称你正在将你的 Git 副本复制到远程跟踪名称。这就是说 tracked 时的意思。


1要了解原因,请尝试每次都输入完整的 URL。它会变得很累,而且错别字的机会很大。

2Git 文档称这些远程跟踪分支名称。我发现这里的branch 这个词只是把它弄乱了。例如,它们不是您存储库中的分支名称,因为 git switch 不会切换到它们;你必须使用 git switch --detach 并且你最终会得到一个分离的 HEAD。这一切都很好,但表明该名称不是 branch 名称,因此也不要将其 称为

3在 Git 1.8.4 版之前,某些类型的 git fetch 根本不需要更新任何远程跟踪名称。一些 Linux 发行版仍然附带这些古老版本的 Git。使用 git --version 找出您拥有的版本。

4这些远程跟踪名称有一个问题。假设 origin 有一个临时分支名称,如 temp。您运行 git fetch origin(或仅运行 git fetch,它从 origin 获取)并在您的存储库中获得 origin/temp

然后——一分钟后,或下周,或其他——控制origin删除他们的temp分支的人。你再次运行git fetch;您的 Git 调用 origin 并找到 main 分支,但没有找到 temp 分支。因此,您的 Git 会更新您的 origin/main ...但对您的 origin/temp 没有任何作用。他们没有,所以没有必要更新你的

这会让您陈旧 origin/temp。这只是剩下的垃圾。您可以手动删除它,也可以运行 git fetch --prune origingit remote prune origin。你的 Git 会调用他们的 Git,查看他们的分支名称,看到他们没有有一个 temp,看到你确实有一个 {{ 1}},并清除剩余的垃圾。

或者,您可以在配置中将 origin/temp 设置为 fetch.prune。我在我的每用户全局中这样做:

true

这使得每个 git config --global fetch.prune true 都像 git fetch 一样,自动清除死木远程跟踪名称。

可能应该是 Git 的默认设置,但 Git 仍然主要与 Git 1.7 版兼容,而 Git 1.7 版没有做到这一点,所以现代 Git 仍然没有。