今天來介紹下 git 的 rebase 命令。這個命令是我進入新公司之后才了解到的,以前還真的沒使用過,盡管我接觸 git 已經(jīng)有 3 年了。
假如現(xiàn)在有個項目,它的 git 狀態(tài)是這樣的:

OK,我們開始今天的內(nèi)容。
分支合并
我們先在 master 分支的基礎(chǔ)上新建一個 dev 分支, 并做一個 commit:
$(master) git checkout -b dev

這時候另外一個開發(fā)人員發(fā)現(xiàn) master 上的代碼有一個問題,對 master 的代碼做了一個 fix,使得 master 的 head 向前推進了一步:

如果我們想將 master 的 Fix 改動應(yīng)用到 dev 分支上,要如何做呢?
可以使用 merge,我們來試下:
$(dev) git merge master

merge 過后 dev 分支向前推進了一步。我們看下多出來的 commit 信息是怎樣的
commit 02581b628586b29c5c8a3cfd04d1563fa4e5b5a7 (HEAD -> dev)
Merge: 18d26a0 8985e47
Author: lwhile <lwhile521@gmail.com>
Date: Sun Jun 3 15:26:55 2018 +0800
Merge branch 'master' into dev
dev 上 多出來的這個 commit(綠色的那個節(jié)點), 就是我們的 merge 信息。
有時候我們并不想要 git 記錄這個 merge 信息,因為讓 git 的歷史記錄變得很繁瑣,要如何做呢?可以使用 rebase !
我們先回到 master 提交了 fix 之后的 git 狀態(tài):

執(zhí)行 rebase 命令:
$ (dev) git rebase master
這時候看下 git 狀態(tài):

比較下 merge 和 rebase 之后的狀態(tài)圖,我們可以發(fā)現(xiàn) masste 的 fix 被接到 dev 的后面,并且沒有多出一個 merge 信息。這樣 commit 信息是不是簡潔了很多?
commit 改寫
除了用在分支的合并上, rebase 命令還能幫你修改 commit 記錄。
我們讓 dev 分支再向前推進 3 步:

╰─$ git log
commit 6639f35cc779afe6f7eb68f13faad0cfe2a8a7a4 (HEAD -> dev)
Author: lwhile <lwhile521@gmail.com>
Date: Sun Jun 3 16:01:29 2018 +0800
add dev3.go
commit c76ac0c0c0359170a6eca0ee1319ec16b2ae6351
Author: lwhile <lwhile521@gmail.com>
Date: Sun Jun 3 16:01:10 2018 +0800
add dev2.go
commit 20cd0cfcd64fee7c4459a1da527f8c2c239ac5e4
Author: lwhile <lwhile521@gmail.com>
Date: Sun Jun 3 16:00:57 2018 +0800
add dev1.go
提交完這 3 個 commit 之后,我們發(fā)現(xiàn)這 3 個 commit 屬于同一個改動類型,完全沒必要分成 3 個 commit。
那要怎么做呢?還是可以使用 rebase
$ (dev) git rebase -i HEAD~4
執(zhí)行該命令 shell 會進入交互模式(-i)
pick c524f8e add dev.go
pick 20cd0cf add dev1.go
pick c76ac0c add dev2.go
pick 6639f35 add dev3.go
# Rebase df58ee3..6639f35 onto df58ee3 (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.
#
# Note that empty commits are commented out
根據(jù)提示,我們將文本做如下修改(將 pick 換成 s,至于為什么要這樣寫,可以看 git 的提示):
pick c524f8e add dev.go
s 20cd0cf add dev1.go
s c76ac0c add dev2.go
s 6639f35 add dev3.go
保存并退出:
[detached HEAD 0a15d35] add dev.go
Date: Sun Jun 3 15:38:35 2018 +0800
4 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 dev.go
create mode 100644 dev1.go
create mode 100644 dev2.go
create mode 100644 dev3.go
Successfully rebased and updated refs/heads/dev.
現(xiàn)在 git 又進入了如下狀態(tài),只不過綠色的那個節(jié)點包含了 4 個 commit 信息

commit 0a15d3549ee9ec61ddeb33916c452fab2ad9b991 (HEAD -> dev)
Author: lwhile <lwhile521@gmail.com>
Date: Sun Jun 3 15:38:35 2018 +0800
add dev.go
add dev1.go
add dev2.go
add dev3.go
這時候再將 dev 合并進 master,commit 信息都會簡潔很多,并且也有利于 review。
總結(jié)
rebase 是一個很神奇的工具,可以幫你做一些比較特別的改動。但要注意, rebase 是會隱藏你真實的修改記錄的,所以最后呈現(xiàn)出來的 git 歷史并不能表現(xiàn)你的真實操作,這點要注意。