git rebase 与 git merge的区别

5,831 阅读9分钟

之前的在公司一直在用git merge 合并, 这家用的是git rebase进行合并,那么有什么区别呢? 本篇主要是针对git rebase 进行整理(抽时间总结了下),文章很长但是不臭甚至还有点香-_-

先说说一般的开发,都是基于dev开一个分支a, a提交到远程, 最后用工具去将a合到dev(毕竟不是所有人都有合并权限)

一 git rebase基本知识

1.git rebase是什么?

rebase的意思就是变基,意思就是基于哪个分支进行修改,base就是基于什么

2.git rebase 与 git merge有什么区别

主要的区别在于基于什么而修改的区别

看看下面这个例子吧~

1.假如有个分支叫做develop,上面已经提交了2个commit c1, C2,这时我基于远程的develop开了一个分支 feature_amount (金额调整)

2.现在又在dev分支提交了2个commit(c3, C4),并且在feature_amount 提交2个commit (c 5 和 c6 ),这时候可以看到dev和feature_amount这两个分支各自“前进”了,它们之间“分叉”了,那我们怎么去把代码push到feature_amount远程并且与dev代码合并呢

3.现在我们有两种方法也可以进行合并,第一种是git merge, 第二种是git rebase 先看看如果我们用的是git merge如何实现

git merge

git add. --- > git commit –m ---> git pull origin dev --- > (解决冲突 --- > git add . --- > git commit –m ---> )git push origin feature_amount

这里我们需要知道的是: git pull = git fetch + git merge, 这是我们经常用的一种方式 ,把dev的代码合到 feature_amout上, 这个合并并不是基于dev或者基于feature_amount

git rebase

还有一种方式就是 git fetch + git rebase

git add . --- > git commit –m ---> git pull origin develop --rebase --->解决完冲突之后 ---> git status(working tree clean) --- > git push origin feature_amount -f

如果你想通过dev本地代码也做更新,再拉本地的dev做变基,也是可以的,首先我们可以先切到develop分支 然后用git pull 直接把代码拉下来 然后切回 feature_amount

git rebase develop --->git stash pop --> 解决完冲突之后 ---> git status ---> git add . --- > git commit –m “add sth” --- > git push origin feature_amount -f

那么这两种有什么区别呢? 从图上可以看出git merge图的话 c5是指向c2是基于c2, git rebase 图用了rebase之后 c5 也就是我们的c5’ 指向的是我们的c4,这就是所谓的变基,那么意思就是说git merge 是基于未修改前的develop, git rebase 是基于修改后的develop进行合并

3.为什么推荐使用git rebase
 3.1整个commit提交成一条直线
 3.2 去掉了不起作用的commit 方便查看 
 3.3有利于回滚
1整个commit提交成一条直线

git merge 提交图形

git rebase 提交图形

2 去掉了不起作用的commit 方便查看

基于远程的develop开了一个分支 feature_rebase, dev上提交了c3 c4 , feature_rebase上提交了c5 c6 现在在feature_rebase进行rebase并且添加一个c7进行提交

在解决冲突的时候是一个一个的先是c5看看与base有没有冲突,再是c6与base有没有冲突,如果在 c5和c6在解决冲突的时候一直都是保留c3,c4,而没有保留c5,c6的内容修改,那么c5,c6这两个commit将不会提交显示

进行rebase develop

3有利于回滚
基于远程的develop开了一个分支 rebase_1  
dev上提交了develop , rebase_1上提交了add rebase1 
现在在rebase_1进行rebase develop 然后提交
这时我想要回退到add rebase1这个commit (重置为[commit]所对应节点的提交)

滚到这个commit的时候 rebase有之前所有的记录,而merge的话 只有当前的commit --- BTW 回滚不要用git reset – hard 用revert就好拉

附: git reset / git checkout / git revert的区别: www.cnblogs.com/darknebula/…

二 Git rebase 怎么使用以及解决冲突

1.git rebase 如何使用

develop为主分支, feature为个人开发分支

git add . --> git commit -m --> git pull origin develop --rebase ---> 解决冲突 ---> git status(只有在working tree clean的状态才能提交) --->git push origin feature -f

2 git rebase 遇到冲突了怎么办

先是解决当前的页面的冲突,然后git add . -->git rebase --continue 如果再有,再解决,持续执行git add . -->git rebase --continue

如果你遇到下面的报错,可能是你之前有一步忘了加git add . , 我建议你重新git rebase -abort 就是回到从来没有rebase过的状态,再试试

或者直接git rebase --skip 跳过这个rebase,解决单个冲突后,执行git add . -->git rebase --continue

那么有没有想过为啥我一直需要git add . ---> git continue --rebase ,feature中每个commit都要与dev修改后的最新代码一个个进行对比,所以我们在开发的时候,也要减少commit的提交,,也是简化的一个操作

所以正常的流程,我在feature分支

git add. --> git commit -m --> git pull origin develop --rebase ---> (REPEAT解决冲突 ---> git add . --->git rebase --continue )---> git status(只有在working tree clean的状态才能提交) ---> git push origin feature -f

当然,如果你解决冲突之后有一些修改,git status那一步之后可以变成 git add . --- > git commit –m --- > git push origin feature –f merge的话 是一次性解决所有的冲突, 而rebase的话,是一个一个commit 去做base上面做修改,一个个解决冲突,所以才会有 红色那几步的重复

最全的流程

git add . ---> git commit -m 'xx' ---> git pull origin develop --rebase ---> (Repeat解决冲突 ---> git add . --->git rebase --continue )---> git status(只有在working tree clean的状态才能提交) ---> git push origin feature –f

什么时候我不用add 和commit 直接强推呢? 比如我a已经发了merge request 到了dev,但是b也发了merge request 到了 dev,b先合并,a和b有冲突,这时候我a要做的事就是去解决冲突,并没有修改,可以直接解决完就推,因为这时候我这个commit提交不提交无所谓,当然最好提交一下

但是当我本地有解决冲突并且也是有实际冲突的提交,可以加上 git add . ---> git commit -m 'xx'

三 绝对不要在公共分支使用rebase

3.1例如在解决冲突的时候,是一个一个commit去解决的,那么有可能有其他的人的commit要解决, 几个人开发一个分支的话,会很浪费时间也不方便

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

先有一个dev的分支 然后在他的基础上开一个 feature 然后dev做了两次提交 c3 c4 feature有两个人开发 我和other吧 这时我们本地最新的代码都是c2 我做了两次提交 c5 c6 这时我push的话做一个rebase 那我变成了c5' c6' 提交了远程 这时other 还在傻傻的写代码 也就是想提交一个c7 那么other面临的困惑是 我到底是rebase dev的代码呢 还是rebase 我这个分支的代码也就是c6’ 如果他rebase的是develop other与我就渐行渐远了 如果他rebase的是我c6'的代码 他可能面临非常多的冲突 关键在于 不去查看远程提交 他不知道到底rebase 哪一个

四 git rebase的踩坑之旅

1. 记得解决冲突的时候是执行git add . --->git rebase --continue

如果你被rebase的之后的冲突折磨疯了的话,很可能你会写 git rebase continue , 那么他也不会报错,会提示下面一大堆, 会被带偏的

2. 为什么会出现重复的commit
如有两个merge request要合到dev 我们这里就是指定test1 和rebase_test_3吧 
test1已经合到dev了 这时我应该把rebase_test_3的request 去close掉,然后更新一下dev的代码到rebase_test_3
然后再push 下面的操作会导致 commit 记录的重复

为什么出现这种情况?

git push的时候,git会比较commit history,如果不一致,commit动作会被拒绝,所以会提示你需要pull,唯一的办法就是带上-f参数

rebase 后,commit 的 hash 变了,在 git 里就是两次不同的提交, 如果直接pull 本地分支远程的代码,就都保留了两次commit ,所以在你push 之前 他推荐你pull的时候,不用管他,直接-f强推

先在你没有pull之前 你是 因为rebase之后hash 变成了 fc1716 ,你现在pull了一次把远程的e785181带过来了,所以会有两次commit,所以这时候你就不要pull了直接推

如何解决

拉完develop的代码之后, 直接做git rebase develop ,有冲突的话解决冲突, 没有的话 git status一下 看看是不是干净的树 , 然后直接强推

3.git rebase --abort
--continue: 就是继续rebase
--abort: 表示放弃之前的rebase
--skip 就是跳过这个rebase

如果是之前处于rebase状态,你现在是对另一个进行rebase ,前面的不用了 ,可以用git rebase --abort

4. 怎么去看提交的commit记录— git log – - graph - -oneline (因为 github 上没用 graph 来显示)

5.git rebase -i (非常强大,自己找文章去试试吧,亲)
squash: 把commit合到前一个
drop: 丢掉某个commit  
Edit: 修改提交 也就是把pick改成edit 去修改文件之后, git add file ---》git commit –amend --- 》git rebase --continue

如何将多个commit变成一个

五 为什么git rebase没有被广泛的推广起来

作为一个用了快一年git rebase的人,从0-> 1,学习时间是一周,谈谈我的感受,用之前我们团队没有一个人会用,我学了然后再分享

1.学习时间成本太高,毕竟这是涉及到合并提交代码,不能乱搞
2.每次解决冲突都是一个一个合的
3.多人开发的分支不适合用

我所知道的还只是皮毛,希望后续能够持续研究~

如果没有精力看完所有,最全提交流程 基于develop开了分支feature, feature上开发完

git add . ---> git commit -m 'xx' --> git pull origin develop --rebase ---> (Repeat解决冲突 ---> git add . --->git rebase --continue )---> git status(只有在working tree clean的状态才能提交) ---> git push origin feature –f

当然如果是git status后面你又有新的更改,还是重新要走一遍相似的流程,因为在push之前一定要保证拉的是最新的代码