懂 git 的朋友們可能對 git reset,git checkout,甚至是 git reflog 很熟悉,但有沒有遇過需要綜合使用上述指令的場景呢?這邊分享一個我遇到的情境,可以體會到 git 如電玩進度存檔的魔力。
問題發生在 rebase develop 到我的 feature branch 過程中,因為有 conflict 所以手動修改了一些地方,但 rebase 過程中並沒有 trigger 既有的 pre-commit git hook,導致一些 code style 錯誤的地方沒有檢查到(就是該死的空白行),push 上去後被 ci 擋下。但尷尬的是 ci log 並沒有指出是哪一個檔案出問題,此時該怎麼處理呢?
核心概念就是,想辦法讓這次修改的 code 重新被 pre-commit 檢查過,詳細作法如下:
初始狀態
第一步:踢出修改
我們把 feature branch 中這次的修改從 repository 中全部踢出來。因為剛剛我們才 rebase 過 develop branch,所以直接讓 git 去比對兩隻 branch,就能正確 reset
$ git reset --soft develop
這邊使用 –soft 或使用預設的 mixed 都沒有差異,只是修改的 code 一個到 staged files,一個到 working tree。
可以用 git status 確認一下是不是修改過這些檔案
$ git status
On branch feat
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: orange.py
第二步:跑 pre-commit
確認後,直接 commit
$ git commit -m test
馬上就會 trigger pre-commit,立刻看到 fail
此時再使用 status 查看哪些檔案被 pre-commit 修改過
$ git status
On branch feat
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: xxxxx.py
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: xxxxxx.py <= 鬼就是他
第三步:重建 feat branch
知道問題後,我們先重建 feat branch,使用 reflog 查看我們剛剛做過的步驟
$ git reflog
ee05fdc (HEAD -> feat, develop) HEAD@{0}: reset: moving to develop
7014e25 HEAD@{1}: rebase finished: returning to refs/heads/feat
7014e25 HEAD@{2}: rebase: [feat]: add xxxxxx
e4795e4 HEAD@{3}: rebase: [fix]: modify xxxxx
我們現在需要回復到 rebase 完成狀態,所以找到 rebase 指令最後代碼 7014e25,複製起來回到 console 下 reset
$ git reset --hard 7014e25
這邊使用 hard ,讓整個環境像坐時光機一樣回朔到 rebase 完的狀態,此時再去錯誤的檔案隨便加一個空白鍵讓他 commit,pre-commit 就會自動幫你修正啦!
延伸閱讀:
Python 詭譎的 default parameter value ,由踩坑來學習!
被新創公司裁員後,我學到的五件事
參考資料
提升程式碼品質:使用 Pre-Commit (Git Hooks)
[Git] Reset – mixed, hard and soft