這是一個系列文章,介紹學習 Git 的一個小游戲 - githug,如果你是第一次看到,請先閱讀:
闖過這 54 關,點亮你的 Git 技能樹
闖過這 54 關,點亮你的 Git 技能樹(一)
闖過這 54 關,點亮你的 Git 技能樹(二)
闖過這 54 關,點亮你的 Git 技能樹(三)
闖過這 54 關,點亮你的 Git 技能樹(四)
沒想到第四彈在「開發者頭條」上獲得了 300 多個贊。
看來大家對這個小游戲挺感興趣的,而且還有不少朋友在促更,今天就讓我們一鼓作氣打通最后的 14 關吧。
同樣,如對任何命令使用有疑問請看第一篇里的推薦教程,也歡迎在下面留言,我會盡力提供幫助的。
第四十一關
項目時間長了,git
倉庫會慢慢變大,如何優化?
這個場景日常很少用到,而且不是必須用的,所以沒什么概念。來看一下提示吧!
打開幫助之后輸入 /redundant
搜索關鍵字,一下就找到了一個 -d
的參數。
第四十二關
有一次,我正在一個特性分支上開發一個功能,提交了幾次代碼,就在準備結束合并代碼的時候,然后產品經理說這個需求不用做了。
我強壓下心里奔騰的一萬只草泥馬,準備刪除這個分支,但在刪除之前想到有一個 commit 是對一個工具類的修改,還是有用的。
這是我就需要從特性分支上把這個 commit 摘出來,合到 master 分支上,再刪除特性分支。
這個題目就是類似的場景,先來看看特性分支叫什么,然后找到需要「摘」出來的那個 commit:
查看了一下 log
命令的幫助,發現可以指定分支,這樣就省去了 checkout 到 new-feature 分支的步驟。
上圖中最后的一次提交就是我們需要「摘」出來的,復制它的 Hash。
順利過關!
第四十三關
我們在開發的過程中,為了不影響當前正在做的事情,會把一些不那么緊急的任務使用 TODO
注釋在代碼里,現代的 IDE 都能幫我們識別這些注釋并在一個單獨的窗口中羅列出來。
當然,不借助 IDE,光憑系統命令或 git 命令也是可以做到的。
第四十四關
查看 log,git log --oneline
,可以看到中間的 commit message 有一個拼寫錯誤。
看一下提示,可以在 rebase 的時候指定 -i
參數:
查看一下幫助就知道是 interactive
的意思:
在打開的 Vim 窗口中將第一行的 pick
改為 r
,表示:使用 commit,并且修改 commit message。
修正拼寫錯誤的 coommit
。
第四十五關
當我使用 TDD 方式進行開發,會進行非常頻繁小步的提交,這樣在其他同事看來就缺乏完整性,也會增加后續維護成本。
所以 git 讓我可以在 push 到遠程倉庫之前,對 commit 歷史進行修改合并,把多個 commit 合并成一個。
用 git log --oneline
看一下提交記錄:
從提交記錄可以看出,它提示我們將最后三個 commit 都合并到第二個 commit - Adding README 中。
接著執行 git rebase -i HEAD~4
:
第一個 commit 為 pick
,后三個改為 s
,意思是使用這個 commit,但將它合并到前一個 commit 中去。
保存退出,會提示我們編輯 commit message,再次保存退出后,查看一下提交記錄:
第四十六關
題目要求在 merge 特性分支時,把所有的新提交合并成一個,先來看看 master 分支當成的狀態:git log --oneline
:
再看一下 git log long-feature-branch --oneline
:
完整過關命令如下:
最后 master 分支狀況如圖,只用一個 commit,包含了 long-feature-branch
所有的修改:
第四十七關
提交順序錯亂時,也可以使用 git rebase -i
進行調整。
先看看 Log,最后兩個提交顛倒了位置:
執行 git rebase -i HEAD~2
,將兩行 pick xxx 代碼交換位置即可。
第四十八關
看一下歷史:
代碼中不知道什么時候引入了 bug,不過沒關系,我們有自動化測試。
我們可以不斷手工 checkout 到某個 commit,結合二分法查找快速定位到引入 bug 的那一個 commit。
不過這種純手工重復的事情,已經包含在 git 的命令中了,就是 bisect
讀一下 git help bisect
,可以找到這個例子:
我們知道 HEAD 的代碼是有問題的,而第一個 commit 的代碼是沒問題的。
通過 git log
獲得第一個 commit 的 Hash,就可以執行 bisect 命令:
紅線部分已經清楚地告訴我們是哪個 commit 引入的 bug 了。
第四十九關
有時開發了一個特性沒提交,接著又開發了另一個特性。
作為一個自律的程序員,應該是要分兩次提交的,如果修改的是不同的文件,那可以輕松地通過 add 不同的文件進行兩次提交。
但這次好巧不巧的是居然修改了同一個文件,怎么辦?看看提示:
原來 git add 的最小粒度不是「文件」,而是 hunk(代碼塊)。git help add
然后查找 hunk
:
執行如下命令:
Git 會讓我們有機會選擇對每一個 hunk 做什么樣的操作。這里修改同一個位置,在一個 hunk 里,根據提示我們還要輸入 e
手工編輯 hunk。
將第 5 行刪除,保存退出,再看當前狀態:git diff --cached
:
git diff
:
目的達到了,過關:
第五十關
正在特性分支上開發一個功能,被頭兒叫去修了一個緊急的 bug,修完后發現:媽蛋,那個特性分支叫啥?忘記了!
當然,作為一個自律的程序員,一般是不是出現這樣的場景的。
這種情況說明分支命名太沒有規律,或者分支太多,不然可以通過 git branch
看一下,也能很快找到特性分支。
先看一下提示吧:
哦,原來有個命令叫 git reflog
,來看看幫助文檔 - git help reflog
,看起來這個命令非常強大,不過我們這里只用到簡單用法就可以了:
上圖中第二行就顯示了我們之前工作的特性分支。
第五十一關
有時代碼 push 到遠程倉庫后發現某一塊代碼有問題,我們可以通過 revert
命令將特定 commit 完全恢復。
首先我們要找到需要 revert 的 commit 的 hash:
完全過程如下:
第五十二關
剛剛把最新的一次提交給毫無保留的扔掉,馬上就改了主意,怎么辦?世界上有后悔藥嗎?
有的,只要進行 git 版本控制的一切都能找得回來。看下提示先:
提示說被我們拋棄的那個 commit 像孤魂野鬼一樣在外游蕩,還沒有被鬼差送入地獄,我們還能通過 git reflog
找到它的代號。
找到它的 Hash 后就通過 cherry-pick 將它找回來:
第五十三關
沖突合并是使用版本控制非常常見的了,居然在這么靠后的位置才出來。
編輯沖突的文件 poem.txt,刪除 Git 添加的標識沖突的行。
別忘了,還要 git add poem.txt
然后 git commit
。
第五十四關
submodule 是 Git 組織大型項目的一種方式,通常可把第三方依賴作為 submodule 包含進來,這個 submodule 本身也是一個獨立的 Git 項目。
第五十五關
最后這一關并非測試使用 GitHub 的能力,而是期望大家貢獻代碼,包括增加更多關卡,修復 Bug 或者完善文檔。
我當初是準備翻譯中文版,結果工作量不小,拖的太久最后不了了之了。
希望你能對開源社區貢獻自己的一分力量!哪怕 Star
一下也是對作者莫大的鼓舞!
總結
終于完結了,謝謝你這么耐心一路跟著操練下來,希望你也像我一樣從這個游戲里收獲很多。
如果你喜歡這個系列文章,將它們分享給你的同事好友,也是對我最大的鼓勵!
如果有什么意見反饋,歡迎評論留言,我一定回復。
如果你發現有好的學習某技術的游戲或教程,歡迎來到「軟件匠藝社區」 與大家分享!