-
1. 起步
-
2. Git 基礎
-
3. Git 分支
-
4. 伺服器上的 Git
- 4.1 協議
- 4.2 在伺服器上部署 Git
- 4.3 生成 SSH 公鑰
- 4.4 架設伺服器
- 4.5 Git Daemon
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 第三方託管服務
- 4.10 小結
-
5. 分散式 Git
-
A1. 附錄 A: Git 在其他環境
- A1.1 圖形介面
- A1.2 Visual Studio 中的 Git
- A1.3 Visual Studio Code 中的 Git
- A1.4 IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine 中的 Git
- A1.5 Sublime Text 中的 Git
- A1.6 Bash 中的 Git
- A1.7 Zsh 中的 Git
- A1.8 PowerShell 中的 Git
- A1.9 小結
-
A2. 附錄 B: 在應用程式中嵌入 Git
-
A3. 附錄 C: Git 命令
7.10 Git 工具 - 使用 Git 除錯
使用 Git 除錯
除了主要用於版本控制之外,Git 還提供了一些命令來幫助你除錯原始碼專案。由於 Git 旨在處理幾乎任何型別的內容,這些工具都相當通用,但當出現問題時,它們通常可以幫助你查詢錯誤或問題的根源。
檔案標註
如果你在程式碼中找到了一個 bug,並且想知道它是何時以及為何引入的,檔案標註通常是你最好的工具。它會顯示哪個提交是最後修改檔案中每行內容的。因此,如果你發現程式碼中的某個方法有 bug,你可以使用 git blame
命令標註該檔案,以確定是哪個提交引入了該行。
以下示例使用 git blame
命令來確定 Linux 核心頂層 Makefile
中哪些行是由哪個提交和提交者負責的,並且進一步使用 -L
選項將標註輸出限制在該檔案的 69 到 82 行。
$ git blame -L 69,82 Makefile
b8b0618cf6fab (Cheng Renquan 2009-05-26 16:03:07 +0800 69) ifeq ("$(origin V)", "command line")
b8b0618cf6fab (Cheng Renquan 2009-05-26 16:03:07 +0800 70) KBUILD_VERBOSE = $(V)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 71) endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 72) ifndef KBUILD_VERBOSE
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 73) KBUILD_VERBOSE = 0
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 74) endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 75)
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 76) ifeq ($(KBUILD_VERBOSE),1)
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 77) quiet =
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 78) Q =
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 79) else
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 80) quiet=quiet_
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 81) Q = @
066b7ed955808 (Michal Marek 2014-07-04 14:29:30 +0200 82) endif
請注意,第一個欄位是最後修改該行的提交的部分 SHA-1 值。接下來的兩個欄位是從該提交中提取的值——作者姓名和該提交的創作日期——這樣你就可以輕鬆地看到是誰以及何時修改了那一行。之後是行號和檔案內容。還要注意 ^1da177e4c3f4
提交行,其中 ^
字首表示在倉庫的初始提交中引入的行,並且此後一直未更改。這有點令人困惑,因為你現在已經看到了 Git 使用 ^
修改提交 SHA-1 的至少三種不同方式,但在這裡它就是這個意思。
Git 的另一個酷炫之處在於它不顯式跟蹤檔案重新命名。它記錄快照,然後嘗試事後隱式地找出哪些檔案被重新命名了。其中一個有趣的功能是,你還可以要求它找出各種程式碼移動。如果你向 git blame
命令傳入 -C
選項,Git 會分析你正在標註的檔案,並嘗試找出其中程式碼片段最初來自何處(如果它們是從其他地方複製過來的)。例如,假設你正在將名為 GITServerHandler.m
的檔案重構為多個檔案,其中一個是 GITPackUpload.m
。透過使用 -C
選項對 GITPackUpload.m
進行 blame 操作,你可以看到程式碼的這些部分最初來自哪裡。
$ git blame -C -L 141,153 GITPackUpload.m
f344f58d GITServerHandler.m (Scott 2009-01-04 141)
f344f58d GITServerHandler.m (Scott 2009-01-04 142) - (void) gatherObjectShasFromC
f344f58d GITServerHandler.m (Scott 2009-01-04 143) {
70befddd GITServerHandler.m (Scott 2009-03-22 144) //NSLog(@"GATHER COMMI
ad11ac80 GITPackUpload.m (Scott 2009-03-24 145)
ad11ac80 GITPackUpload.m (Scott 2009-03-24 146) NSString *parentSha;
ad11ac80 GITPackUpload.m (Scott 2009-03-24 147) GITCommit *commit = [g
ad11ac80 GITPackUpload.m (Scott 2009-03-24 148)
ad11ac80 GITPackUpload.m (Scott 2009-03-24 149) //NSLog(@"GATHER COMMI
ad11ac80 GITPackUpload.m (Scott 2009-03-24 150)
56ef2caf GITServerHandler.m (Scott 2009-01-05 151) if(commit) {
56ef2caf GITServerHandler.m (Scott 2009-01-05 152) [refDict setOb
56ef2caf GITServerHandler.m (Scott 2009-01-05 153)
這非常有用。通常,你會得到複製程式碼的那個提交作為原始提交,因為那是你首次在此檔案中觸及這些行。Git 會告訴你你編寫這些行的原始提交,即使它是在另一個檔案中。
二分查詢
如果你一開始就知道問題在哪裡,標註檔案會有所幫助。但如果你不知道是什麼導致了問題,而且自從程式碼上次正常工作以來已經有幾十甚至數百個提交,你很可能會求助於 git bisect
。bisect
命令透過你的提交歷史執行二分查詢,幫助你儘快識別是哪個提交引入了問題。
假設你剛剛將程式碼釋出到生產環境,收到了關於開發環境中未出現的問題的 bug 報告,並且你無法想象程式碼為什麼會那樣執行。你回到程式碼,發現可以重現該問題,但無法弄清楚哪裡出了問題。你可以對程式碼進行 二分查詢 來找出原因。首先執行 git bisect start
開始查詢,然後使用 git bisect bad
告訴系統你當前所在的提交是損壞的。接著,你必須使用 git bisect good <good_commit>
告訴 bisect 上一個已知的良好狀態是什麼時候。
$ git bisect start
$ git bisect bad
$ git bisect good v1.0
Bisecting: 6 revisions left to test after this
[ecb6e1bc347ccecc5f9350d878ce677feb13d3b2] Error handling on repo
Git 發現你標記為最後一個良好提交 (v1.0) 和當前損壞版本之間大約有 12 個提交,它為你檢出了中間的那個提交。此時,你可以執行你的測試,看看問題是否存在於這個提交中。如果存在,那麼它是在這個中間提交之前某個時候引入的;如果不存在,那麼問題是在這個中間提交之後某個時候引入的。結果發現這裡沒有問題,你透過輸入 git bisect good
告訴 Git,然後繼續你的查詢之旅。
$ git bisect good
Bisecting: 3 revisions left to test after this
[b047b02ea83310a70fd603dc8cd7a6cd13d15c04] Secure this thing
現在你在另一個提交上,它介於你剛剛測試的提交和你的壞提交之間。你再次執行測試,發現這個提交是損壞的,所以你用 git bisect bad
告訴 Git。
$ git bisect bad
Bisecting: 1 revisions left to test after this
[f71ce38690acf49c1f3c9bea38e09d82a5ce6014] Drop exceptions table
這個提交是好的,現在 Git 擁有了確定問題是在哪裡引入所需的所有資訊。它會告訴你第一個損壞提交的 SHA-1 值,並顯示一些提交資訊以及在該提交中修改了哪些檔案,這樣你就可以找出可能引入此 bug 的原因。
$ git bisect good
b047b02ea83310a70fd603dc8cd7a6cd13d15c04 is first bad commit
commit b047b02ea83310a70fd603dc8cd7a6cd13d15c04
Author: PJ Hyett <pjhyett@example.com>
Date: Tue Jan 27 14:48:32 2009 -0800
Secure this thing
:040000 040000 40ee3e7821b895e52c1695092db9bdc4c61d1730
f24d3c6ebcfc639b1a3814550e62d60b8e68a8e4 M config
完成後,你應該執行 git bisect reset
來將你的 HEAD 重置到你開始前的狀態,否則你會陷入一個奇怪的狀態。
$ git bisect reset
這是一個強大的工具,可以在幾分鐘內幫助你檢查數百個提交以查詢引入的 bug。事實上,如果你有一個指令碼,當專案良好時退出碼為 0,當專案損壞時退出碼為非 0,你可以完全自動化 git bisect
。首先,你再次透過提供已知的損壞和良好提交來告訴它二分查詢的範圍。如果你願意,可以透過 bisect start
命令列出它們,先列出已知的損壞提交,再列出已知的良好提交。
$ git bisect start HEAD v1.0
$ git bisect run test-error.sh
這樣做會自動在每個檢出的提交上執行 test-error.sh
,直到 Git 找到第一個損壞的提交。你也可以執行類似 make
或 make tests
或任何能為你執行自動化測試的命令。