参考:
https://blog.csdn.net/liuxiaoheng1992/article/details/79108233
https://www.cnblogs.com/rainboy2010/p/12671633.html
https://www.cnblogs.com/marblemm/p/7161614.html
https://segmentfault.com/a/1190000018580144?utm_source=tag-newest
https://www.jianshu.com/p/4079284dd970
https://www.cnblogs.com/runnerjack/p/9342362.html
git merge 与 git rebase的区别
git fetch & pull详解
git merge 与 git rebase的区别
前言
其实这个问题困扰我有一段时间,相信也有人和我一样有这个困扰,网上已有很多这种解释了,但是要么就是无图,要么就是解释的很乱,没太看懂,经过自己对git的使用,加上向同事请教,算是理解了这个问题,所以写下来分享一下,我尽量详细说明
merge与rebase的区别
假设我们有如下图一所示仓库,该仓库有master和develop两个分支,且develop是在(3.added merge.txt file)commit处从master拉出来的分支。
merge
假设现在HEAD在(6.added hello.txt file)处,也就是在master分支最近的一次提交处,此时执行git merge develop, 结果如下图所示。
工作原理就是:git 会自动根据两个分支的共同祖先即 (3.added merge.txt file)这个 commit 和两个分支的最新提交即 (6.added hello.txt file) 和 (5.added test.txt file) 进行一个三方合并,然后将合并中修改的内容生成一个新的 commit,即图二的(7.Merge branch ‘develop’)。
这是merge的效果,简单来说就合并两个分支并生成一个新的提交。
rebase
那rebase是这么工作的呢?
假设初始状态也是图一所显示的。两个分支一个master,一个develop,此时HEAD在(6.added hello.txt file)处,现在执行git rebase develop,结果如下图三所示。
可以看见develop分支分出来分叉不见了,下面来解释一下它的工作原理:
在执行git rebase develop之前,HEAD在(6.added hello.txt file)处,当执行rebase操作时,git 会从两个分支的共同祖先 (3.added merge.txt file)开始提取 当前分支(此时是master分支)上的修改,即 (6.added hello.txt file)这个commit,再将 master 分支指向 目标分支的最新提交(此时是develop分支)即(5.added test.txt file) 处,然后将刚刚提取的修改应用到这个最新提交后面。如果提取的修改有多个,那git将依次应用到最新的提交后面,如下两图所示,图四为初始状态,图五为执行rebase后的状态。
简单来说,git rebase提取操作有点像git cherry-pick一样,执行rebase后依次将当前的提交cherry-pick到目标分支上,然后将在原始分支上的已提交的commit删除。
注:图中6没有的原因:因为5和6不小心搞成一样的修改了,然后它就合并了
merge OR rebase
那什么时候用merge,什么时候用rebase呢?
再举个例子:
初始状态如下图六所示:
和之前一样的是,develop分支也是在 (3.added merge.txt file)处从master分支拉取develop分支。不一样的是两个分支各个commit的时间不同,之前develop分支的4和5commit在master分支3之后6之前,现在是develop分支的4提交早于master分支的5提交,develop分支的6提交晚于master的5提交早于master的7提交。
在上图情况下,在master分支的7commit处,执行git merge develop,结果如下图七所示:
执行git rebase develop,结果如下图八所示:
- 可以看出merge结果能够体现出时间线,但是rebase会打乱时间线。
- 而rebase看起来简洁,但是merge看起来不太简洁。
- 最终结果是都把代码合起来了,所以具体怎么使用这两个命令看项目需要。
还有一点说明的是,在项目中经常使用git pull来拉取代码,git pull相当于是git fetch + git merge,如果此时运行git pull -r,也就是git pull --rebase,相当于git fetch + git rebase
最后推荐一些git可视化工具,我用的是gitkraken,这些工具功能基本一样,看个人喜欢好使用
git merge和git rebase的区别
在分支合并时,有两种方式:git merge 和git rebase
举个例子,当前有一个master分支,日志信息如下:
现在在master分支上创建一个dev分支,然后在dev分支上进行两次提交,添加dev1.txt,dev2.txt,日志信息如下:
同时在master分支上进行两次提交,添加master1.txt,master2.txt,日志信息如下:
现在要把dev分支合并到master分支
使用merge命令合并:git merge dev
使用rebase命令合并:git rebase dev
Git 会从两个分支的共同祖先8eda20d开始提取 master 分支(当前所在分支)上的修改,即 e0779e1、ae0decb,再将 master 分支指向 dev的最新提交(目标分支)即 e45d38f处,然后将刚刚提取的修改依次应用到这个最新提交后面。操作会舍弃 master 分支上提取的 commit,同时不会像 merge 一样生成一个合并修改内容的 commit,相当于把 master 分支(当前所在分支)上的修改在 dev分支(目标分支)上原样复制了一遍
总结
-
merge 是一个合并操作,会将两个分支的修改合并在一起
-
merge 的提交历史忠实地记录了实际发生过什么,关注点在真实的提交历史上面
-
rebase 并没有进行合并操作,只是提取了当前分支的修改,将其复制在了目标分支的最新提交后面
Git中分支merge和rebase的适用场景及区别
Git merge是用来合并两个分支的。
git merge b # 将b分支合并到当前分支同样 git rebase b,也是把 b分支合并到当前分支
原理 如下:
假设你现在基于远程分支"origin",创建一个叫"mywork"的分支。 $ git checkout -b mywork origin 假设远程分支"origin"已经有了2个提交,如图 现在我们在这个分支做一些修改,然后生成两个提交(commit). $ vi file.txt $ git commit $ vi otherfile.txt $ git commit ... 但是与此同时,有些人也在"origin"分支上做了一些修改并且做了提交了. 这就意味着"origin"和"mywork"这两个分支各自"前进"了,它们之间"分叉"了。 在这里,你可以用"pull"命令把"origin"分支上的修改拉下来并且和你的修改合并; 结果看起来就像一个新的"合并的提交"(merge commit): 但是,如果你想让"mywork"分支历史看起来像没有经过任何合并一样,你也许可以用 git rebase: $ git checkout mywork $ git rebase origin 这些命令会把你的"mywork"分支里的每个提交(commit)取消掉,并且把它们临时 保存为补丁(patch)(这些补丁放到".git/rebase"目录中),然后把"mywork"分支更新 为最新的"origin"分支,最后把保存的这些补丁应用到"mywork"分支上。 当'mywork'分支更新之后,它会指向这些新创建的提交(commit),而那些老的提交会被丢弃。 如果运行垃圾收集命令(pruning garbage collection), 这些被丢弃的提交就会删除. (请查看 git gc) 二、解决冲突 在rebase的过程中,也许会出现冲突(conflict). 在这种情况,Git会停止rebase并会让你去解决 冲突;在解决完冲突后,用"git-add"命令去更新这些内容的索引(index), 然后,你无需执行 git-commit,只要执行: $ git rebase --continue 这样git会继续应用(apply)余下的补丁。 在任何时候,你可以用--abort参数来终止rebase的行动,并且"mywork" 分支会回到rebase开始前的状态。 $ git rebase --abort 三、git rebase和git merge的区别 现在我们可以看一下用合并(merge)和用rebase所产生的历史的区别: 当我们使用Git log来参看commit时,其commit的顺序也有所不同。 假设C3提交于9:00AM,C5提交于10:00AM,C4提交于11:00AM,C6提交于12:00AM, 对于使用git merge来合并所看到的commit的顺序(从新到旧)是:C7 ,C6,C4,C5,C3,C2,C1 对于使用git rebase来合并所看到的commit的顺序(从新到旧)是:C7 ,C6‘,C5',C4,C3,C2,C1 因为C6'提交只是C6提交的克隆,C5'提交只是C5提交的克隆, 从用户的角度看使用git rebase来合并后所看到的commit的顺序(从新到旧)是:C7 ,C6,C5,C4,C3,C2,C1
知乎用户回答https://www.zhihu.com/question/36509119/answer/67828312
两个使用场景是不一样的,merge只是合并另外一个分支的内容,rebase也合并另外一个分支的内容,但是会把本分支的commits顶到最顶端
假设我们现在有3个分支- master分支:线上环境使用的分支
- testing分支:测试环境使用的分支
- my_feature分支:开发新功能的分支,也就是当前分支
A. 假设我在my_feature上开发了一段时间,之后另外的同事开发的功能正式上线到master分支了,那么我可以在当前的分支下rebase一下master分支,这样我这个分支的几个commits相对于master还是处于最顶端的,也就是说rebase主要用来跟上游同步,同时把自己的修改顶到最上面
B. 我在my_feature上开发了一段时间了,想要放到testing分支上,那就切到testing,然后merge my_feature进来,因为是个测试分支,commits的顺序无所谓,也就没必要用rebase (当然你也可以用rebase)
另外,单独使用rebase,还有调整当前分支上commits的功能(合并,丢弃,修改commites msg)
PS:
其他知友的答案都说到冲突的问题,
1. 用merge确实只需要解决一遍冲突,比较简单粗暴
2. 用rebase有时候会需要多次fix冲突(原因在于本地分支已经提交了非常多的commit,而且很久都没有和上游合并过)
git rebase 与 git merge 的区别
前言
初学git,在合并分支上必定会常用到 git merge 语法。今日接触到 git rebase,发现二者都有用于分支合并的功能,那接下来让我们探究一下二者的不同之处。
开门见山:二者的区别
主要区别在于git log上:是否保留分支的commit提交节点 。
其次细讲:详情分析
前提:
- 在一个git项目中我先创建并保存了两个文档:1.txt 和 2.txt 记作“1” 和 “2”;
- 创建分支branch1;
- 继续在主分支Master上创建并保存两个文档:3.txt 和 4.txt 记作“3” 和 “4”;
- 转到branch1分支上创建 5.txt 和 6.txt 记作“5” 和 “6”;
此时,我们的主分支Master上有1、2、3、4 四个文档,branch1分支上则是1、2、5、6 四个文档,接下来执行我们的合并操作。
- git merge:
我们直接回到主分支Master上执行 git merge 命令,显示如下:
此时我们的 git log 上保留了分支branch1的 5 和 6 的commit提交,且又在主分支Master上自动创建了一个新的commit提交节点 “7”。
简单而言就是Master的1、2、3、4和合并的branch1的5、6的提交历史节点都被记录下来了,且自动在Master上自动生成第7个节点:
- git rebase:
我们在分支branch1上执行 git rebase 命令:
会发现branch1合并了 Master 的 3、4 文档,所以现在branch1 就有了1、2、3、4、5、6所有文档,回到Master再合并一下:
这时我们的 git log 上就得到一个简洁的项目历史,且未生成新的 merge commit(保留了分支上的提交信息成功与Master合并,但删去了提交历史记录):
- 自我猜想:
学完rebase,我即刻猜想,若是在分支baranch1上直接merge合并主分支,得到所有文档后再回到主分支上执行merge会不会也能得到一条线,事实证明,这么想说明还是没有完全理解rebase的真正含义,先看结果吧...
rebase 到底是什么?
rebase就是——变基, 变基, 变基 。
即:改变一条分支的 基点 ,使原分支从指定的节点(commit)延续。。
通俗点讲,变基操作其实就是保留了该 commit 作出的修改,但删丢弃了分支上一些现有的提交记录,删去了这些节点。
最后结论:二者比较
比较 | merge | rebase |
---|---|---|
优点 | 保留有价值的历史文档 | 删减就繁 |
缺点 | 分支杂乱冗余 | 无法体现时间线 |
所以,使用merge还是rebase还是得分情况考虑,具体项目具体分析:
- 如果项目庞大,需要一个简洁的线性历史树便于leader管理,推荐使用 git rebase 。
- 如果是小型项目,需要审查历史纪录来便于编写过程报告,则推荐使用 git merge 。
git rebase 还是 merge的使用场景最通俗的解释
什么是 rebase?
git rebase 你其实可以把它理解成是“重新设置基线”,将你的当前分支重新设置开始点。这个时候才能知道你当前分支于你需要比较的分支之间的差异。
原理很简单:rebase需要基于一个分支来设置你当前的分支的基线,这基线就是当前分支的开始时间轴向后移动到最新的跟踪分支的最后面,这样你的当前分支就是最新的跟踪分支。这里的操作是基于文件事务处理的,所以你不用怕中间失败会影响文件的一致性。在中间的过程中你可以随时取消rebase 事务。
官方解释: https://git-scm.com/book/zh/v2/Git-分支-变基
git rebase 和 git merge 有啥区别?
rebase会把你当前分支的 commit 放到公共分支的最后面,所以叫变基。就好像你从公共分支又重新拉出来这个分支一样。
举例:如果你从 master 拉了个feature分支出来,然后你提交了几个 commit,这个时候刚好有人把他开发的东西合并到 master 了,这个时候 master 就比你拉分支的时候多了几个 commit,如果这个时候你 rebase master 的话,就会把你当前的几个 commit,放到那个人 commit 的后面。
merge 会把公共分支和你当前的commit 合并在一起,形成一个新的 commit 提交
merge
注意:
- 不要在公共分支使用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 –abort 放弃一次合并
-
合并多次commit操作:
1 git rebase -i dev
2 修改最后几次commit记录中的pick 为squash
3 保存退出,弹出修改文件,修改commit记录再次保存退出(删除多余的change-id 只保留一个)
4 git add .
5 git rebase --continue
作者:曹九朵_
链接:https://www.jianshu.com/p/4079284dd970
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
git fetch & pull详解
1、简单概括
先用一张图来理一下git fetch
和git pull
的概念:
可以简单的概括为:
git fetch
是将远程主机的最新内容拉到本地,用户在检查了以后决定是否合并到工作本机分支中。
而git pull
则是将远程主机的最新内容拉下来后直接合并,即:git pull = git fetch + git merge
,这样可能会产生冲突,需要手动解决。
下面我们来详细了解一下git fetch
和git pull
的用法。
2、分支的概念
在介绍两种方法之前,我们需要先了解一下分支的概念:
分支是用来标记特定代码的提交,每一个分支通过SHA1sum值来标识,所以对分支的操作是轻量级的,你改变的仅仅是SHA1sum值。
如下图所示,当前有2个分支,A,C,E属于master分支,而A,B,D,F属于dev分支。
A----C----E(master)
\
B---D---F(dev)
它们的head指针分别指向E和F,对上述做如下操作:
git checkout master //选择or切换到master分支
git merge dev //将dev分支合并到当前分支(master)中
合并完成后:
A---C---E---G(master)
\ /
B---D---F(dev)
现在ABCDEFG属于master,G是一次合并后的结果,是将E和F的代码合并后的结果,可能会出现冲突。而ABDF依然属于dev分支。可以继续在dev的分支上进行开发:
A---C---E---G---H(master)
\ /
B---D---F---I(dev)
分支(branch)的基本操作:
git branch //查看本地所有分支
git branch -r //查看远程所有分支
git branch -a //查看本地和远程的所有分支
git branch <branchname> //新建分支
git branch -d <branchname> //删除本地分支
git branch -d -r <branchname> //删除远程分支,删除后还需推送到服务器
git push origin:<branchname> //删除后推送至服务器
git branch -m <oldbranch> <newbranch> //重命名本地分支
/**
*重命名远程分支:
*1、删除远程待修改分支
*2、push本地新分支到远程服务器
*/
//git中一些选项解释:
-d
--delete:删除
-D
--delete --force的快捷键
-f
--force:强制
-m
--move:移动或重命名
-M
--move --force的快捷键
-r
--remote:远程
-a
--all:所有
3、git fetch 用法
git fetch 命令:
$ git fetch <远程主机名> //这个命令将某个远程主机的更新全部取回本地
如果只想取回特定分支的更新,可以指定分支名:
$ git fetch <远程主机名> <分支名> //注意之间有空格
最常见的命令如取回origin
主机的master
分支:
$ git fetch origin master
取回更新后,会返回一个FETCH_HEAD
,指的是某个branch在服务器上的最新状态,我们可以在本地通过它查看刚取回的更新信息:
$ git log -p FETCH_HEAD
如图:
可以看到返回的信息包括更新的文件名,更新的作者和时间,以及更新的代码(19行红色[删除]和绿色[新增]部分)。
我们可以通过这些信息来判断是否产生冲突,以确定是否将更新merge到当前分支。
4、git pull 用法
前面提到,git pull
的过程可以理解为:
git fetch origin master //从远程主机的master分支拉取最新内容
git merge FETCH_HEAD //将拉取下来的最新内容合并到当前所在的分支中
即将远程主机的某个分支的更新取回,并与本地指定的分支合并,完整格式可表示为:
$ git pull <远程主机名> <远程分支名>:<本地分支名>
如果远程分支是与当前分支合并,则冒号后面的部分可以省略:
$ git pull origin next
标签:GIT,merge,rebase,常见,命令,git,master,commit,分支
From: https://www.cnblogs.com/kn-zheng/p/17056010.html