主要参考文章:
http://jartto.wang/2018/12/11/git-rebase/
https://juejin.im/entry/5ae9706d51882567327809d0
https://blog.csdn.net/gtlbtnq9mr3/article/details/80222523
场景一:合并多次提交记录
场景二:分支合并
场景三:对一个分支做『变基』操作
1、代码修改时,有时候一个功能可能返回修改并提交(commit)多次,到最终完成这项功能,可能会存在很多无效的提交,于是这就让一些强伯症的人很不舒服;关键是如果有一天线上出现了紧急问题,你需要回滚代码,却发现海量的 commit
需要一条条来看,这是令人崩溃的。
那么,如何实现多次的提交用一次提交实现呢?这就对应Git rebase的场景一的应用
这样做的依据: 遵循项目规范才能提高团队协作效率,而不是随心所欲。
那它是如何实现的呢?看第三节
2、说到代码分支的合并,我们首先想到的就是 Git merge。对我来讲,git merge已经满足了我的需求,但是git merge存在一个问题就是,将dev分支合并到master分支时, 在master上git log会发现多了一次merge相关的log记录,这又让一些强迫症者们不舒服了。
那么该如何才能做到既能做到分支的合并,又能不增加无效的commit记录呢?这就对应了Git rebase的场景二了。
它是如何实现的呢?看第四节
(番外:相对Git rebase的不留痕迹的合并,我还是喜欢Git merge, 毕竟留下痕迹才能日后跟踪)
1.我们来合并最近的 4 次提交纪录,执行:
|
2.这时候,会自动进入 vi
编辑模式:
|
有几个命令需要注意一下:
按照如上命令来修改你的提交纪录:
|
然后wq
保存退出后是注释修改界面 :
在这个页面可以编辑提交的信息,如果不做任何修改直接wq退出的话,提交信息就包括上面4次的提交信息
(额外说明:可以再浏览态 按下两个dd可以删除一行)
# This is a combination of 4 commits.
# This is the 1st commit message:
qrcode
# This is the commit message #2:
indexddb hack
# This is the commit message #3:
add indexedDB floder
# This is the commit message #4:
add test2.js
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Fri Apr 24 19:08:59 2020 +0800
#
"~/Documents/Projects/Test/.git/COMMIT_EDITMSG" 24L, 587C
3.查看结果
|
这时候看到的最新的一次commit log 就是合并了这4次commit的结果
上面是正常的流程,下面说下很多情况遇到的不正常的情况:
需要注点:
1、注意不要合并先前提交的东西,也就是已经提交远程分支的纪录。
如果这样做,可能出现push rejected。 解决方式当然是先拉下远程的代码,进行冲突处理,再进行提交。
(但是,如果非要这么干,这是何必呢,我只是想把多次提交合成一次,结果本来正常的代码出现冲突,所以还是不要合并已经push的东西)
2、在上面第2步如果出现不正常的操作,导致退出了vim编辑页面,这时候如果还想使用git rebase -i HEAD~4进入vim编辑页面是不行的,会提示:
It seems that there is already a rebase-merge directory, and
I wonder if you are in the middle of another rebase. If that is the
case, please try
git rebase (--continue | --abort | --skip)
If that is not the case, please
rm -fr "/Users/qinwenjing/Documents/Projects/Test/.git/rebase-merge"
and run me again. I am stopping in case you still have something
valuable there.
解释的还算清楚,所以不要慌!
使用 git rebase --edit-todo 会再次进入刚才编辑错误退出前的vim状态,这时候可以修改你的编辑。
使用git rebase --abort 表明退出当前的合并请求( 又回到原来的4个commit的状态)
3、如何只是合并多次commit,会不会出现冲突呢,目前还是没试出来。。。。
1. 我们先从 master
分支切出一个 dev
分支,进行开发:
|
2. 这时候,你的同事完成了一次 hotfix
,并合并入了 master
分支,此时 master
已经领先于你的 feature1
分支了:
3. 恰巧,我们想要同步 master
分支的改动,首先想到了 merge
,执行:
|
|
就会在记录里发现一些 merge
的信息,但是我们觉得这样污染了 commit
记录,想要保持一份干净的 commit
,怎么办呢?这时候,git rebase
就派上用场了。
4. 让我们来试试 git rebase
,先回退到同事 hotfix
后合并 master
的步骤:
5.使用 rebase
后来看看结果:
|
这里补充一点:rebase
做了什么操作呢?
首先,git
会把 feature1
分支里面的每个 commit
取消掉;
其次,把上面的操作临时保存成 patch
文件,存在 .git/rebase
目录下;
然后,把 feature1
分支更新到最新的 master
分支;
最后,把上面保存的 patch
文件应用到 feature1
分支上;
从 commit
记录我们可以看出来,feature1
分支是基于 hotfix
合并后的 master
,自然而然的成为了最领先的分支,而且没有 merge
的 commit
记录,是不是感觉很舒服了。
6. 在 rebase
的过程中,也许会出现冲突 conflict
。在这种情况,git
会停止 rebase
并会让你去解决冲突。在解决完冲突后,用 git add
命令去更新这些内容。
例如在master分支上执行了 git rebase dev, 存在冲突
MacBook-Pro-3:Test qinwenjing$ git rebase dev
First, rewinding head to replay your work on top of it...
Applying: rrrrrr
Using index info to reconstruct a base tree...
M src/main/java/gittest/simpleTest.java
Falling back to patching base and 3-way merge...
Auto-merging src/main/java/gittest/simpleTest.java
CONFLICT (content): Merge conflict in src/main/java/gittest/simpleTest.java
error: Failed to merge in the changes.
Patch failed at 0001 rrrrrr
The copy of the patch that failed is found in: .git/rebase-apply/patch
Resolve all conflicts manually, mark them as resolved with
"git add/rm ", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
MacBook-Pro-3:Test qinwenjing$
解释的也比较清楚,定位到SimpleTest, 解决完冲突后,你无需执行 git-commit,需要的是执行add和continue
|
这样 git
会继续应用余下的 patch
补丁文件,继续上面的解决冲突的过程。最后解决完所有的冲突,完成合并。
(个人感觉这种合并方式不好,需要针对每次commit进行合并,非常麻烦,而不是像git merge那样直接处理所有的冲突。)
7.在任何时候,我们都可以用 --abort
参数来终止 rebase
的行动,并且分支会回到 rebase
开始前的状态。
|
参考这个:https://blog.csdn.net/gtlbtnq9mr3/article/details/80222523
从第四节也可以看出,使用git rebase会改变git的提交记录(变基)。这种危险性存在于一个分支被多个人开发的情况(这种情况再正常不过了)。
You在开发feature分支时rebase了master, 导致feanture分支的变基(基础由白色点变成了红色点),当You push feature分支到远程后,远程的feature分支也发生了变基。
当你的同时Bob在拉取远程的feature分支时,果不其然的出现了冲突,因为Bob本地feature分支基础和远程feature分支基础是不一样的。