Git rebase命令

主要参考文章:

http://jartto.wang/2018/12/11/git-rebase/

https://juejin.im/entry/5ae9706d51882567327809d0

https://blog.csdn.net/gtlbtnq9mr3/article/details/80222523

 

一、Git rebase的主要应用场景

场景一:合并多次提交记录

场景二:分支合并

场景三:对一个分支做『变基』操作

二、Git rebase解决的问题

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,  毕竟留下痕迹才能日后跟踪)

 

三、使用git rebase合并多次commit

1.我们来合并最近的 4 次提交纪录,执行:

git rebase -i HEAD~4

2.这时候,会自动进入 vi 编辑模式:

s cacc52da add: qrcode
s f072ef48 update: indexeddb hack
s 4e84901a feat: add indexedDB floder
s 8f33126c feat: add test2.js

# Rebase 5f2452b2..8f33126c onto 5f2452b2 (4 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#

有几个命令需要注意一下:

  • p, pick = use commit
  • r, reword = use commit, but edit the commit message
  • e, edit = use commit, but stop for amending
  • s, squash = use commit, but meld into previous commit
  • f, fixup = like “squash”, but discard this commit’s log message
  • x, exec = run command (the rest of the line) using shell
  • d, drop = remove commit

按照如上命令来修改你的提交纪录:

p cacc52da add: qrcode
s f072ef48 update: indexeddb hack
s 4e84901a feat: add indexedDB floder
s 8f33126c feat: add test2.js

然后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.查看结果

git log

这时候看到的最新的一次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,会不会出现冲突呢,目前还是没试出来。。。。

 

四、使用git rebase进行分支合并

1. 我们先从 master 分支切出一个 dev 分支,进行开发:

git:(master) git checkout -b feature1

 

Git rebase命令_第1张图片
2. 这时候,你的同事完成了一次 hotfix,并合并入了 master 分支,此时 master 已经领先于你的 feature1 分支了:
Git rebase命令_第2张图片
3. 恰巧,我们想要同步 master 分支的改动,首先想到了 merge,执行:

git:(feature1) git merge master

 

Git rebase命令_第3张图片
图中绿色的点就是我们合并之后的结果,执行:

git:(feature1) git log

就会在记录里发现一些 merge 的信息,但是我们觉得这样污染了 commit 记录,想要保持一份干净的 commit,怎么办呢?这时候,git rebase 就派上用场了。

4. 让我们来试试 git rebase ,先回退到同事 hotfix 后合并 master 的步骤:
Git rebase命令_第4张图片
5.使用 rebase 后来看看结果:

git:(feature1) git rebase master

这里补充一点:rebase 做了什么操作呢?

首先,git 会把 feature1 分支里面的每个 commit 取消掉;
其次,把上面的操作临时保存成 patch 文件,存在 .git/rebase 目录下;
然后,把 feature1 分支更新到最新的 master 分支;
最后,把上面保存的 patch 文件应用到 feature1 分支上;

Git rebase命令_第5张图片

从 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 add .
git rebase --continue

这样 git 会继续应用余下的 patch 补丁文件,继续上面的解决冲突的过程。最后解决完所有的冲突,完成合并。

(个人感觉这种合并方式不好,需要针对每次commit进行合并,非常麻烦,而不是像git merge那样直接处理所有的冲突。)

 

7.在任何时候,我们都可以用 --abort 参数来终止 rebase 的行动,并且分支会回到 rebase 开始前的状态。

git rebase —abort

五、Git 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分支基础是不一样的。

Git rebase命令_第6张图片

你可能感兴趣的:(GIT)