不會 Git,千萬別說你會版本控制!Git 進階用法與最佳實踐

在〈Git與GitHub介紹,軟體版本控制基本教學〉一文中,我們對於 Git 是什麼,已經有了初步的認識,也提到了在 Git 版本控制中,幾個相當常用的 command,提交修改使用 git commit,拉取遠端分支修改用 git pull,把local change 推向遠端用 git push 等等。

但除了這些之外,你還知道 git 還有許多實用的功能嗎?

蛤?不知道?不知道也沒關係!讓我們一起來看看。

三分鐘小測驗,找到線上自學程式的高效入口

Git 進階用法(Advanced usage for Git)

1. 暫存 local branch 修改

git stash

git stash 是一個相當實用的 command,適用於當你如果想要在不同 branch 間切換,但是又不想把你目前的 change 加進 git 中時。

當下了 git stash 之後,git 便會把你目前所有的修改暫存起來,把 work tree 還原成最初的狀態。

但到這裡可能會有點疑惑,那如果我重新開機的話,存進 stash 中的修改還會在嗎?答案是肯定的,因為 stash 的紀錄是存在於 git 的紀錄中。

舉例來說,當我修改了一個 app.js 的檔案,但又不想太快把它加進 git 中時:

如上圖所示,我們下了git status命令後,可以看到多了一筆還沒加入git stage中的紀錄。

然而如上圖所示,當我們下了 git stash 的命令之後,可以發現到出現了一行文字 “Saved working directory and index state WIP on master”,之後再查看 git 的狀態後可以發現,狀態還原至尚未進行更改的狀態。但是我們要怎麼把更改叫回來呢?

git stash pop

如果要把更改叫回來的話,我們只要輸入git stash pop 這個指令就可以了!

由於 git stash 可以存不只一個的 stash record,所以pop的意思是彈出最上層的stash record。另外,我們也可以透過 git stash list 查看目前暫存了幾個 local change,如下圖所示。

git stash list

而刪除 stash 也是相當簡單,只要透過 git stash drop 就能刪掉第一筆 stash、git stash clear 刪除所有 stash。

2. 修改 commit 紀錄

在 commit change 時,我相信有一定的機率會發生手速太快導致打錯字的情況發生,這時候可以透過 amend 與 rebase 兩種命令來達成。

git commit –amend -m “Your message.” 只能用來修改最新一筆的 commit 紀錄。

而 git rebase 則可以修改過去的所有 commit,它提供了一個相當友善的互動模式供使用者依照自己的需求回溯紀錄。

舉例來說 git rebase -i 4cdfdea94c9be⋯⋯ 的意思是回溯從現在到 4cdfd 這個 Commit,-i 參數是指要進入 Rebase 指令的「互動模式」。

下完命令後,我們便回到了 test1 所在的 commit。

上面的 pick 意思是「保留這次的 Commit,不做修改」,如果我們想修改 commit message,就會需要把 pick 改成 reword。

ok 這樣就編輯完了,那要如何存檔呢,只要按下 ESC 鍵(代表離開編輯模式)之後再輸入:wq!(q!為離開的意思,再加上 w 代表存檔且離開)進行存檔後,會再彈出另一個編輯器頁面:

我們將原本的 message 從 test2 改為 test2-1 並進行存檔後,又跑出了另一個頁面,這是由於我們總共有兩個 commit 需要修改的緣故。

我們再將 test3 的 message 改成 test3-1。

ok!存檔之後就大功告成了!這時候後我們在用 git log 來看看是否有成功被修改。

git log 上顯示的已經是更新過後的值了。

可以透過以下這張對比圖,可以發現一些微妙的事實:

看起來好像只有改訊息,但並不是只有單純的改字而已。如果你仔細看,那兩次 Commit 的 SHA-1 值都變了,原本是 a14c50e 跟 e0c714f ,現在變成 383ff4a 跟 1473dd2,這兩次的 Commit 根本就是全新的 Commit 物件了。

不過,很重要的一點是,git amend 與 git rebase 修改的前提都是你還沒把 local change 推向遠端的情況下,因為這兩個命令都是在修改既定的事實,如果你已經把更改推向遠端了,再執行這兩種指令,伺服器是會拒絕你的請求的,但如果你真的很想 push 的時候該怎麼辦呢?

很簡單 只要在 git push 時加上 -f 參數就行了,-f 參數代表force push的意思。

git push -f origin <your branch name>

但是!在多人協同開發一個專案的時候,git push -f 是一個非常危險的指令,因為很可能會不小心把別人上傳的 code 整個覆蓋掉,通常只有在單人開發、非常有把握的時候,或者是每個功能都能獨立成個別的 feature branch ,且那條 feature branch 只有你在用的情形下,才會用 git push -f 來強制更新分支。

總而言之,就是要非常小心使用這個命令。

Git 最佳實踐(Best practices for using Git)

以上便是 git 之中的幾個進階用法,不過,使用 git 時有沒有什麼遊戲規則最好要遵守的呢? 答案是有的,雖然 git 的功能真的非常強大,但如果沒有好好維護,反而會使各種紀錄雜亂無章。

在使用 git 時最好遵守以下的幾點原則:

1. 保持每次 commit的 乾淨度、目的性

每次的 commit 應該是可以獨立的,這是什麼意思呢?

我們在開發新功能時,常常會將一個功能 breakdown 成不同的小功能,也就是說,當程式碼完成一個小段落後,就可以進行 commit。最好不要等到完成所有功能才提交修改。

這是由於當錯誤發生,我們可以藉由乾淨的 commit history rollback 至任何一個節點,此舉對於 Debug 會很有幫助,也可以幫助別人在幫你 code review 時,可以清楚的識別各個修改。

另外,如果你有使用專案管理的工具如 Jira 等等,最好在每次 commit 都標示你的 ticket number,訊息也最好涵蓋你做的相關更改。

2. 儘早提交更改

像我們上一點提到的,最好不要等完成所有功能後再一次提交 commit,這是因為 code 的更改越大,潛在的衝突就會越多,儘早提交,我們才可以以最少的 effort 去處理那些可能會發生的衝突。

3.不要隨便更改已發布的 commit history

除非是像打錯 commit message 這種不改不行、可能會造成別人誤會的這種狀況,不然最好不要使用 git rebase 來更改 commit(忘記的同學麻煩回去文章開頭再複習一遍R),雖然它很好用。

4.不要提交自動生成的文件

有許多專案在下完 build code 指令後,常常會 generate 出很多檔案,例如以 java maven 為例,下完 maven clean package 後,就會在 target directory 產生打包完的專案和一堆描述檔。因此,千萬不要把這種自動生成的檔案加入 git 裡面,這是相當沒有意義的。當別人 pull你的 code 下來後,一定會相當疑惑,因為它既不屬於程式碼的一部分,也不是很重要的檔案,不僅浪費空間,也會讓你的 repository 不好維護;所以,最好的方法就是把這些檔案加入gitignore 中,讓 git 自動忽略它們。

以上就是關於 Git 的一些小秘密以及最佳實務,在軟體開發領域中,Git 是一個相當實用的工具,只要善加使用它,將可以使我們的開發事半功倍喔!

Code Review怎麼做?新手工程師如何提升「程式碼品質」