什么是跟踪分支?

251

有人能解释一下"tracking branch"在git中是什么吗?

这是git-scm.com的定义:

在Git中,“跟踪分支”是连接到远程分支的本地分支。当您在该分支上推送和拉取时,它会自动推送和拉取到与其连接的远程分支。

如果您总是从同一上游分支拉入新分支,并且不想显式使用“git pull”,则可以使用此功能。

不幸的是,作为一个新手,来自SVN,这个定义对我来说完全没有意义。

我正在阅读"The Pragmatic Guide to Git"(顺便说一句,这是一本很棒的书),他们似乎在暗示跟踪分支是一件好事,并且在创建第一个远程库(在这种情况下是origin)之后,应该将主分支设置为跟踪分支,但它不幸没有涵盖为什么跟踪分支是一件好事,或者通过将主分支设置为原始存储库的跟踪分支可以获得什么好处。

有人能用英语给我解释一下吗?


9
一个术语注释:在Git中,单词“track”被使用得非常混乱。有些文件是“tracked”,有些是“untracked”;有些分支名称称为“remote-tracking branches”;你可以使用--track选项创建一个(本地)分支,并将其中一个远程跟踪分支设置为其“upstream”。这些术语在2006年至2019年之间发生了一些演变,因此不同的人有时可能会对每个术语有不同的理解。 - torek
我个人建议使用短语“remote-tracking names”代替“remote-tracking branches”,部分原因是因为单词“branch”也有点过载。远程跟踪名称看起来像origin/master:它们在您的存储库中,但它们是Git记住在origin上看到的分支名称的方式。如果您使用更现代的术语upstream来表示您的master已将origin/master设置为其upstream,则可以避免所有这些术语混淆。 - torek
@torek,“remote-tracking branch” 这个术语不能被替换为“remote-tracking names”,因为跟踪分支具有物理状态,可能与本地分支和远程分支都不同。 - Michael Freidgeim
@MichaelFreidgeim: 玫瑰花,无论叫什么名字…… 如果你关心哈希 ID 的存储,你应该意识到在 Git 中,哈希 ID 存储在 名称 下。不仅是 分支 名称,还有 标签 名称、refs/stash、二分查找名称和其他名称:所有这些都存储了一个哈希 ID。 - torek
值得一提的是,从 Git 2.37(2022 年第三季度)开始,可以使用 git config git config --global push.autoSetupRemote 命令来设置自动推送远程分支。这样你就不需要太过担心了。 - Robin Bastiaan
@torek 一个替代的官方名称可以是“远程跟踪指针”。 - ankostis
7个回答

206

ProGit书非常好的解释:

跟踪分支

从远程分支检出本地分支会自动创建所谓的跟踪分支。跟踪分支是具有与远程分支直接关联关系的本地分支。如果您在跟踪分支上并输入git push,Git会自动知道要推送到哪个服务器和分支。此外,在这些分支中运行git pull将获取所有远程引用,然后自动合并相应的远程分支。

当你克隆仓库时,通常会自动创建一个跟踪origin/master的主分支。这就是为什么git pushgit pull可以直接使用而无需其他参数的原因。但是,如果您希望设置其他跟踪分支,则可以设置不跟踪origin上的分支或不跟踪master分支的跟踪分支。最简单的情况是刚才看到的示例,运行git checkout -b [branch] [remotename]/[branch]。如果您的Git版本为1.6.2或更高版本,则还可以使用--track简写:

$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch refs/remotes/origin/serverfix.
Switched to a new branch "serverfix"

如果你想要用一个不同的名字来设置本地分支而不是远程分支,你可以轻松使用第一种方法,并指定一个不同的本地分支名:

$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch refs/remotes/origin/serverfix.
Switched to a new branch "sf"

现在,你的本地分支sf会自动推送到和拉取自origin/serverfix

BONUS:额外的git status信息

使用跟踪分支,git status将告诉你你距离跟踪分支有多远-这对提醒你还没有推送你的更改非常有用!它看起来像这样:

$ git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)
或者
$ git status
On branch dev
Your branch and 'origin/dev' have diverged,
and have 3 and 1 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)


@JohnO,你可能需要与Pro Git的作者商量一下。据我所知,整本书都是通过大规模编辑协作完成的。 - Assaf Lavie
3
根据 https://www.sbf5.com/~cduan/technical/git/git-4.shtml 的说法,--track 默认已经开启了,因此不必要加上该参数。 - Hank Lin
这本书看起来是一个很好的资源。谢谢! - Alex Mandelias
只是提醒一下,我看到很多人在使用“git status”时都犯了同样的错误——它不会检查你本地的主分支/任何分支是否与远程分支同步,所以当“git status”显示“up to date...”时,请不要感到困惑并相信你的分支已经与远程同步,因为“git status”不会进行任何网络调用,它只是检查当前仓库状态与克隆/更新本地时仓库状态之间的差异。要检查远程同步/更新,请使用“git fetch”。 - Abhinav Ghosh
如果我想从origin/dev一次性拉取到abc本地分支怎么办?我不想动态地推送和拉取origin/dev的变化。在这种情况下,我不会追踪该分支,只需执行一次拉取操作,对吗? - Jatin

84

以下是我个人关于GIT跟踪分支的学习笔记,希望对未来的访问者有所帮助:

enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here


追踪分支和"git fetch":

enter image description here enter image description here enter image description here


1
谢谢你的笔记!如果可能的话,你介意分享所有的笔记吗?谢谢; - Aditya
@Aditya:这个问题是关于跟踪分支的,我已经发布了所有关于这个主题的笔记。如果我找到其他相关问题可以发布我的其他GIT笔记,我会很高兴这样做。 - hagrawal7777
@Aditya:啊,我明白了。现在你清楚自己的意思了。我正在赶我的网站,还没有为自己创建一个。 - hagrawal7777
13
你的笔记很有用,但请考虑使用文本而不是图片。https://meta.stackoverflow.com/questions/303812/discourage-screenshots-of-code-and-or-errors/307500#307500 - Michael Freidgeim
2
标题为“如何显式设置远程跟踪分支”的部分对于新手(比如我自己)来说可能有些误导性。我正在寻找特定的命令来设置跟踪 - 但最后一个单词是'master'。它应该改为<本地分支名称>。除了这个小问题,这是非常好的信息。 - venk
显示剩余2条评论

53

《Pro Git》 提到

跟踪分支是与远程分支有直接关系的本地分支

不完全正确。SO问题 "难以理解 git-fetch" 包括:

没有所谓的本地跟踪分支,只有远程跟踪分支。
因此,origin/masterorigin 仓库中 master 的远程跟踪分支。


注意,Git 2.37(2022年第3季度)允许您自动设置远程跟踪分支,方法如下:

git config --global push.autoSetupRemote true

实际上,一旦您在以下之间建立了上游分支关系

  • master这样的本地分支
  • 和像origin/master这样的远程跟踪分支

您可以使用git branch -avv列出它们。

然后,您可以将master视为本地跟踪分支:它跟踪远程跟踪分支origin/master,后者又跟踪上游repo origin的主分支。

alt text

换句话说:"远程"在"远程跟踪分支"中表示远程分支的一个本地副本(跟踪),以记住上次获取的内容。
正如Michael Freidgeim评论中所补充的:

"远程跟踪分支"这个术语很令人困惑。

更加精确的词应该是:

"本地位置的远程跟踪分支"。

否则,有人可能会误解“远程跟踪分支”位于源服务器上。


图像说明:我的计算机比原始版本领先2个提交。这就是那两个提交来自主分支的原因。图像链接:http://progit.org/book/ch3-5.html - idbrii
3
@SherylHohman,不会直接或间接地跟踪任何内容,只会跟踪你为其指定的远程跟踪分支。在分支派生的情况下,最佳做法是对于常用分支(如主分支master),跟踪上游(即原始仓库),对于新分支(如PR或特性分支)跟踪origin(你的远程分支)。请参阅https://dev59.com/wGEh5IYBdhLWcg3w7nWW#21847690。 - VonC
3
“@VonC - The statement "There's no such concept of local tracking branches, only remote tracking branches." is interesting b/c there's such conflicting terminology around branches. This often referenced link https://web.archive.org/web/20130419172453/http://www.gitguys.com/topics/tracking-branches-and-remote-tracking-branches distinguishes between "tracking branches" & "remote tracking branches". They call origin/master a "remote tracking branch" - I agree - but then they call "master" a "tracking branch" too. What is master tracking? Are they wrong or is it a terminology problem?”这段话中的语句“没有本地跟踪分支的概念,只有远程跟踪分支”的说法很有趣,因为分支方面的术语存在着很多冲突。这个链接 https://web.archive.org/web/20130419172453/http://www.gitguys.com/topics/tracking-branches-and-remote-tracking-branches 经常被引用,并将“跟踪分支”和“远程跟踪分支”区分开来。他们将origin/master称为“远程跟踪分支”,我也同意这一点,但然后他们也称“master”为“跟踪分支”。那么master是什么样的跟踪分支?他们是错了还是术语上存在问题? - Howiecamp
2
@Howiecamp,所谓的“跟踪分支主分支”就是一个带有关联远程跟踪分支origin/master的本地分支master,用于记忆上次从远程主分支origin获取的SHA1值。因此,它是指定“带上游分支的本地分支”的一种“快捷方式”。 - VonC
“它跟踪远程跟踪分支的源头/主分支”这句话是什么意思?这是否意味着每当我在git pull origingit fetch origin命令后不加任何参数,则会将origin/master中的内容拉取到本地的master分支中?如果没有被跟踪,那么该命令就不能为我完成此操作。我必须使用git pull origin master才能使其工作?(已编辑) - mfaani
显示剩余4条评论

12

这是我添加跟踪分支的方法,以便可以从中拉取到我的新分支:

git branch --set-upstream-to origin/Development new-branch

7
记住,所有的git分支本身都用于跟踪一组文件的历史。因此,每个分支实际上都是一个“跟踪分支”,因为这些分支用于跟踪文件随时间变化的历史记录?
因此,我们应该将普通的git“分支”称为“跟踪分支”,但我们没有这样做。相反,我们将它们的名称缩短为“分支”。

因此,“跟踪分支”这个术语非常令人困惑的部分原因是:对于初学者来说,它很容易意味着两种不同的东西。

在git中,“跟踪分支”的术语是“远程跟踪分支”的简称。

起初最好使用更正式的术语,直到您对这些概念更加熟悉为止。


让我们将您的问题改成这样:

什么是 "远程-跟踪分支"?

关键词在于 'Remote',所以跳到您感到困惑的部分,我将描述什么是 远程跟踪分支 以及它如何使用。


为了更好地理解git术语,包括分支和追踪,这些可能一开始非常令人困惑,我认为最容易的方法是您首先完全清楚git是什么以及其基本工作结构。如果没有像这样牢固的理解,我向您保证,您将在许多细节中迷失方向,因为git非常复杂;(翻译:许多人将其用于非常重要的事情)。
以下是简介/概述,但您可能还会发现{{link1:这篇优秀文章}}也很有帮助。

GIT是什么以及它的作用

一个git存储库就像一个家庭相册:它保存了历史快照,展示了过去时光的样子。 "快照" 是某一时刻记录下来的东西。

Git存储库不仅限于保存人类家庭照片,它可以用于记录和组织任何随着时间演变或变化的事物

基本思想是创建一本书,以便我们可以轻松地回顾过去的时间,

  • 比较过去、现在或其他时刻,以及
  • 重新创建过去。

当你被复杂的术语和概念所困扰时,请记住,Git仓库首先是快照的存储库,就像相册一样,用于存储和组织这些快照。

快照和跟踪

tracked - 跟踪一个人或动物,寻找他们曾经去过某个地方的证据(dictionary.cambridge.org)

在Git中,“您的项目”指的是文件的目录树(一个或多个文件,可能使用子目录组织成树结构),您希望保留其历史记录。

通过一个三步骤的过程,Git记录了您的项目目录树在特定时间点的“快照”。

然后,每个Git项目的快照都通过"链接"组织到前面的项目的快照中。

一个接一个地,我们可以逐个链接,向后查找任何您或您的家族的以前的快照。

例如,我们可以从今天最新的您的快照开始,然后使用链接向后查找,找到昨天或上周拍摄的您的照片,或者是您还是婴儿时的照片,或者是您的母亲等等。

这被称为“跟踪”;在这个例子中,它追踪你的生活,或者看到你留下了什么痕迹,以及你来自哪里。

提交记录

提交记录类似于你的相册中的一页,只有一个快照,其中不仅包含了该快照的内容,还有关于该快照的相关元信息。它包括:

  • 地址或固定位置,我们可以在那里找到这个提交记录,类似于页面编号。
  • 项目的一个快照(文件目录树)在某个时间点的状态。
  • 说明或注释,说明该快照是关于什么的。
  • 该快照的日期和时间。
  • 谁拍摄了该快照。
  • 向后链接到先前的相关快照,例如昨天的快照或父级快照等一项或多项链接。换句话说,“链接”类似于指向其他旧照片的页码的指针,或者当我出生时指向我的直系亲属。

提交记录是组织良好的相册中最重要的部分。


随着分支和合并的时间推移,家谱不断演变

消歧义:此处的“树”不是指文件目录树,而是指随着时间推移形成的相关父子提交的家谱。

Git家谱结构模仿了我们人类的家谱树。

为了帮助您简单理解链接,我将引用以下术语:

  • 一个parent-commit简称为“parent”,
  • 一个child-commit简称为“child”,如果是复数则为“children”。

您应该本能地理解这一点,因为它基于生命之树:

  • 一个父亲可能有一个或多个指向他们的孩子,
  • 孩子总是有一个或多个指向他们的父母。

因此,除了全新的提交(可以说是“幼嫩的提交”)之外,所有提交都有一个或多个指向它们的孩子。

  • 如果没有子元素指向父元素,那么这个提交只是一个“生长点”,或者下一个子元素将从哪里出生。

  • 如果只有一个子元素指向父元素,那么这只是一个简单的、单一的父元素<--子元素关系。

简单的、单一的父代链条反向链接的线状图:

(older) ... <--link1-- Commit1 <--link2-- Commit2 <--link3-- Commit3 (newest)

分支

branch - “分支”是一个活跃的开发线路。在分支上最新的提交被称为该分支的“尖端”。分支的“尖端”由一个分支头引用,随着对分支的进一步开发而向前移动。单个Git存储库可以跟踪任意数量的分支,但您的工作树仅与其中一个相关联(“当前”或“签出”分支),HEAD指向该分支。(gitglossary)

Git分支还指两件事:

  • 一个名称给定的增长点(标识符)
  • 链接提交之间图形中的实际分支

多个子节点指向同一个父节点,这就是Git所谓的“分支”。

注意:实际上,任何父母的任何孩子,无论是第一、第二还是第三等,都可以被视为他们自己的小分支,有着自己的生长点。因此,一个分支不一定是一个有许多节点的长物,而是一个小东西,只需从给定的父级中创建一个或多个提交即可。
一个父级的第一个孩子可能被认为是同一分支的一部分,而该父级的后续孩子通常被称为“分支”。
实际上,所有的孩子(不仅仅是第一个孩子)都从它的父级分支出来,或者你可以说是链接,但我会认为每个链接实际上是一个分支的核心部分。
正式地说,git的“分支”只是一个名称,比如'foo',给家族层次结构的特定生长点。它是所谓的“ref”的一种类型。(标签和稍后我将解释的远程也是refs。) ref - 以refs/开头的名称(例如refs/heads/master),指向对象名称或另一个引用(后者称为符号引用)。为方便起见,当用作Git命令的参数时,有时可以缩写引用;有关详细信息,请参阅gitrevisions(7)。 引用存储在存储库中。
引用名称空间是分层的。不同的子层次结构用于不同的目的(例如,refs/heads/层次结构用于表示本地分支)。有一些不以refs/开头的特殊用途引用。最显着的例子是HEAD。(gitglossary
(您应该查看.git目录内部的文件树。这是保存git结构的地方。)
因此,例如,如果您的名字是Tom,则仅包括您快照的提交链接在一起,可能是我们命名为“Tom”的分支。

因此,虽然你可能认为树枝就是它的木材,但在Git中,分支只是给它的生长点(不包括通向它的整个木杆)起的名称。

专业的园艺师(修剪果树的人)称之为“主干”,而Git称之为主分支

Commit1及其2个子节点的线条图(或我们所说的Git"分支"):

                parent      children

                        +-- Commit <-- Commit <-- Commit (Branch named 'Tom')
                       /
                      v
(older) ... <-- Commit1 <-- Commit                       (Branch named 'master')    

请记住,链接从子级指向父级。

没有反向链接,即从旧的到新的,也就是从父级到子级的链接。

因此,父提交没有直接列出其子提交的方法,换句话说,无法列出从它派生的内容。


合并

孩子有一个或多个父母。

  • 只有一个父母时,这只是一个简单的父亲 <-- 孩子提交。

  • 有多个父母时,这就是Git所称的"合并"。 每个孩子可以同时指向多个父母,就像拥有母亲和父亲一样,而不仅仅是母亲。

线条图示:带有2个父级的提交2(或我们称之为git "合并",即来自多个父级的繁殖):

                parents     child

           ... <-- Commit
                        v
                         \
(older) ... <-- Commit1 <-- Commit2  

远程

这个词也有两个不同的含义:

  • 一个远程仓库,以及
  • 远程仓库的本地别名,即指向远程仓库的URL的名称。

远程仓库 - 用于跟踪相同项目但位于其他位置的仓库。要与远程通信,请参见获取或推送。(来源:gitglossary)

(远程仓库甚至可以是我们自己计算机上的另一个git仓库。) 实际上,每个远程名称都有两个URL,一个用于推送(即上传提交),另一个用于从远程git仓库拉取(即下载提交)。

"远程"是一个名称(标识符),它有一个关联的URL,该URL指向远程git仓库。(虽然它不止如此,但它已被描述为URL的别名。)

如果您想要拉取或推送到多个远程仓库,则可以设置多个远程。

虽然通常只有一个默认名称为“origin”的上游源(表示从哪里克隆),但可以有多个。

origin - 默认的上游存储库。大多数项目至少有一个它们跟踪的上游项目。默认情况下,使用origin进行此操作。新的上游更新将被获取到名为origin/name-of-upstream-branch的远程跟踪分支中,您可以使用git branch -r查看。(来源:gitglossary)

Origin代表你克隆仓库的位置。
那个远程仓库称为“上游”仓库,而你克隆的仓库称为“下游”仓库。

upstream - 在软件开发中,上游指向作为源代码分发的软件的原始作者或维护者的方向wikipedia

上游分支 - 默认的分支,会被合并到所讨论的分支中(或者所讨论的分支会被变基到该分支上)。 它是通过branch..remote和branch..merge进行配置的。如果A的上游分支是origin/B,有时我们会说"A正在跟踪origin/B"。(gitglossary

这是因为大部分水通常都流向你。
不时地,您可能会将一些软件推回到上游存储库,以便它可以流向所有克隆它的人。

远程跟踪分支

远程跟踪分支首先是一个分支名称,就像任何其他分支名称一样。

它指向本地增长点,即的本地git存储库中的最新提交。

但请注意,它实际上也指向您从中克隆提交的远程存储库中的相同提交。

远程跟踪分支 - 用于跟踪来自另一个存储库的更改的引用。它通常看起来像refs/remotes/foo/bar(表示它跟踪名为foo的远程中的名为bar的分支),并匹配配置的fetch refspec的右侧。远程跟踪分支不应包含直接修改或对其进行本地提交。(来源:gitglossary
假设你克隆的远程仓库只有两个提交,如下所示:parent4 <== child-of-4,当你克隆它时,你的本地Git仓库也有完全相同的两个提交:parent4 <== child-of-4。你的名为origin的远程跟踪分支现在指向child-of-4
现在假设远程仓库添加了一个提交,看起来是这样的:parent4 <== child-of-4 <== new-baby。为了更新你的本地下游仓库,你需要获取new-baby,并将其添加到你的本地git仓库中。现在你的本地远程跟踪分支指向new-baby。你明白了吧,远程跟踪分支的概念就是为了跟踪你关心的远程分支之前的tip。

跟踪实战

首先,我们使用git开始跟踪一个文件。

enter image description here

以下是与文件跟踪相关的基本命令:
$ mkdir mydir &&  cd mydir &&  git init         # create a new git repository

$ git branch                                    # this initially reports no branches
                                                #  (IMHO this is a bug!)

$ git status -bs   # -b = branch; -s = short    # master branch is empty
## No commits yet on master

# ...
$ touch foo                                     # create a new file

$ vim foo                                       # modify it (OPTIONAL)


$ git add         foo; commit -m 'your description'  # start tracking foo 
$ git rm  --index foo; commit -m 'your description'  # stop  tracking foo 
$ git rm          foo; commit -m 'your description'  # stop  tracking foo 
                                                     #   & also delete foo

远程跟踪实现

$ git pull    # Essentially does:  get fetch; git merge    # to update our clone

关于fetch、merge等还有很多需要学习的内容,但我希望这能让你朝着正确的方向前进。


2
没有人提到如何查看已设置的所有跟踪分支,因此这里是命令,考虑这是部分答案,请阅读其余内容以了解跟踪分支是什么:
git branch -vv
可以查看所有已设置的跟踪分支。
我的简短回答是:跟踪分支就像普通分支,但与某个远程存储库的分支有一个“链接”,如果远程分支更改,则在您进行操作时会通知您的本地分支。
git status

1

跟踪分支是一种节省输入的方式。同时在使用git statusgit branch -v时,它也会提供一些额外的细节。

现在让我解释一下"节省输入"的含义。

如果我们跟踪一个分支,我们就不必每次都输入git push origin <branch-name>git pull origin <branch-name>git fetch origin <branch-name>git merge origin <branch-name>假设我们将远程命名为origin,我们可以直接使用git pushgit pullgit fetchgit merge。如果我们没有将远程命名为origin,我们可以分别使用git push <remote-name>git pull <remote-name>git fetch <remote-name>git merge <remote-name>

执行默认的git pull调用等同于git fetch origin HEADgit merge HEAD,其中HEAD是指向当前分支的引用。 git push命令将当前分支上的所有提交发送到中央仓库。因此,该命令看起来像git push origin <current-branch> 如果我们正在跟踪一个分支,那么简单的短语git merge被视为git merge origin/<current-branch> 当我们执行以下操作时,就会跟踪一个分支:
  1. 使用git clone克隆存储库
  2. 使用git push -u origin <branch-name>。这个-u使它成为一个跟踪分支。
  3. 使用git branch -u origin/<branch-name> <branch-name>
  4. 在检出时使用--track。例如:git checkout --track origin/<branch-name>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接