1.說明
有時(shí)commit多了看著會(huì)不爽.所以想合并掉一些commit. 這里是最簡(jiǎn)單的情況, 一條線下來N個(gè)commit, 合并掉末端的(沒有branch出去的).
假設(shè)有a,b,c,d四個(gè)commit, 從新到舊是a, b, c, d (也就是先d->c->b->a). 四個(gè)commit的SHA-1分別是a1,b1,c1,d1.
合并commit只能倒退, 就是說把a(bǔ)合到b(老的),順序是abc可以合并起來成k, 最后成k, d這樣.
2.過程
# git log |head
git rebase -i d1
# if fail, use git rebase --abort
git push --force
git log可以查看commit的情況, 配著head命令可以查看前幾個(gè). git log --pretty=oneline一行一個(gè)commit更好了(默認(rèn)就是如此)
rebase前需要把狀態(tài)push掉. 就是說不能有unstaged的修改.
-i 是選擇不動(dòng)的commit, 比他新的commit都有被修改的可能.
執(zhí)行rebase后如果出錯(cuò)或者merge沖突什么退出來, rebase會(huì)被鎖定, 再次執(zhí)行時(shí), 提示有三個(gè)選項(xiàng):
git rebase --abort來忽略之前的rebase嘗試,并恢復(fù)HEAD到開始的分支.
git rebase --continue就繼續(xù)上次修改, 一般是rebase中間處理merge沖突后使用.
git rebase --skip是重新開始rebase并跳過現(xiàn)在所進(jìn)行的處理.
執(zhí)行rebase后會(huì)像commit一樣進(jìn)入編輯狀態(tài), 在開始會(huì)是幾個(gè)commit的SHA值, 從上到下是越來越新的commit. 如果沒有比-i指定的心的話會(huì)出現(xiàn)noop.
開始狀態(tài)所有出現(xiàn)的commit前面都是pick. 這個(gè)pick是對(duì)該commit進(jìn)行的操作, 有:
- pick就是說保留該commit, 也可以用縮寫p. (黃色)
- squash, 使用該commit但合并到前一個(gè)老的commit去(常用). 可以用縮寫s代替 (綠色).
- reword, 和pick類似, 但可以修改commit時(shí)的提交信息(中間會(huì)彈出來讓你修改commit).可以用縮寫r代替 (紫紅色).
- edit, 使用commit, 但停下來進(jìn)行修改, 可能用于merge沖突.可以用縮寫e代替.
- fixup, 和squash類似, 但會(huì)舍棄commit信息. 可以用縮寫f (紅色)
- exec, 執(zhí)行shell命令.可以用縮寫x
如果該commit是空commit, 前面會(huì)被注釋掉#. 會(huì)被自動(dòng)刪除.
執(zhí)行完修改后,:wq退出vi, 這時(shí)開始進(jìn)行rebase操作(1/10 這樣倒數(shù)). 中間會(huì)再次彈出修改文件, 此時(shí)是修改commit信息, 可以修改每次commit的信息(如果是fixup會(huì)忽略掉commit提交信息). 最后這個(gè)合并后的新commit顯示的信息可能是多個(gè)commit的集合(多行).不想修改或改完后直接:wq退出vi即可.
所以都完成后需要一次強(qiáng)制的push, 要加入--force覆蓋掉github上的commit.git push --force
例如我上面-i d1會(huì)修改3個(gè)commit, 保留最老最上最靠近d1的c (用reword或者pick都可以),其余a1和b1合并掉(squash或者fixup).最后生成一個(gè)新commit叫c2(就是3個(gè)合在一起了).所以從新到舊有c2, d1.