原文地址:https://www.cpweb.top/455

一、概念介绍

  简单来说git fetch命令用于将远程仓库的最新内容拉到本地,用户在检查了以后决定是否合并到本地分支中。
  但是我们要搞清楚,fetch操作并不会更新你本地仓库的代码。我的理解也有点模糊,这么说,可以理解为本地保存有两个分支,一个是本地分支,就是工作的那个master;另一个则是本地远程分支,fetch拉取的内容就保存在这里。
  要想更新本地代码为远程仓库最新内容,我们要进行fetch获取最新内容保存到本地远程分支,然后merge操作将本地远程分支内容合并到本地master分支中完成更新。
  而git pull 则是将远程主机的最新内容拉下来后直接合并,即:git pull = git fetch + git merge,这个命令简单粗暴下面就不着重讲解了,我们重点是fetch+merge这种更新本地代码的方法。

二、图解+实例演示理解远程分支和本地分支概念

  假设我们在gitee上有一个名为test的仓库。直接克隆到本地,Git 的 clone 命令会自动将仓库地址命名为 origin,拉取它的所有数据,创建一个指向它的 master 分支的指针,并且在本地将其命名为 origin/master(本地远程分支)。 Git 也会给你一个与 origin 的 master 分支在指向同一个地方的本地 master 分支,这样你就有工作的基础。

[root@git ~]# git clone git@gitee.com:cui-peng/test.git
[root@git ~]# cd test && ll
total 4
-rw-r--r--. 1 root root 5 Jun 19 04:39 index.html
[root@git test]# cat index.html 
test
[root@git test]# git branch -av                         //查看分支和远程分支
* master                8d8e222 create test file
  remotes/origin/HEAD   -> origin/master
  remotes/origin/master 8d8e222 create test file

   值得一提的是,如果你在本地的 master 分支做了一些工作,在同一段时间内有其他人更新了远程test仓库,只要你不使用git fetch命令拉取远程仓库内容,你的 origin/master 指针就不会移动,本地远程分支还是8d8e222版本,而master则是fff222版本了。

  假设此时有其他人更新了test仓库内容,那么本地如何更新。首先我们需要使用git fetch命令同步远程仓库内容到本地远程远程分支。同步之后此时已经产生分叉了,本地远程分支origin/master是一个版本,本地工作分支master是一个版本,但是本地远程分支并不会影响本地分支代码,所以此时本地代码不变,所以本地电脑的8d8e222版本和a7651d7版本不在一条线上。

[root@git test]# git fetch origin                               //同步远程仓库数据
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From gitee.com:cui-peng/test
   8d8e222..a7651d7  master     -> origin/master                //可以看到内容保存到了本地远程分支
[root@git test]# cat index.html                         //此时我们看下本地代码是否有所改变
test
[root@git test]# git branch -av                         //我们可以看到本地远程分支内容已经发生了改变
* master                8d8e222 [behind 1] create test file
  remotes/origin/HEAD   -> origin/master
  remotes/origin/master a7651d7 first test
[root@git test]# git diff origin                        //对比变化
diff --git a/index.html b/index.html
index 7cc6cd7..9daeafb 100644
--- a/index.html
+++ b/index.html
@@ -1,2 +1 @@
 test
-test-first
\ No newline at end of file

要想更新本地还要进行merge操作

[root@git test]# git merge origin/master                        //将本地远程分支合并到本地分支
Updating 8d8e222..a7651d7
Fast-forward
 index.html | 1 +
 1 file changed, 1 insertion(+)
[root@git test]# cat index.html                                 //此时可以看到本地代码已经更新了
test
test-first
[root@git test]# git branch -av                                 //可以看到两个分支位于同一版本了
* master                a7651d7 first test
  remotes/origin/HEAD   -> origin/master
  remotes/origin/master a7651d7 first test

三、问题

当我们使用fetch命令拉取指定分支的更新时,会出现下面问题。

[root@git test]# git fetch origin master
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From gitee.com:cui-peng/test
 * branch            master     -> FETCH_HEAD

            //这里我们发现没有将拉取的内容保存到本地远程分支中,而是返回一个FETCH_HEAD。

[root@git test]# git branch -av
* master                a7651d7 first test
  remotes/origin/HEAD   -> origin/master
  remotes/origin/master a7651d7 first test

            //查看一下,发现确实没有发生变化,那么此时我们像上面实例样按流程进行merge操作时,会有什么结果呢。

[root@git test]# git merge origin/master            //提示已经是最新的了
Already up-to-date.
[root@git test]# cat index.html                     //查看文件发现代码并没有变化
test
test-first
[root@git test]# git branch -av
* master                a7651d7 first test
  remotes/origin/HEAD   -> origin/master
  remotes/origin/master a7651d7 first test

  如何解决,首先我们要理解什么是FETCH_HEAD,它指某个branch在服务器上的最新状态,我们可以在本地通过它查看刚取回的更新信息。

[root@git test]# git log -p FETCH_HEAD
commit 9ec46677574c93ccfc8b6ae535b6dfc6615e6938
Author: 崔* <**_work@163.com>
Date:   Fri Jun 19 17:59:08 2020 +0800

    second test

diff --git a/index.html b/index.html
index 7cc6cd7..140d787 100644
--- a/index.html
+++ b/index.html
@@ -1,2 +1,3 @@
 test
-test-first
\ No newline at end of file
+test-first
+test-second
\ No newline at end of file
.........

既然如此,我们也可以通过它去更新本地代码

[root@git test]# git merge FETCH_HEAD             //将取回的最新内容合并到当前所在的分支中
Updating a7651d7..9ec4667
Fast-forward
 index.html | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
[root@git test]# cat index.html 
test
test-first
test-second
[root@git test]# git branch -av
* master                9ec4667 [ahead 1] second test
  remotes/origin/HEAD   -> origin/master
  remotes/origin/master a7651d7 first test

  上面更新本地代码的操作可以等价于pull,即:git pull origin master = git fetch origin master + git merge FETCH_HEAD

[root@git test]# git pull origin master
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From gitee.com:cui-peng/test
 * branch            master     -> FETCH_HEAD
Updating 9ec4667..feef2d0
Fast-forward
 index.html | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
[root@git test]# cat index.html 
test
test-first
test-second
test-third[root@g
[root@git test]# git branch -av
* master                feef2d0 [ahead 2] third test
  remotes/origin/HEAD   -> origin/master
  remotes/origin/master a7651d7 first test

四、其它

(1)拉取其它分支

[root@git test]# git fetch origin cc:cc
From gitee.com:cui-peng/test
 * [new branch]      cc         -> cc

  这个命令意思是从远程仓库拉取cc分支内容,如果本地不存在cc分支, 则会自动创建一个新的cc分支保存拉取的内容;如果本地存在cc分支, 并且是" fast forward ", 则自动合并两个分支, 否则, 会阻止以上操作。
  fast foward是什么意思呢?要知道提交到远程仓库的代码必须是按照一定的顺序来,即远程仓库的最新提交版本是本地分支的上一个版本。假设你从远程仓库获取到代码,对某某文件进行了修改,然后push到远程仓库。但是其他人在你之前就拿到了远程仓库的代码,在你push成功之后也对同样文件进行了修改,这个时候他也运行push命令推送代码。
  因为你们都是基于同一个版本开始工作的,此时会两种可能情况,一是他push时加上-f强制,则你提交的被覆盖成他的,你的提交丢失;二是他没加-f,则他的push失败。他想提交他则需要先从远程仓库获取最新的版本,此时会自动检测你本地代码和从远程仓库拉取的是否冲突,冲突则合并失败,反之成功。
  注意,fetch也是如此。

注意:git 1.8.4 (August 2013)版本之前,git fetch origin master确实不会在本地更新本地远程分支;
但在git 1.8.4版本之后,将会更新远程本地分支。详见:https://github.com/git/git/commit/f269048754f3b835f4f7287c5a132714a059efce
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐