写在前面

不管是merge,还是rebase都是将一个分支的修改合并到另一个分支,但是方式方法有所不同,下面我们具体来看下每种情况。

1:merge

merge就是合并代码,这种方式合并代码后,合并的结果会生成一个新的commit(效果同手动修改后的提交),而merge又有两种方式分别是fast-forward和,非fast-forward,分别来看下这两种方式。

1.1:fast-forward

当合并代码的时候,如果是没有冲突(更准确的表述应该是文件不需要合并时),git就会默认采用这种方式,接下来看下具体操作。

  • 基于master创建分支dev100
$ git checkout -b dev100
Switched to a new branch 'dev100'JHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev100)
$ git push origin dev100:dev100
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
remote: Powered by GITEE.COM [GNK-6.3]
remote: Create a pull request for 'dev100' on Gitee by visiting:
remote:     https://gitee.com/dongsir2020/test-cherry-pick/pull/new/dongsir2020:dev100...dongsir2020:master
To https://gitee.com/dongsir2020/test-cherry-pick.git* [new branch]      dev100 -> dev100JHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev100)
$ git branch --set-upstream-to=origin/dev100
Branch 'dev100' set up to track remote branch 'dev100' from 'origin'.JHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev100)
$ git branch -vvdev    1d2f221 dev first commitdev10  09ea18b [origin/dev10] dev second add content
* dev100 09ea18b [origin/dev100] dev second add contentmaster 09ea18b [origin/master] dev second add content

命令git branch --set-upstream-to=origin/dev100是用来关联本地的dev100到远程的dev100分支。

  • 在dev100分支执行若干次提交
JHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev100)
$ touch dev100.txtJHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev100)
$ git status
On branch dev100
Your branch is up to date with 'origin/dev100'.Untracked files:(use "git add <file>..." to include in what will be committed)dev100.txtnothing added to commit but untracked files present (use "git add" to track)JHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev100)
$ git add dev100.txtJHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev100)
$ git commit -am'add dev100.txt'
[dev100 cebe7f0] add dev100.txt1 file changed, 0 insertions(+), 0 deletions(-)create mode 100644 dev100.txtJHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev100)
$ vim dev100.txtJHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev100)
$ git commit -am'add some content in dev100.txt'
warning: LF will be replaced by CRLF in dev100.txt.
The file will have its original line endings in your working directory
[dev100 8adeee0] add some content in dev100.txt1 file changed, 1 insertion(+)JHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev100)
$ git status
On branch dev100
Your branch is ahead of 'origin/dev100' by 2 commits.(use "git push" to publish your local commits)nothing to commit, working tree cleanJHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev100)
$ git push origin dev100:dev100
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 12 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 459 bytes | 459.00 KiB/s, done.
Total 5 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Powered by GITEE.COM [GNK-6.3]
To https://gitee.com/dongsir2020/test-cherry-pick.git09ea18b..8adeee0  dev100 -> dev100

此时相比master新增的提交如下:

$ git log -n2 --pretty=oneline
8adeee00933d01888f128ced8193e728f99faf1f (HEAD -> dev100, origin/dev100) add some content in dev100.txt
cebe7f0df20707a6a55419a310671c5fb3fc1b95 add dev100.txt
  • 切换到master,并执行merge
$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.JHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (master)
$ git branchdevdev10dev100
* masterJHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (master)
$ git merge dev100
Updating 09ea18b..8adeee0
Fast-forwarddev100.txt | 1 +1 file changed, 1 insertion(+)create mode 100644 dev100.txt

通过输出Fast-forward就可以知道使用了fast forward方式,此时查看master的历史记录:

$ git log --pretty=oneline -n4 --graph
* 8adeee00933d01888f128ced8193e728f99faf1f (HEAD -> master, origin/dev100, dev100) add some content in dev100.txt
* cebe7f0df20707a6a55419a310671c5fb3fc1b95 add dev100.txt
* 09ea18b4302ede38ddc42e7051e14593c1862e9a (origin/master, origin/dev10, origin/HEAD, dev10) dev second add content
* 8497aa644b7c63d4c1d59b5cd9a1bf9dc19eb136 dev first commit

提交记录是有的,但是并不能体现出到底是从哪个分支合并过来的代码其实仅仅是改变了指针的指向,这不利于我们维护代码,因为有时这些信息对我们还是很有用的,此时就可以考虑使用非fast forward的方式,我们继续往下看。

1.2:none fast-forward

想要使用none fast-forward方式也比较简单,只需要在merge时增加参数–no-ff即可,如下实验过程。

  • 基于master创建分支dev101
$ git branchdevdev10dev100
* masterJHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (master)
$ git checkout -b dev101
Switched to a new branch 'dev101'JHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev101)
$ git push origin dev101:dev101
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
remote: Powered by GITEE.COM [GNK-6.3]
remote: Create a pull request for 'dev101' on Gitee by visiting:
remote:     https://gitee.com/dongsir2020/test-cherry-pick/pull/new/dongsir2020:dev101...dongsir2020:master
To https://gitee.com/dongsir2020/test-cherry-pick.git* [new branch]      dev101 -> dev101JHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev101)
$ git branch --set-upstream-to=origin/dev101
Branch 'dev101' set up to track remote branch 'dev101' from 'origin'.JHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev101)
$ git branch -vvdev    1d2f221 dev first commitdev10  09ea18b [origin/dev10] dev second add contentdev100 8adeee0 [origin/dev100] add some content in dev100.txt
* dev101 8adeee0 [origin/dev101] add some content in dev100.txtmaster 8adeee0 [origin/master] add some content in dev100.txt
  • 在dev101分支执行若干次提交
$ touch 101.txtJHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev101)
$ git add *JHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev101)
$ git commit -am'add 101.txt'
[dev101 065f581] add 101.txt1 file changed, 0 insertions(+), 0 deletions(-)create mode 100644 101.txtJHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev101)
$ vim 101.txtJHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev101)
$ git commit -am'add some content in 101.txt'
warning: LF will be replaced by CRLF in 101.txt.
The file will have its original line endings in your working directory
[dev101 0e2c8a0] add some content in 101.txt1 file changed, 1 insertion(+)JHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev101)
$ git push origin dev101:dev101
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 12 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 488 bytes | 488.00 KiB/s, done.
Total 5 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Powered by GITEE.COM [GNK-6.3]
To https://gitee.com/dongsir2020/test-cherry-pick.git8adeee0..0e2c8a0  dev101 -> dev101
  • 切换到master,使用none fast-forward方式合并
$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.JHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (master)
$ git merge dev101 --no-ff
Merge made by the 'recursive' strategy.101.txt | 1 +1 file changed, 1 insertion(+)create mode 100644 101.txt

注意git merge dev101 --no-ff时会弹出一个窗口让我们录入生成的新提交的注释信息,我这里录入的是这是--no-ff方式合并产生的新提交的comment,此时log如下:

$ git log -n4 --pretty=oneline --graph
*   291d49a04f24dd2f266d74d7f1f63406c2632c1e (HEAD -> master) 这是--no-ff方式合并产生的新提交的comment
|\
| * 0e2c8a01e24715b45386b10f0a75b6b4d6215c07 (origin/dev101, dev101) add some content in 101.txt
| * 065f5815cf2505c1ff0feb4f0931056211f42ba2 add 101.txt
|/
* 8adeee00933d01888f128ced8193e728f99faf1f (origin/master, origin/dev100, origin/HEAD, dev100) add some content in dev100.txt

可以看到保留了合并分支的信息,并生成了一个提交的日志291d49a04f24dd2f266d74d7f1f63406c2632c1e (HEAD -> master) 这是--no-ff方式合并产生的新提交的comment。个人觉得这种方式比较好,很清晰。

git rebase有时怎样呢?我们继续来一起看下。

2:rebase

rebase翻译过来就是变基,那么这个基是什么呢,比如当前master分支的提交状态如下:

然后我们使用命令git checkout -b feature,创建了feature分支,然后有执行了提交B1,B2(产生提交并不必须,只是为了好描述),此时如下图:

那么此时feature分支的基就是A3,知道了什么是基,变基就清晰了,就是改变这个基,而改变这个基的命令就是git rebase。这种操作个人认为最大的坏处就是破坏了实际的提交记录,改变了代码提交实际的时间线,我们通过一个实际的例子来看下。

首先从master创建test,dev两个分支,然后分别在两个分支上执行2次提交(注意提交内容在合并时不要产生冲突,这里不考虑rebase有冲突的情况),变为下图:

准备完毕后,查询test,dev两个分支的提交记录如下:

JHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev)
$ git log --pretty=oneline -n2
90f470ed681d6ecdc43cbddbea6b846714cc7a7f (HEAD -> dev) dev2
4a386b2c4d4974d0b9aaa650540a4deb589a25f1 dev1
----------------华丽的分割线--------------
JHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (test)
$ git log -n2 --pretty=oneline
620f696b01e25185185eddc8661c533f59aabcac (HEAD -> test) test2
16c55db40582ac77d8f76e18a44583bcf3369499 test1

接下来我们合并test分支到dev分支,只需要让dev变基到test即可,执行如下操作:

$ git checkout dev
Switched to branch 'dev'JHP+Administrator@jhp MINGW64 /d/test/test-cherry-pick (dev)
$ git rebase test
Successfully rebased and updated refs/heads/dev.

此时查看dev的提交日志:

$ git log -n4 --pretty=oneline
b7b9b230af21686b822ebe80edb6ed71d97c488e (HEAD -> dev) dev2
cfdc1108b0d42a1b516a1fed8310cc438e1d866e dev1
620f696b01e25185185eddc8661c533f59aabcac (test) test2
16c55db40582ac77d8f76e18a44583bcf3369499 test1

可以看到test的提交日志插入到了dev自身提交日志之前,如果魔法一般,这就是变基的结果,此时结构变为下图:

2:总结

merge fast-forward方式是在合并代码时,不需要真正的合并文件就能完成合并时采用的方式,通过简单的移动指针达到效果,合并效率高,但是因为没有真正的合并,所以不会产生合并的记录,即不会有分叉产生,一旦需要合并文件(自然包括有冲突的情况)就会使用none fast forward方式,也可以通过参数–no-ff禁用fast forward,这样保证不管什么情况都是明显的合并记录生成。
rebase因为变基,所以会改变代码提交的时间线,修改程序的实际的提交记录,让代码管理陷入混乱,虽然解决了合并产生的复杂分叉的问题,但是引入的问题也更多,出现问题时,无法正常的通过代码提交查找问题,无法正常的回滚代码等,所以建议非必要就不要使用rebase方式合并代码,而是使用merge配合–no-ff参数的方式,这样能够在保证保留了足够多代码合并信息的同时,也不会改变已有的代码提交历史,唯一的不足的可能就是多了一次因合并而产生的commit而已,不过这又有什么问题呢!

写在后面

参考网址:

8.Git merge之 Fast Forward和 No Fast Forward(–no-ff方式)解析 。

【学了就忘】Git操作 — 65.rebase实战 。

git之merge和rebase相关推荐

  1. 图解 Git 基本命令 merge 和 rebase

    Git 基本命令 merge 和 rebase,你真的了解吗? 前言 Git 中的分支合并是一个常见的使用场景. 仓库的 bugfix 分支修复完 bug 之后,要回合到主干分支,这时候两个分支需要合 ...

  2. Git使用Merge和Rebase

    git rebase命令常常因为江湖上关于它是一种Git魔法命令的名声而导致Git新手对它敬而远之,但是事实上如果一个团队能够正确使用的话,它确实可以让生活变得更简单.在这篇文章中我们会比较git r ...

  3. git中merge,rebase,cherry-pick,patch的联系与区别

    这些操作都是为了把一个分支上的工作加到另一个分支上. merge 把另一个分支合并到当前分支上. rebase 把当前分支的提交在另一分支上重演.(如果可以成功重演,本分支将会消失) cherry-p ...

  4. Merge和Rebase在Git中的区别

    git命令Merge和Rebase的区别 git merge 会生成一个新得合并节点,而rebase不会 比如: [plain] view plaincopyprint? D---E test / A ...

  5. git merge与rebase

    参考这篇文章 Git 之 merge 与 rebase 的区别  文章2 另外,使 rebase出现冲突后,先修改冲突,然后git add 某文件(我使用add  .经常有问题),然后git reba ...

  6. Git Merge VS Rebase

    首先要明白的是 git rebase 可以用来解决和 git merge 一样的问题,两个命令都是被设计出来将一个分支的改变合并到另一个分支里,只是两者的实现方式截然不同而已. 原文链接: https ...

  7. Git 2.9增加了Merge、Rebase、Commit等新特性

    Git 2.9版本已于近期发布.它给merge.rebase和commit工作流带来了新的特性,以及许多其他方面的改进和缺陷修复. \\ Git merge和pull的命令将不允许两个不相关历史的分支 ...

  8. Git分支合并:Merge、Rebase的选择

    git代码合并:Merge.Rebase的选择 - iTech - 博客园 http://www.cnblogs.com/itech/p/5188932.html Git如何将一个分支的修改同步到另一 ...

  9. git merge用法_Git 基本命令 merge 和 rebase,你真的了解吗?

    前言 Git 中的分支合并是一个常见的使用场景. 仓库的 bugfix 分支修复完 bug 之后,要回合到主干分支,这时候两个分支需要合并: 远端仓库的分支 A 有其他小伙伴合入了代码,这时候,你需要 ...

  10. ​同样更新分支,git merge 和 rebase 有什么区别?

    最近在给 kubernetes 提交代码,k8s 社区要求非常严格,既要分支保持与主干的代码同步,还要一次只能有一条 commit.过程中我错误地使用了一把 git merge 和 git rebas ...

最新文章

  1. 查看Linux内核版本的命令
  2. Spring中Controller层、Filter层、Interceptor层全局统一异常处理
  3. Visual C# 3.0 新特性概览
  4. C# rdlc 报表学习总结
  5. 正数数组的最小不可组成和
  6. 吴恩达深度学习课程deeplearning.ai课程作业:Class 1 Week 2 assignment2_1
  7. html页面的header,HTML5教程 | HTML5 header和footer元素
  8. linux eclipse go插件,Eclipse的Go插件(goclipse)
  9. 合并排序(Java)-解析
  10. 《selenium2 python 自动化测试实战》(15)——调用js控制滚动条等操作
  11. mysql回滚与错误提示_对mysql事务提交、回滚的错误理解 – jae – 博客园
  12. 【人工智能】全网首发!2020年AI、CV、NLP等最全国际会议、顶会时间汇总!!
  13. Linux20180502 六周第四次课(5月2日)
  14. Maven实战(高清完整带书签)
  15. hive 窗口函数使用
  16. 当前网络上迅雷各版本实际效果研究报告
  17. O2O营销模式的核心是什么 O2O模式下便利店有哪些特点?
  18. Unicode 中文,日文,西欧语言Unicode编码域(区间)
  19. 计算机的品牌和发展历程,世界著名电脑品牌苹果的发展历程
  20. C++第四章4.7综合实例----个人银行账户管理程序

热门文章

  1. 京东领取京豆助力、京喜活动
  2. 电脑xls图标未正常显示
  3. 什么是socket编程?
  4. 三进制与八进制相互转换
  5. python爬豆瓣影评代码_十行Python代码爬取豆瓣电影Top250信息
  6. mate桌面暗色调超好看的配置
  7. lg android tv遥控器,LG TV Remote遥控器
  8. 热模块替换/热更新 HMR
  9. 桌面PDF文件名太长无法删除的问题
  10. 【机器人学】机器人开源项目KDL源码学习:(9)KDL中的内联函数