使用Git的rebase操作优化提交历史

编程

如果现在执行git merge feature#1,git会找到提交对象G和D的共同基点C,然后做三方比较合并,合并之后产生一个新的提交对象H,分支的演变如下:

     E---F---G  feature#1

     /    

A---B----C---D-----H  master

但是如果我们采用git rebase feature#1则情况完全不同,git也会产生合并,但实际上是git先把master倒回(rewind)到C的提交点,然后把feature#1分支上的所有提交按顺序在master上重新执行一遍,然后把master上的在C之后的提交D进行一次fast-forward合并, 结果项目的分支情况就是下面这样:

     E---F---G      feature#1

     /

A---B----C---E"---F"---G"---D  master

现在我们从master上使用git log查看提交历史的话,看不到任何分支的分叉轨迹,完全是线性的,就好像所有的提交(包括实际上发生在feature#1分支上的提交)都是在master分支上发生的,并且可以看到原先master上的修改好像都是在feature#1的基础上进行的而不祖先C,这就是rebase表达的含义,它改变了master上所最新提交的历史基点。

正式由于rebase这样的结果,所以要根据具体情况来使用它,如果我们想要明确的保留项目的分叉合并历史演进情况,那么rebase不合适而应该使用merge。

注意,不要在一个已经向其他人公开了的分支上执行rebase,这会导致项目其他成员已经获得的分支历史纪录丢失。

适合使用rebase的情景

  1. 我们在一个私有的分支上对项目做了改动(增加新功能或解决缺陷),然后我们把私有分支rebase到主干上提交给项目管理人,这样主干上会获得一个非常干净直观的提交历史。

  2. 我们正在进行一个特性分支,但是由于已经发布的代码发现了缺陷,我们解决了缺陷然后发布到了主干上,继续回到特性分支上工作,这时我们想把刚刚解决的那个问题的代码合并到特性分支上,因为我们的新功能开发需要依赖有缺陷的那部分代码,这个时候非常适合使用rebase而不是merge,把主干rebase到特性分支上以后,结果就好像我们所有的新功能代码都是在解决了缺陷以后的基础上进行的。

  3. 某个分支产生了很多无效的提交,污染项目的分支提交历史,这种情况下使用rebase的交互式模式可以把已经发生的多次提交压缩成一次提交,得到了一个干净的提交历史,例如某个分支的提交历史情况如下:

    $ git log --pretty=oneline --abbrev-commit

    // 这些提交从e9782b9到a97cf60就是冗余的提交

    e9782b9 (HEAD -> feature#pos-nowpay, origin/feature#pos-nowpay) 修复缺陷

    a3880b3 修复缺陷

    6c0aa44 修复缺陷

    5b29942 优化代码

    e1e20f3 优化代码

    62340d1 修复缺陷

    e4f656a pom优化

    ad0f0c1 汉朔POS机支付接入现在支付平台

    a97cf60 汉朔POS机支付接入现在支付平台

    f8e7257 增加日志打印细节

    ......

    进入交互式模式的方式是执行:

    $ git rebase -i <base-commit>

    参数base-commit就是指明操作的基点提交对象,对于上述提交历史的例子,我们要把最后的一个提交对象(f8e7257)之前的提交压缩成一次提交,我们需要执行的命令格式是:

    $ git rebase -i f8e7257

    # 或者使用 HEAD~9也行

    $ git rebase -i HEAD~9

    接着git会进入一个交互式的文本编辑器中,编辑器中列出的信息类似下面这样:

    pick a97cf60 汉朔POS机支付接入现在支付平台

    pick ad0f0c1 汉朔POS机支付接入现在支付平台

    pick e4f656a pom优化

    pick 62340d1 修复缺陷

    pick e1e20f3 优化代码

    ...... # 这里省略一些提交对象

    # Rebase f8e7257..e9782b9 onto f8e7257 (9 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.

    ......

    上面的命令中squash表示压缩的意思,我们保留第一个提交,把后面的提交前面的命令都改为squash或者s

    pick a97cf60 汉朔POS机支付接入现在支付平台

    squash ad0f0c1 汉朔POS机支付接入现在支付平台

    squash e4f656a pom优化

    squash 62340d1 修复缺陷

    squash e1e20f3 优化代码

    # Rebase f8e7257..e9782b9 onto f8e7257 (9 commands)

    ......

    然后保存并退出编辑器,接着git再次进入文本编辑模式,这一次我们可以重新编辑提交消息,编辑好提交消息后再次保存退出即可,接着git会继续rebase过程,完了之后就变成了一次提交,如下:

    $ git log --pretty=oneline --abbrev-commit

    # 压缩之后变成一次提交

    2b0e2e3 (HEAD -> feature#pos-nowpay) 汉朔POS机支付接入现在支付平台

    f8e7257 增加日志打印细节

    注意,不要在一个已经公开的分支上执行任何rebase操作,否则会导致其它项目成员丢失提交历史

以上是 使用Git的rebase操作优化提交历史 的全部内容, 来源链接: utcz.com/z/512844.html

回到顶部