Git問題集 - rebase


Posted by TempuraEngineer on 2022-12-10

目錄


rebase是什麼

rebase是一個git指令,通常用於合併分支重定分支的base修改commit


rebase和merge有差嗎

rebase merge
難易度 較難
合併時產生commit × ○ (ex: Merge pull request ... from ...、Merge branch ... into ...)
合併後分支的樣子 一條直直的 兩條分支到上面的時候變一條
呈現時間先後 混亂 清楚


git graph - 合併的樣子

一開始git graph長這樣

  • merge

  • rebase


rebase怎麼合併分支

你的分支應該從main的HEAD分出去(在gitgraph上看到會是一條直直的,沒有和main岔開)

但是當有多個分支的時候,若是某個分支PR已過,且先被合併到main時,那你的分支就不再是從main的HEAD分出去了(在gitgraph上看到會是分岔的)

這時會需要使用rebase重新定你的分支的base,步驟如下

  1. 先把遠端的所有分支東西都拉下來
     git fetch —-all
     git pull
    
  2. checkout到rebase的分支

     git checkout 分支名
    
  3. 重新定義你的分支的base為main目前的HEAD
    之後會看到一些原本在你們分支上不存在,或者被修改過的檔案

     git rebase main
    
  4. 如果有衝突先解,然後再丟到暫存區(如果沒衝突不會有這個步驟)
     git add .
    
  5. 繼續rebase(如果沒衝突不會有這個步驟)
     git rebase —-continue
    
  6. 確認你的分支原有的commit都還在後,強制推到你的分支

    如果有少可以cherry-pick
     git push --force
    


rebase怎麼修改commit

調換commit的順序

只有特殊情況會這麼做

  1. 終端機跳到vim模式
     git rebase -i commit編號~
    
  2. 按i進入vim的編輯模式
  3. 把commit整行移到想要的位置
  4. esc跳出編輯模式,shift+:進入指令模式,wq儲存並離開
  5. 推上去
     git push --force
    


多個commit變一個

一開始git graph長這樣,我們要把tempura、ninja、and、samurai合成一個

  1. 終端機跳到vim模式
     git rebase -i commit編號~
    
  2. 按i進入vim的編輯模式
  3. 把想要壓到別的commit裡的commit前面的pick改成s(squash)
  4. esc跳出編輯模式,shift+:進入指令模式,wq儲存並離開
  5. 終端機的vim會跳到詢問是否編輯commit message的畫面
    如果要用其中一個可以把不要的部分刪掉(dd可以直接刪除鼠標所在的那行),如果要修改則按i
  6. shift+:進入指令模式,wq儲存並離開
  7. 推上去
     git push --force
    


一個commit變多個

一個commit裡包含的東西太多,也就是一個commit的顆粒度太大時,如果團隊有code review的機制,這會造成review的困難,所以才要拆分commit

一開始git graph長這樣,我們要把tempura ninja and samurai拆成兩兩一組

  1. 查看要拆的commit的編號
     git log
    
  2. 終端機跳到vim模式
     git rebase -i commit編號~
    
  3. 按i進入vim的編輯模式
  4. 把想要拆開的commit前面的pick改成e(edit)
  5. esc跳出編輯模式,shift+:進入指令模式,wq儲存並離開
  6. 把舊的部分砍下來
    之所以要把舊的部分砍下來是因為這樣commit才會回到暫存區,回到暫存區後才能重新編輯或者commit
     git reset HEAD~
    
  7. 重新commit

  8. 繼續rebase

     git rebase --continue
    
  9. 推上去
     git push --force
    


舊的commit卡在新的PR上怎麼辦

這是因為上次PR用rebase合併分支後沒有把本地分支刪掉,或者重定base

下面只寫要怎麼刪掉重來,重定base可以看前面

  • 刪掉分支重開
  1. 先把本地分支a改名b
     git branch -m 舊分支名 新分支名
    
  2. 刪除本地的分支a
    不用刪除遠端分支是因為合併後它已經和main沒有掛鉤
    雖然遠端分支不會出現在git graph上,但在被git回收掉前還是存在的
     git branch -d 分支名
    
  3. 切到要當base的分支(假設是main)
     git checkout main
    
  4. git branch A / 建立新分支A
     git branch A
    
  5. 將分支A發到遠端
     git push --set-upstream origin 分支名
    
  6. 確認目前本地跟遠端的分支目前有什麼
    git branch --all
    
  7. 把本地分支b的commit複製到新開的遠端分支A

     git cherry-pick commit編號
    

    想改commit message的話可以加上-no-commit flag就不會把原本的貼過來

     git cherry-pick —no-commit commit編號
    
  8. cherry-pick完後把本地的分支b刪掉


rebase失敗搞得一團亂怎麼辦

rebase對於不熟的人相對來說是個比較容易踩雷的指令(我就踩過幾次),如果真的把git graph搞得一團亂弄不回去,還是能放大絕reset

git reset commit編號

reset就是整個砍掉重來,它會把你的commit都砍下來丟回暫存區(預設是mixed的情況來說),這樣就可以把做壞的部分重做了


手殘開到reset hard模式怎麼辦

reset hard模式會導致改過的地方都丟失,不過仍可以使用reflog救回來

  1. 查看reflog的SHA-1編號
    reflog只會在你的本地端存在,所以只要換了電腦就沒了

     git reflog
    
  2. 找到你想回去的commit點的SHA-1編號
  3. 復原
     git reset commit編號 --hard
    


參考資料

git-rebase Documentation
為你自己學git - 把一個Commit拆解成多個Commit


#Git #rebase #squash #cherry-pick #reset #reflog







Related Posts

JavaScript 的判斷式

JavaScript 的判斷式

【 JS筆記 】 e.target 與 e.currentTarget 的差別

【 JS筆記 】 e.target 與 e.currentTarget 的差別

Codewars Kyu 4 Python 3

Codewars Kyu 4 Python 3


Comments