[关闭]
@captainjack 2021-04-14T06:53:50.000000Z 字数 4382 阅读 372

git rebase 在工作中的应用

git


写在前面的话

如果你准备从git新手向更高级一点的目标学习的话,那么你应该认真的学习一下git rebase命令.这个命令可以让你对应git commit history管理更加得心应手.本文主要从工作实际应用出发,分三个部分:
1. git rebase 简介
2. git rebase 与 git merge 的区别
3. git rebase -i (交互式rebase)

git rebase 简介

rebase,翻译成中文叫变基,这个很好理解,base就是基础的意思,rebase自然就叫变基,那拆开来就是改变基础的意思,那再想一下,在git中,基础指什么?当然是git commit 历史,所以简单理解起来,git rebase命令就是用来改变git commit历史的.

git rebase 与 git merge 的区别

在git中整合来自不同分支的修改主要有两种方法:mergerebase.我们通过一个实际的场景来说明两者的区别.看下图:
basicrebase1.png-9.2kB
如果,我们有两个分支,开发分支experiment和主分支master,两个分支都有各自的更新c4c3,这个时候我们如果用git merge命令.那么得到的效果如下图:
basic-rebase-2.png-8kB
可以看到,它会把两个分支的最新快照(C3 和 C4)以及二者最近的共同祖先(C2)进行三方合并,合并的结果是生成一个新的快照(并提交),这里强调一下,我们产生了一个新的提交!!!
那么,如果我们用git rebase会怎么样呢? 试一下

  1. $ git checkout experiment
  2. $ git rebase master
  3. First, rewinding head to replay your work on top of it...
  4. Applying: added staged command

结果如下图:
basic-rebase-3.png-7.6kB
提取在 C4 中引入的补丁和修改,然后在 C3 的基础上应用一次,在 Git 中,这种操作就叫做rebase/变基,它的原理是首先找到这两个分支(即当前分支 experiment、变基操作的目标基底分支 master)的最近共同祖先 C2,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件,然后将当前分支指向目标基底C3, 最后以此将之前另存为临时文件的修改依序应用。这里注意观察一下,并没有产生多的提交!!!
这时候,再回到master分支,进行一次fast-forward(快进)合并

  1. $ git checkout master
  2. $ git merge experiment

得到的最终结果如下:
basic-rebase-4.png-6.4kB
看起来是不是 特别干净!!!
这个大概是 git merge 跟 git rebase 在使用中的区别

git rebase -i 交互式变基

很多时候,我们需要修改某个分支的提交历史,这个时候,就需要用到git rebase -i
用法如下

  1. git rebase -i 需要改变的commit的前一个commit

来看一个实际的例子
你想要修改最近三次提交信息,或者那组提交中的任意一个提交信息,将想要修改的最近一次提交的父提交作为参数传递给 git rebase -i 命令,即 HEAD~2^ 或 HEAD~3。 记住 ~3 可能比较容易,因为你正尝试修改最后三次提交;但是注意实际上指定了以前的四次提交(因为当前提交是HEAD~0),即想要修改提交的父提交。这里是我觉得可能会绕一点的,建议慢点看
于是,输入命令

  1. $ git rebase -i HEAD~3

得到

  1. pick f7f3f6d changed my name a bit
  2. pick 310154e updated README formatting and added blame
  3. pick a5f4a0d added cat-file
  4. # Rebase 710f0f8..a5f4a0d onto 710f0f8
  5. #
  6. # Commands:
  7. # p, pick = use commit
  8. # r, reword = use commit, but edit the commit message
  9. # e, edit = use commit, but stop for amending
  10. # s, squash = use commit, but meld into previous commit
  11. # f, fixup = like "squash", but discard this commit's log message
  12. # x, exec = run command (the rest of the line) using shell
  13. #
  14. # These lines can be re-ordered; they are executed from top to bottom.
  15. #
  16. # If you remove a line here THAT COMMIT WILL BE LOST.
  17. #
  18. # However, if you remove everything, the rebase will be aborted.
  19. #
  20. # Note that empty commits are commented out

你可以看到上面的输出,一个提交列表,可以使用vim进行编辑,不懂vim的看这里
这里,主要提醒注意两点:
1. 你看到的上面三个commit记录的顺序,跟你使用git log看到的顺序是反的。
2. 对应的commands 都有相应的英文解释,自己先看明白了
下面我们针对每个command 进行讲解:
* pick ,就是会保留这个commit,什么都不变,不变顺序,也不变commit信息
* reword,就是只改变commit信息
* edit,相当于对这个commit 使用 git commit --amend
* squash,压缩这个commit,就是把对应更改压缩到前一次提交,去掉本次提交,但是这次的提交信息还保留着
* fixup,这个比较squash,就是提交信息也不保留了
* exec,这个我没用过,应该是执行shell 命令吧直接,暂时不会用到
有可能,你看到这里还是有点蒙蔽,下面我们直接来说说,下一步我们可以做哪些事情
1. 改变提交顺序
还记得之前列出来的3次提交吧,你可以通过文本编辑,直接删除或者交换顺序

  1. pick f7f3f6d changed my name a bit
  2. pick 310154e updated README formatting and added blame
  3. pick a5f4a0d added cat-file

比如我们可以删除 added cat-file这次提交,并且交换另外两次提交的顺序,
像这样

  1. pick 310154e updated README formatting and added blame
  2. pick f7f3f6d changed my name a bit

然后,你保存并退出文本编辑,最后你看到的结果就是,git 修改了提交顺序并且移除了你刚才删除的提交
2. 压缩提交
继续回到那三次提交

  1. pick f7f3f6d changed my name a bit
  2. pick 310154e updated README formatting and added blame
  3. pick a5f4a0d added cat-file

如果我们想要压缩310154ea5f4a0d这两次提交,那么我们就需要用之前提到的命令squash或者fixup,通常我们用squash,提交信息嘛,待会也是可以注释删除掉的
我们编辑文本如下:

  1. pick f7f3f6d changed my name a bit
  2. squash 310154e updated README formatting and added blame
  3. squash a5f4a0d added cat-file

这个时候,保存并推出文本编辑器,Git会应用这三次修改,然后再把你放到编辑器中来合并三次提交信息(之前就跟你说squash也可以注释来删除提交信息),你看到的编辑器是这样的:

  1. # This is a combination of 3 commits.
  2. # The first commit's message is:
  3. changed my name a bit
  4. # This is the 2nd commit message:
  5. updated README formatting and added blame
  6. # This is the 3rd commit message:
  7. added cat-file

这还有啥好说的,看看你想要提交信息是什么样子的,就编辑成什么样子呗,注意一下 #开头的,就是相当于注释掉,然后一样的操作,保存并推出,你就完成了压缩提交操作:)
3. 拆分提交
这个就有点意思了,感觉之前の命令里面,好像没有说到可以拆分提交的.没有说就等于没有吗?那你就太年轻了.下面来看一下,我们怎么做到的
还是回到那三次提交

  1. pick f7f3f6d changed my name a bit
  2. pick 310154e updated README formatting and added blame
  3. pick a5f4a0d added cat-file

这时候,我们想要把310154e拆分成,updated README formattingadded blame,那么我们可以对310154e提交试用edit命令,像这样

  1. pick f7f3f6d changed my name a bit
  2. edit 310154e updated README formatting and added blame
  3. pick a5f4a0d added cat-file

保存并推出文本编辑器.
然后你看到提示信息如下,并且进入到命令行

  1. Stopped at 310154e... changed my name a bit
  2. You can amend the commit now, with
  3. git commit --amend
  4. Once youre satisfied with your changes, run
  5. git rebase --continue

上面说,你可以选择git commit --amend或者git rebase --continue,前者是修改本次提交,后者是继续下一步. emmm,那我们现在改怎么做呢?
我们选择做自己想做的,撤销本次提交,然后将修改的内容分两次提交
像这样:

  1. $ git reset HEAD^
  2. $ git add README
  3. $ git commit -m 'updated README formatting'
  4. $ git add lib/simplegit.rb
  5. $ git commit -m 'added blame'

最后在执行

  1. git rebase --continue

完成之后,你看到的提交历史就是这样的

  1. $ git log -4 --pretty=format:"%h %s"
  2. 1c002dd added cat-file
  3. 9b29157 added blame
  4. 35cfb2b updated README formatting
  5. f3cc40e changed my name a bit

显然,我们完成了对历史提交的拆分,欧耶~

写在最后的话

那么,你现在大概知道了 git rebase的用法,多用几次就熟悉了,其实最主要的就是,你现在可以用这个方法来整理你的提交历史,让你的提交显得清晰,不冗余.
暂时先写到这里
参考资料:
1.git-book,分支-变基
2.git-book,工具-重写历史

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注