Git 冷門技巧集

那些高冷到結凍的神奇指令,我也是看報紙才知道的

Ray Yuan Liou
8 min readOct 31, 2023
What the… ?

繼上次分享的整理 commit 技巧以及 worktree 的使用,最近還發現了一些 git 新奇的使用方式。其中一個是關於在 commit 之中寫筆記,這個功能可以為了特定的 commit 留下額外紀錄。
另一個則是方便 Pair Programming 或是幫忙修正程式碼時實用的技巧,git 可以將 Diff 儲存成 patch 檔案。我們可以將這個 Patch 檔案分享給其他人,其他人就能讀取出 Diff,而不用再另外開 Draft Pull Request 來看 Diff。
最後則是如果程式出問題,我們可以減少至少一半找問題節點的時間!

git notes

git notes 可以為特定的 commit 留下筆記。這個資料預設儲存於本地端,所以不用擔心會影響到其他人。但是,如果我們想要將這份 notes 上傳到 repository,也是可以辦到。

首先,需要找到想要為他留下筆記的 commit hash 值,我們可以透過 git log 來查看 commit 列表。我們以圖中的第二個 commit 為範例:

如果想為 `ce39f016e67a03dd70c304e8cce4bd7f175b1e7d` commit 做筆記,可以使用以下指令:

$ git notes add <you_sha_hash>

以這個範例來說,就會是:

$ git notes add ce39f016e67a03dd70c304e8cce4bd7f175b1e7d

這時文字編輯器會跳出來,我們可以開始寫對於這個 commit 的筆記。
寫完筆記後儲存退出。我們可以透過 git log 指令來看到我們的筆記。
如果 add 不給任何的 hash,則預設都會指到 HEAD (也就是目前的節點)。

可以看到除了原有的 commit message 以外,下面多了一個 Notes: 顯示我們剛剛輸入的筆記資料。
想要來查看目前所有的筆記,可以使用以下指令 (list 可有可無)

$ git notes (list)

這些資料顯示的格式是: 筆記 hash<空格>commit hash

對於一個筆記,我們還有以下這些指令可以使用。這邊都需要指定筆記來源的 commit hash 值,否則預設都是指到 HEAD 的筆記。

$ git notes show <commit_hash>  # 顯示該 commit 的筆記
$ git notes edit <commit_hash> # 修改該 commit 的筆記
$ git notes remove <commit_hash> # 移除該 commit 的筆記
$ git notes prone # 移除到不了的 commit 的筆記

上面有提到 git notes 指令,是建立在本地的筆記。但如果我們想要也可以將這些筆記上傳到版本控制服務,這個指令是:

$ git push origin refs/notes/commits

當我們將筆記上傳上去後,可以用下面這個指令將筆記同步下來:

$ git fetch origin refs/notes/commits:refs/notes/commits

最後,這個功能多冷門呢?冷門到 GitHub 在 2014 年就決定停止顯示 git commit note 🥲,但恭喜大家知道了一個可能連官方都遺忘的高冷功能。

git diff to a patch file

不知道大家在交付一個程式碼建議都怎麼做?目前我們團隊會使用 Draft Pull Request 的功能來看 Diff,但其實 diff 這個指令,比大家想的更有料。

git diff 可以把變更變成一個檔案,我們只要將這個檔案給和我們 Pair Programming 的同事,請他 Apply 上去即可看到 Diff。
假設現在有兩個 branch,我們幫忙同事 Pair Programming,發現一些問題:

調整後 code 的在 optimize_search_result

這個線圖是這樣長的,我們幫忙調整了一些 Code,所以 branch 高度比他高一些。

想將這個多出來的三個節點做成 Diff 給同事參考。如果是過去,可能會先發一個 Draft Pull Request。現在,可以改下這個指令:

$ git diff «target_commit_HASH» > ~/<your_name>.patch

這時,需要知道該對比基準 commit 的 hash 值,以我們的例子來說這個指令就會是這樣:

我們來幫忙調整同事的 branch 😋 也就是 from_colleague 的
$ git diff 6bf4d46e0e002712a73b9a3cc1d16abe2a0d3f1b > ~/draft_patch.patch

使用這個指令後,會在 家目錄 下產生 draft_patch.patch 檔案,我們可以自訂義要產生檔案的地點以及他的名稱。
透過檔案管理器存取這個 .patch 檔案,可以注意到它其實是一個文字檔案。

如果我們 Preview 他

將這個檔案給同事,同事拿到檔案之後可以下這個指令:

$ git apply <your_name>.patch

就會發現變更都已經套用上去了。(別忘了保持 branch 狀態是乾淨)如此一來就可以用自己喜歡的 Diff 工具,或是 IDE 來看相關的變更啦。

例如可以用 fork 來看 Diff

git bisect

最後一個功能則是我的超人 —— bisect,用白話文來解釋這個功能就是利用 binary search 的方式來找到出錯的 commit。

不曉得大家遇到靈異問題的時候都怎麼解呢?通靈找節點?一個一個測試?如果發現上次正常的 commit 已經長的這麼高了,不免有點絕望的感覺。

這時就是最適合大家的超人 — — bisect 出來的時候了!因為 binary search 的特性將我們俄羅斯輪盤的時間複雜度降到了 O(log n),換句話說減少了一半的時間!

但 bisect 有個前提是:必須要先確定哪一個 commit 是運作良好的,找到這個節點之後,就可以開始來 bisect 了!

$ git bisect start <from_hash> <to_hash>

例如,我們確定我們的 app 在 2.1.1 版前沒有某個問題,故先去尋找 2.1.1 版的 commit hash。 (這時打 tag 或 release branch 就很方便)
我們的範例就會像是:

例如 2.1.1 版的 app 是某個行為正常的,就以他為基準點
$ git bisect start HEAD 141ee92615c924695553ad731187cdb16bfe02d8

下了指令之後,git 會告訴我們還剩幾步找到問題節點。這時,請嘗試重現問題,是否還會發生。

git 會提醒我們,還有幾步需要測試

如果問題發生了,請下:

$ git bisect bad

如果問題「沒有發生」,也就是好節點,請下:

$ git bisect good

連續幾次 good、good、bad、bad 之後,很快速地就能找到有問題的節點。最後,git 會告訴我們出問題的節點是哪一個,如此一來就可以來看 Code 查寫錯的地方啦。

開獎

最後,因為目前還在 bisect 模式之下,所以請使用以下指令離開這個模式:

$ git bisect reset

Happy coding! 🙌🏼

延伸閱讀:

  • 整理 Commit 的技巧
    說明如何 rebase,教你合成節點或是拆節點。並說明 squash 和 fixup 的異同,和超酷的 autosquash。
  • worktree 的簡單介紹
    讓資料夾變成其中一個 branch,救火的時候再也不用 stash 或 WIP。

--

--