“git pull”和“git fetch”有什么区别?

13731

435
我发现了一篇关于git fetch和git pull的写得很好的文章,值得一读:http://longair.net/blog/2009/04/16/git-fetch-and-merge/ - Marcos Oliveira
68
我们的替代方法是在工作流程中使用 git fetch; git reset --hard origin/master。它会清除本地更改,让你与主分支保持同步,而且还能确保你不会在当前变更的基础上拉取新变更并搞砸一切。我们已经使用这种方法一段时间了,在实践中感觉更加安全。只需确保先添加/提交/储藏任何正在进行中的工作! - Michael Durrant
38
请确保您知道如何正确使用git stash。如果您正在询问“pull”和“fetch”,那么可能需要解释“stash”...... - Henry Heleine
48
许多从Mercurial过来的人会继续使用"git pull",认为它等同于"hg pull"。但实际上并不是这样。Git中等同于“hg pull”的命令是“git fetch”。 - Serge Shultz
1
git pull 从远程分支拉取并合并代码。 git fetch 只是从远程分支获取代码,但不进行合并。 - Murat Özbayraktar
显示剩余2条评论
38个回答

11454

简单来说,git pull 命令会先执行 git fetch,然后再执行 git merge


git fetch会更新你的远程跟踪分支,存储在refs/remotes/<remote>/中。此操作安全,可以随时运行,因为它不会更改refs/heads下的任何本地分支。

git pull将本地分支与其远程版本保持最新,并更新其他远程跟踪分支。

来自git pull的Git文档中的说明:

git pull使用给定参数运行git fetch,根据配置选项或命令行标志调用git rebasegit merge以协调分叉的分支。


379
“git pull”是用来更新您的代码仓库的操作。它会将您本地的分支与远程分支合并,使之保持同步。与此不同,“git fetch”只是获取最新的远程分支代码,并没有实际进行合并操作。关于“merge”的问题: 它将远程分支与您本地的分支进行合并,确保两者代码相一致。 - Albert
224
@Albert: 是的,这句话措辞有点奇怪。git pull 命令总是会将更新合并到当前分支。因此,你要选择从哪个分支拉取代码,并将其合并到当前分支中。被拉取的分支可以是本地分支或远程分支;甚至可以是一个未在 git remote 中注册的远程分支(也就是说,在 git pull 命令行上传递一个 URL)。 - intuited
143
不。推送操作不会自动执行合并操作。用户需要先拉取代码,本地解决任何合并冲突,然后再将代码推送回远程仓库。 - Greg Hewgill
39
如果我在 /home/alice/ 目录下执行了 git fetch /home/bob,接下来如果要执行 git merge 命令,应该传入哪些参数? - ripper234
125
给正在学习Git的人们的提示:使用“fetch”加“merge”无法真正模拟“pull”的效果。我只是获取了一个仅远程分支指针发生变化的更改,但“merge”却拒绝执行任何操作。相反,“pull”会快速向前推进我的跟踪分支。 - Roman Starkov
显示剩余6条评论

2606
  • git pull 会在获取提交记录后自动尝试合并。由于其具有上下文敏感性,因此所有获取的提交记录将被合并到您当前活动的分支中。git pull 会自动合并提交记录,不让您事先审查。如果您没有仔细管理分支,可能会经常遇到冲突。

  • git fetch 会收集目标分支中不存在于当前分支中的任何提交记录,并将它们存储在本地仓库中。然而,它不会与您当前的分支合并。如果您需要将提交记录与当前分支集成,则必须之后使用git merge


45
同意,很棒的评论。这就是为什么我讨厌git pull。让一个修订工具替你编辑代码有何意义呢?而将两个文件合并不就是在做这件事吗?如果这两个编辑在文件中物理上分开,但逻辑上相互矛盾呢? - Lee Dixon
我不确定我是否正确理解了这个问题。如果我错了,请告诉我:假设我有两个分支,master和test。test是我正在进行实验的一个分支。如果我执行git fetch命令,它会将目标分支更新到master分支。如果我执行git pull命令,它会尝试将目标分支更新到test分支。这样对吗?如果不是,那么我可能不理解“本地存储库”的含义——我认为它指的是我的本地master分支。 - elexhobby
156
"git fetch" 只会更新您的 ".git/" 目录(又称为本地仓库),而不会影响 ".git/" 以外的任何内容(即工作树)。它不会更改您的本地分支,也不会触及 "master" 分支。但是,它会更新 "remotes/origin/master" 分支(请参见 "git branch -avv")。如果您有更多的远程仓库,请尝试使用 "git remote update" 命令,这可以一次性更新所有远程仓库。 - Tino
32
@Tino你提出的确实是最重要的观点。人们可能不知道,“远程”分支实际上是存储在.git/refs/remotes/origin目录下的一串哈希值。 - Chris
1
@crazyTech 如果这就是 'git fetch' 的作用,为什么 git 文档说它更新远程跟踪分支的网络通信? "远程跟踪分支是对远程分支状态的引用。 它们是本地引用,您无法移动; 只要您进行任何网络通信,Git 就会代替您移动它们" - Nick Koprowicz
显示剩余2条评论

1412
重要的是要将 git 的设计理念与传统的源代码控制工具(如 SVN)的哲学进行对比。
Subversion 是使用客户端/服务器模型设计和构建的。有一个单一的仓库作为服务器,多个客户端可以从服务器获取代码、在其上工作,然后将其提交回服务器。假设客户端需要执行操作时,它总是可以联系到服务器。
Git 设计支持更分布式的模型,无需中央仓库(尽管如果您愿意,可以使用)。而且 Git 的设计使得客户端和“服务器”不需要同时在线。甚至可以通过电子邮件交换代码,在不可靠的链接上工作也是可能的。可以完全脱机工作,通过 Git 刻录 CD 来交换代码。
为了支持这种模型,Git 维护本地存储库和另一个本地存储库,镜像远程存储库的状态。通过在本地保留远程存储库的副本,即使远程存储库无法访问,Git 也可以确定所需的更改。当您需要将更改发送给其他人时,Git 可以将它们作为一组变更从已知远程存储库的时间点传输。
- `git fetch` 命令用于将本地的远程存储库同步更新; - `git pull` 命令用于将远程存储库中的变更合并到您自己的代码存储库和可能的工作副本中。
通常情况下,`git pull` 通过执行 `git fetch` 来使本地的远程存储库同步更新,并将变更合并到您自己的代码存储库和可能的工作副本中。
需要记住的是,在您的工作站上通常至少有三个项目副本。其中一个副本是您自己的存储库,包含自己的提交历史记录;第二个副本是您正在编辑和构建的工作副本;第三个副本是本地“缓存”的远程存储库。

93
从技术上讲,本地和远程仓库实际上是同一个仓库。在 Git 中,仓库是指指向其父级提交的有向无环图。分支从技术上讲只是提交的有意义名称。本地分支和远程分支唯一的区别在于,远程分支以 remoteName/ 为前缀。《从底层开始学习 Git》是一篇非常好的阅读材料。一旦您理解了 Git 的工作原理——它真的很简洁——一切都很容易理解。 - Emil Lundberg
2
错误。仓库不包含您的工作树的副本。仓库是更改列表。因此,除非您明确地cp -R它,否则工作站上只有一个项目实例。 - Aleks N.
感谢@EmilLundberg提供的链接。那篇文章看起来会改变人生。 - DryLabRebel

1143

188
一张更新的包含'git clone'和'git merge'的图片会非常有帮助! - MEMark
24
是的,请添加 git merge - 它应该清楚地显示,单独调用 merge 不同于调用 pull,因为 pull 仅从远程合并,并忽略您在本地分支中跟踪的远程分支中的本地提交。 - JustAMartin
16
一幅图胜过千言万语!克隆和合并数据流的更新图片是否已经准备好了?除图表中已有的数据流之外,还有其他的数据流吗? - shikhanshu
@JustAMartin 这完全是错误的。拉取操作不会忽略任何合并操作不会忽略的内容。拉取操作就是获取(fetch) + 合并(merge),没有更多,也没有更少。 - Gerard van Helden
好的。你的评论“忽略本地提交”似乎暗示了不同的意思,这就是为什么我有所反应的原因。 - Gerard van Helden
显示剩余3条评论

587

git fetch的一个用例是,以下命令将告诉您自上次拉取以来远程分支中的任何更改...因此您可以在进行实际拉取之前进行检查,这可能会更改当前分支和工作副本中的文件。

git fetch
git diff ...origin

请参考 git diff 文档,了解双点号..和三点号...语法。


如果fetch有冲突会发生什么?谢谢。 - eastwater
@eastwater 根据定义,fetch操作本身不会产生冲突。它只是从远程获取变更。冲突通常发生在我们合并变更的过程中。 - undefined

430

我花了一点时间才明白它们之间的区别,但这是一个简单的解释。在您的本地主机中,master 是一个分支。

当你克隆一个存储库时,你会将整个存储库提取到你的本地主机。这意味着此时你有一个指向 HEAD 的 origin/master 指针和一个指向相同 HEAD 的 master。

当您开始工作并提交时,您将使 master 指针前进到 HEAD + 您的提交。但是,origin/master 指针仍然指向您克隆时的位置。

因此,它们之间的区别是:

  • 如果您执行 git fetch,它只会获取远程存储库(GitHub)中的所有更改并将 origin/master 指针移动到 HEAD。与此同时,您的本地 master 分支将继续指向其原来的位置。
  • 如果您执行 git pull,它基本上会执行 fetch(如前面所述)并将任何新更改合并到您的 master 分支,并将指针移动到 HEAD

17
origin/master 是本地分支,是 origin 上 master 分支的一个复制。当你执行 fetch 操作时,会更新本地的 /origin/master。一旦你真正理解了 git 中一切都是分支的概念,这就有很多意义了,它是一种非常强大的方式来维护不同的变更集、创建快速本地分支、合并和变基,并从廉价分支模型中获得很多价值。 - cam8001
@cam8001 我觉得你应该强调“本地”而不是“复制”。 - Mehdi Charife

297

简言之

git fetch 获取更新但不合并。

git pull 在后台执行 git fetchmerge

详细解释

git fetch 类似于 pull 但不会合并。即它会获取远程的更新(refsobjects),但本地仓库保持不变 (例如 origin/master 更新了,但是 master 仍然保持原样)。

git pull 会从远程拉取最新的内容并立即合并。

git clone 克隆一个仓库。

git rebase 将当前分支中不在上游分支中的更改保存到临时区域。此时你的分支与进行更改前一样。因此,git pull -rebase 会拉取远程更改,回退本地分支,逐个回放你的更改,直到你跟上最新版本。

另外,git branch -a 可以显示所有分支(本地和远程)的情况。

这篇博客文章很有用:

git pull、git fetch 和 git clone (以及 git rebase) 的区别 - Mike Pearce

其中包括 git pullgit fetchgit clonegit rebase

更新

我想更新一下,展示如何在实践中使用这些命令。

  1. 从远程更新本地仓库(但不合并):

     git fetch 
    
  2. 下载更新后,让我们看看有什么不同:

  3.  git diff master origin/master 
    
  4. 如果您对这些更新感到满意,那么请进行合并:

  5.  git pull
    

注意:

在第2步: 有关本地和远程之间差异的更多信息,请参见:如何比较本地 Git 分支和其远程分支

在第3步: 在一个快速变化的存储库上,可能更准确的做法是在这里执行git rebase origin。请参见另一个答案中的@Justin Ohms comment

还可以参考:http://longair.net/blog/2009/04/16/git-fetch-and-merge/

注意:我在pull过程中提到了merge,但您也可以配置pull使用rebase


以下是非常重要的更新在下载更新后,让我们看看差异:'git diff master origin/master' - Aadishri
在这里的第三步中,这不可以是git merge而不是git pull吗?因为git fetch已经发生了。 - Scott Weaver
上面的Mike Pearce链接已经失效了,真可惜。有没有其他的选择?啊,找到了:https://mikepearce.wordpress.com/2010/05/18/the-difference-between-git-pull-git-fetch-and-git-clone-and-git-rebase/ - undefined

297
有时候,视觉表现会更有帮助。

输入图片描述


27
我认为这张图片应该展示它也会影响本地代码库。也就是说,Git pull 是同时影响本地代码库和工作副本的。现在似乎只有工作副本受到了影响。 - nonopolarity

207
git-pull - 从另一个存储库或本地分支获取并合并内容 概述
git pull … 描述
使用给定的参数运行git-fetch,并调用git-merge将检索到的head(s)合并到当前分支。 使用--rebase,调用git-rebase而不是git-merge。
请注意,您可以使用 . (当前目录) 作为从本地存储库中提取——这在将本地分支合并到当前分支时非常有用。
还要注意,用于git-pull本身和底层git-merge的选项必须在用于git-fetch的选项之前给出。
如果您想要合并历史记录,则会进行pull操作; 如果您只想要代码,则会进行fetch操作,因为某些人一直在标记这里的一些文章。

189

好的,这里有关于git pullgit fetch的一些信息,这样你就可以了解实际的区别...用简单的话来说,fetch获取最新的数据,但不获取代码更改,也不会对你当前的本地分支代码进行干扰,而pull获取代码更改并立即合并到你的本地分支,继续阅读以获取更多关于每个命令的详细信息:

git fetch

它会下载所有的引用对象以及任何新的分支到你的本地仓库...

从一个或多个其他存储库中获取分支和/或标签(统称为“refs”),以及完成其历史记录所需的对象。远程跟踪分支会被更新(有关控制此行为的方法,请参阅下面的描述)。
默认情况下,任何指向被获取历史记录的标签也会被获取;效果是获取指向您感兴趣的分支的标签。可以通过使用--tags或--no-tags选项或配置remote..tagOpt来更改此默认行为。通过使用显式获取标签的refspec,您还可以获取不指向您感兴趣的分支的标签。
如果给出了,git fetch可以从单个命名存储库或URL中获取,也可以一次从多个存储库中获取,如果配置文件中有remotes.条目(请参阅git-config1)。
当未指定远程时,默认情况下将使用origin远程,除非为当前分支配置了上游分支。
被获取的ref的名称以及它们指向的对象的名称将写入.git/FETCH_HEAD。此信息可供脚本或其他git命令(如git-pull)使用。

git pull

它将把来自远程的更改应用到本地的当前分支上...

将远程仓库的更改合并到当前分支中。 在默认模式下,git pull是git fetch后跟git merge FETCH_HEAD的简写。

更准确地说,git pull使用给定的参数运行git fetch,并调用git merge将检索到的分支头合并到当前分支。使用--rebase选项时,它会运行git rebase而不是git merge。

应该是一个远程仓库的名称,如传递给git-fetch1。可以使用来命名任意远程引用(例如标签的名称)或者一组具有相应远程跟踪分支的引用(例如refs/heads/:refs/remotes/origin/),但通常它是远程仓库中的一个分支的名称。

对于的默认值是从当前分支的"remote"和"merge"配置中读取的,这些配置由git-branch --track设置。


我还创建了下面的可视化内容,以展示给你看git fetchgit pull如何一起工作...

git pull and git fetch


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