当前位置:   article > 正文

git fetch、git rebase和merge区别

rebase

一、概述

merge和rebase

标题上的两个命令:merge和rebase都是用来合并分支的。

这里不解释rebase命令,以及两个命令的原理,详细解释参考这里

下面的内容主要说的是两者在实际操作中的区别。

1.1 什么是分支

分支就是便于多人在同一项目中的协作开发。比方说:每个人开发不同的功能,在各自的分支开发过程中互不影响,完成后都提交到develop分支。极大的提高了开发的效率。

1.2 合并分支

每个人创建一个分支进行开发,当开发完成,需要合并到develop分支的时候,就需要用到合并的命令。

1.3 什么是冲突

合并的时候,有可能会产生冲突。

冲突的产生是因为在合并的时候,不同分支修改了相同的位置。所以在合并的时候git不知道哪个到底是你想保留的,所以就提出疑问(冲突提醒)让你自己手动选择想要保留的内容,从而解决冲突。

二、merge和rebase的区别

fetch命令:

  1. git fetch <远程主机名> #这个命令将某个远程主机的更新全部取回本地
  2. git fetch <远程主机名> <分支名> #如果只想取回特定分支的更新,可以指定分支名
  3. git fetch origin master #最常见的命令如取回origin 主机的master 分支

取回更新后,会返回一个FETCH_HEAD ,指的是某个branch在服务器上的最新状态,我们可以在本地通过它查看刚取回的更新信息:
git log -p FETCH_HEAD 

可以看到返回的信息包括更新的文件名,更新的作者和时间,以及更新的代码(19行红色[删除]和绿色[新增]部分)。

我们可以通过这些信息来判断是否产生冲突,以确定是否将更新merge到当前分支。

 merge命令: 

  1. git merge <branch> #将branch分支合并到当前分支
  2. git merge origin/master #将远程分支合并到当前分支
  3. 这两个命令可以加上--no-ff 表示 不要Fast-Foward合并,这样可以生成merge提交,然后需要再加上-m参数,表示对提交的说明

pull命令: 

  1. 格式:git pull <远程主机名> <远程分支名>:<本地分支名>
  2. git pull origin master:master 将远程库origin的master分支的更新下载并与master分支合并
  3. git pull origin master 将远程库origin的master分支的更新下载并与当前分支合并(相当于 git fetch origin master + git merge origin/master)
  4. git pull origin 将远程库origin与当前分支存在追踪关系的分支的更新下载并合并到当前分支
  5. git pull 如果当前分支只有一个追踪关系,就将对于远程分支的更新下载并合并到当前分支中
git rebase branchName

2.1 区别

  1. 采用merge和rebase后,git log的区别,merge命令不会保留分支的commit,rebase会保留所有的commit

    rebase 会把你当前分支的 commit 放到公共分支的最后面,所以叫变基。就好像你从公共分支又重新拉出来这个分支一样。
    举例:如果你从 master 拉了个feature分支出来,然后你提交了几个 commit,这个时候刚好有人把他开发的东西合并到 master 了,这个时候 master 就比你拉分支的时候多了几个 commit,如果这个时候你 rebase master 的话,就会把你当前的几个 commit,放到那个人 commit 的后面。

    merge 会把公共分支和你当前的commit 合并在一起,形成一个新的 commit 提交

  2. 处理冲突的方式:

    • (一股脑)使用 git merge branchName 命令合并分支,解决完冲突,执行git add .git commit -m 'fix conflict'。这个时候会产生一个commit
    • (交互式)使用 git rebase branchName 命令合并分支,解决完冲突,执行git add .git rebase --continue不会产生额外的commit。这样的好处是,‘干净’,分支上不会有无意义的解决分支的commit;坏处,如果合并的分支中存在多个commit,需要重复处理多次冲突。
  3. git pullgit pull --rebase区别:git pull做了两个操作分别是‘获取’和合并。所以加了rebase就是以rebase的方式进行合并分支得到一条干净的分支流。

 git pull = git fetch origin branchName+ git merge branchName
 git pull --rebase =  git fetch origin branchName+ git rebase branchName

git rebase --continue; 让 rebase 过程继续执行。
git rebase --abort; 发生代码冲突后,放弃合并,回到操作前的样子。

2.2 git mergegit merge --no-ff的区别

1、我自己尝试merge命令后,发现:merge 时并没有产生一个commit。不是说merge时会产生一个merge commit吗?

注意:只有在冲突的时候,解决完冲突才会自动产生一个commit。

如果想在没有冲突的情况下也自动生成一个commit,记录此次合并就可以用:git merge --no-ff命令,下面用一张图来表示两者的区别:

2、如果不加 --no-ff 则被合并的分支之前的commit都会被抹去,只会保留一个解决冲突后的 merge commit。

三、如何选择合并分支的方式

我的理解:主要是看哪个命令用的熟练,能够有效的管理自己的代码;还有就是团队用的是哪种方式。

我对于rebase比较熟悉,所以我一般都用rebase,但是现在的公司用的是merge --no-ff命令合并分支。所以,我在工作上就用merge,个人项目就用rebase。

也可以两者结合:

  • 获取远程项目中最新代码时:git pull --rebase,这个时隐性的合并远程分支的代码不会产生而外的commit(但是如果存在冲突的commit太多就像上面说的,需要处理很多遍冲突)。

  • 合并到分支的时候:git merge --no-ff,自动一个merge commit,便于管理(这看管理人员怎么认为了)

注意:

  • 不要在公共分支使用rebase
  • 本地和远端对应同一条分支,优先使用rebase,而不是merge

抛出问题:

为什么不要再公共分支使用rebase?
因为往后放的这些 commit 都是新的,这样其他从这个公共分支拉出去的人,都需要再 rebase,相当于你 rebase 东西进来,就都是新的 commit 了

  • 1-2-3 是现在的分支状态
  • 这个时候从原来的master ,checkout出来一个prod分支
  • 然后master提交了4.5,prod提交了6.7
  • 这个时候master分支状态就是1-2-3-4-5,prod状态变成1-2-3-6-7
  • 如果在prod上用rebase master ,prod分支状态就成了1-2-3-4-5-6-7
  • 如果是merge
    1-2-3-6-7-8
    ........ |4-5|
  • 会出来一个8,这个8的提交就是把4-5合进来的提交

merge和rebase实际上只是用的场景不一样
更通俗的解释一波.
比如rebase,你自己开发分支一直在做,然后某一天,你想把主线的修改合到你的分支上,做一次集成,这种情况就用rebase比较好.把你的提交都放在主线修改的头上
如果用merge,脑袋上顶着一笔merge的8,你如果想回退你分支上的某个提交就很麻烦,还有一个重要的问题,rebase的话,本来我的分支是从3拉出来的,rebase完了之后,就不知道我当时是从哪儿拉出来的我的开发分支
同样的,如果你在主分支上用rebase, rebase其他分支的修改,是不是要是别人想看主分支上有什么历史,他看到的就不是完整的历史课,这个历史已经被你篡改了

常用指令

  • git rebase -i dev 可以将dev分支合并到当前分支
    这里的”-i“是指交互模式。就是说你可以干预rebase这个事务的过程,包括设置commit message,暂停commit等等。

  • git rebase --continue   让 rebase 过程继续执行

  • git rebase --abort   放弃一次合并

  • 合并多次commit操作:
    1 git rebase -i dev
    2 修改最后几次commit记录中的pick 为squash
    3 保存退出,弹出修改文件,修改commit记录再次保存退出(删除多余的change-id 只保留一个)
    4 git add .
    5 git rebase --continue
    6 git push origin 开发分支

案例:

1.合并当前分支的多个commit记录

$ git log --pretty=format:'%h: %s'
2eeb74a: modify c
5d340c4: modify b
e51aaca: modify b
16aee3f: modify b
58c8fed: modify a
f6f3452: Initial commit

其实,中间的对 b 的 3 次提交完全可以合并成一次 commit,这个时候 rebase 就很有用了。

2.找到想要合并的commit然后使用rebase -i

 这里的合并的 commit 是待合并的多个 commit 之前的那个 commit,这里也就是最下面那个 modify a 的commit。

$ git rebase -i 58c8fed

注意:git rebase -i startPonit endPoint

前开后闭区间,这里的 startPonit 是指需要合并的 commit 的前一个 commit (即当前示例中的 58c8fed ),因为三个 commit 肯定要基于上一个 commit 合并成了新的 commit。

谨慎使用 endPoint,该参数省略即默认表示从起始 commit 一直到最后一个,但是一旦你填写了,则表示endPoint 后面的commit全部不要了。

3.进入Interact交互界面 

 终端会进入选择交互界面,让你进行变基选择操作。

最上面三行,就是刚刚选中的三个 commit,按时间顺序依次往下排序。

前面的三个 Pick 其实就是下面 Commands 展示的 7 种命令中的第一个 p,也就是 use commit。

4.使用s命令合并到上一个commit

按 i 进入操作,将第 2 和 第 3 个 commit 的 pick 改成 s,按 Esc 退出操作,输入 :wq 保存并退出。

5.修改commit记录

接下来会弹出第二个页面,分别展示 3 个commit的提交信息。

 这里三个信息都是一样的,我们选用第一个的提交信息,将其余的全部注释掉,重复上述步骤,保存退出即可。

# 执行结果
$ git rebase -i 58c8fed
[detached HEAD 792e41c] modify b
 Date: Tue Mar 14 12:28:51 2023 +0800
 1 file changed, 1 insertion(+)
Successfully rebased and updated refs/heads/master.

6.查看最新合并情况

$ git log --pretty=format:'%h: %s'
e6c4bbd: modify c
792e41c: modify b
58c8fed: modify a
f6f3452: Initial commit

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/971138
推荐阅读
相关标签
  

闽ICP备14008679号