git pull 和 git fetch的区别?

我的理解是git pull是下拉所有的branch git fetch是下拉远程仓库中所有的数据,但是所有的数据其实都是在branch是的啊
关注者
182
被浏览
1,228,958

20 个回答

虽然是已经过去很久的问题,但是觉得可以再来回答一下。

pull 根据不同的配置,可等于 fetch + merge 或 fetch + rebase。具体了解可继续读下去。

要理解它们的区别,首先我们需要明白的git的架构,它是分布式的版本管理系统。我画了张图,不仅仅涉及到git fetch和git pull,对整体理解也会很有帮助。如下:

上图展示了git的整体架构,以及和各部分相关的主要命令。先说明下其中涉及的各部分。

工作区(working directory),简言之就是你工作的区域。对于git而言,就是的本地工作目录。工作区的内容会包含提交到暂存区和版本库(当前提交点)的内容,同时也包含自己的修改内容。

暂存区(stage area, 又称为索引区index),是git中一个非常重要的概念。是我们把修改提交版本库前的一个过渡阶段。查看GIT自带帮助手册的时候,通常以index来表示暂存区。在工作目录下有一个.git的目录,里面有个index文件,存储着关于暂存区的内容。git add命令将工作区内容添加到暂存区。

本地仓库(local repository),版本控制系统的仓库,存在于本地。当执行git commit命令后,会将暂存区内容提交到仓库之中。在工作区下面有.git的目录,这个目录下的内容不属于工作区,里面便是仓库的数据信息,暂存区相关内容也在其中。这里也可以使用merge或rebase将远程仓库副本合并到本地仓库。图中的只有merge,注意这里也可以使用rebase。

远程版本库(remote repository),与本地仓库概念基本一致,不同之处在于一个存在远程,可用于远程协作,一个却是存在于本地。通过push/pull可实现本地与远程的交互;

远程仓库副本,可以理解为存在于本地的远程仓库缓存。如需更新,可通过git fetch/pull命令获取远程仓库内容。使用fech获取时,并未合并到本地仓库,此时可使用git merge实现远程仓库副本与本地仓库的合并。git pull 根据配置的不同,可为git fetch + git merge 或 git fetch + git rebase。rebase和merge的区别可以自己去网上找些资料了解下。

看到这里,不仅清楚了 git fetch 与 git pull。而且我们使用每个命令时,也能清楚的明白此时git做了什么工作。

如果想了解更多,可以参考一篇文章:

Git是一款非常受欢迎,也非常强大的版本管理工具。

但是,它的工作流程相对于SVN等其他版本管理工作也复杂很多,对于刚接触的同学会有很多操作难以理解。

例如,当我们和其他同学进行协同开发时,我们每个人都从远程仓库拉取了一份代码到本地仓库,此时每个人电脑上的本地仓库和远程仓库都是一致的。

但是,随着开发的不断推进,如果其他同事事先已经把修改的代码推送到远程仓库,当我们后面再push时就会发生冲突。

这时候,就需要先把远程代码的最新版本重新拉取一下到本地仓库,这时候,就会用到git pullgit fetch

在这个过程中,很多同学就有点分不清了,都是拉取远程仓库的代码到本地仓库,它们的区别是什么呢?

要想理解它们的工作愿意,首先要对Git仓库有一个清晰的认识。

在我们开发过程中,代码仓库至少会有3个仓库/副本:

  • 本地工作目录:也就是我们开发过程中正在编辑的工作目录
  • 本地仓库:这一点是很多初学者容易忽略和搞混的,由于git是分布式的,所以每个开发者本地都会有一个本地仓库,当我们通过git commit提交代码时,更改就从本地工作目录提交到了本地仓库
  • 远程仓库:这个应该大多数同学都很清楚,顾名思义,就是在远程服务器上存储的仓库,例如Github、Gitlab,当我们使用git push推送代码时,代码就从本地仓库推到了远程仓库

在很多刚接触Git的同学意识里,容易理解本地工作目录和远程目录,认为执行commitpush就是直接从本地工作目录推到了远程仓库,容易忽略本地仓库。

现在,理解了Git的工作流,接下来再解释git pullgit fetch的区别就简单多了。

就如同前面提到的,很多同事协同开发过程中并不是同步的。例如,AB两位开发者都从远程仓库拉了一份最新数据到本地仓库,A修改了代码之后先推送到远程仓库了,这时候B的本地仓库代码和远程仓库的就不一样了。如果这时候直接push就会引起冲突。

所以,协同开发过程中,在推送代码之前,首先需要先检查一下本地仓库与远程仓库的差异,然后把最新的代码拉到本地,然后再提交、推送。

这时候就会用到git pullgit fetch,它们在完成相同的工作,只是处理方式不同。

git fetch

在拉取代码过程中,git fetch会首先检查本地仓库和远程仓库的差异,检查哪些不存在于本地仓库,然后将这些变动的提交拉取到本地。

但是,这里请注意,它是把远程提交拉取到本地仓库,而不是本地工作目录,它不会自行将这些新数据合并到当前工作目录中,我们需要继续执行git merge才会把这些变动合并到当前工作目录。

git pull

git pullgit fetch刚好相反,它直接获取远程的最新提交,直接拉取并合并到本地工作目录,而且在合并过程中不会经过我们的审查,如果不仔细检查,这样很容易遇到冲突。

理解了git pullgit fetch的区别,那么该用哪种方式呢?

相比之下,git fetch是一个更安全的选择,因为它从你的远程仓库拉入所有的提交,但不会对你的本地文件做任何修改。

这给了你足够时间去发现远程仓库自从你上次拉取后到现在为止发生的变化。

你可以在合并前检查哪些文件有变化,哪些文件可能导致冲突。

git pull相当于运行git fetch,然后立即将你的改动合并到本地仓库。

这样的确少了一个步骤,但是也会带来一些风险。

作为一名开发者,在项目开发过程中很难绕开git,只有深入理解git的工作原理才能在工作中更加自如的应用Git完成项目协同开发,如果一直处于一知半解的状态,在版本控制中经常会遇到各种各样的问题。

我写了一篇关于Git和Github的入门回答,循序渐进,比较详细,感兴趣的同学可以看一下:

另外,在实践中我们可以得到更多的锻炼,也可以加深对于Git的理解。我建议大家可以多参与Github上开源代码的协同开发,这样不仅可以锻炼对于Git的理解,还有很多额外的好处。

如果还不知道如何加入Github开源项目,可以参考我之前写的一篇内容:

建议大家有空可以多浏览Github,有很多非常优秀的开源项目。但是,目前Github上项目多如牛毛,而且刷榜现在也非常严重,想要找到优质的项目变得越来越难。这里,给大家推荐Github上一个非常不错的项目《DevWeekly》,这个项目每周都会精挑细选一些优质的开源项目,涵盖C++、JAVA、JavaScript、Python、Go等不同编程语言。此外,还有一些开源工具、优秀的技术文章,喜欢的同学可以Star并收藏一下,每周五会定期更新: