Git
Chapters ▾ 2nd Edition

2.3 Git 基礎 - 檢視提交的歷史記錄

檢視提交的歷史記錄

在產生數筆提交(commit)或者克隆(clone)一個已有歷史記錄的版本庫之後,你或許會想要檢視之前發生過什麼事; 最基本也最具威力的工具就是 git log 命令。

以下範例使用一個非常簡單的「simplegit」專案做展示; 欲取得此專案,執行:

$ git clone https://github.com/schacon/simplegit-progit

在此專案目錄內執行 git log,你應該會看到類似以下訊息:

$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    removed unnecessary test

commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 10:31:28 2008 -0700

    first commit

預設情況(未加任何選項)git log 以反向的時間順序列出版本庫的提交歷史記錄——也就是說最新的提交會先被列出來; 如你所見,它也會列出每筆提交的 SHA-1 校驗碼、作者名字及電子郵件、寫入日期以及提交訊息。

git log 命令有大量且多樣的選項,能精確地找出你想搜尋的結果; 在這裡,我們會展示一些最受歡迎的選項。

最有用的選項之一是 -p,用來顯示每筆提交所做的修改內容; 你還可以加上 -2 選項,限制只輸出最後兩筆提交內容。

$ git log -p -2
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

diff --git a/Rakefile b/Rakefile
index a874b73..8f94139 100644
--- a/Rakefile
+++ b/Rakefile
@@ -5,7 +5,7 @@ require 'rake/gempackagetask'
 spec = Gem::Specification.new do |s|
     s.platform  =   Gem::Platform::RUBY
     s.name      =   "simplegit"
-    s.version   =   "0.1.0"
+    s.version   =   "0.1.1"
     s.author    =   "Scott Chacon"
     s.email     =   "schacon@gee-mail.com"
     s.summary   =   "A simple gem for using Git in Ruby code."

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    removed unnecessary test

diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index a0a60ae..47c6340 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -18,8 +18,3 @@ class SimpleGit
     end

 end
-
-if $0 == __FILE__
-  git = SimpleGit.new
-  puts git.show
-end
\ No newline at end of file

這個選項除了顯示相同的資訊以外,還會在每筆提交資訊後面附加每個修改檔案的差異內容(譯註:使用 - + 來表示差異,- 是刪除行,+ 是新增行;未修改的上下文資訊預設是三行,用來定位有修改的地方); 對於「程式碼審核」或「快速瀏覽」協同工作者所新增的一系列提交內容,這是非常有幫助的。 你也可以使用 git log 提供的一系列「摘要」選項; 例如:若想檢視每筆提交簡略的統計資訊,你可以使用 --stat 選項:

$ git log --stat
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

 Rakefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    removed unnecessary test

 lib/simplegit.rb | 5 -----
 1 file changed, 5 deletions(-)

commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 10:31:28 2008 -0700

    first commit

 README           |  6 ++++++
 Rakefile         | 23 +++++++++++++++++++++++
 lib/simplegit.rb | 25 +++++++++++++++++++++++++
 3 files changed, 54 insertions(+)

如你所見,--stat 選項在每筆提交訊息的下方列出「被更動的檔案」、「總共有多少檔案被更動」、「這些檔案中有多少行被加入或移除」; 它也會在最後印出總結訊息。

另一個實用的選項是 --pretty, 用來改變原本預設輸出的格式; 有數個內建的選項供你選用, 其中 oneline 選項將每一筆提交顯示成單獨一行,對於檢視大量的提交時很有用; 更進一步,shortfullfuller 選項輸出的格式大致相同,但分別會少一些或者多一些資訊。

$ git log --pretty=oneline
ca82a6dff817ec66f44342007202690a93763949 changed the version number
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test
a11bef06a3f659402fe7563abf99ad00de2209e6 first commit

最有趣的選項是 format,讓你可以指定自訂的輸出格式; 當需要輸出給機器分析時特別有用——因為明確地指定了格式,即可確定它不會因為更新 Git 而被更動:

$ git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 6 years ago : changed the version number
085bb3b - Scott Chacon, 6 years ago : removed unnecessary test
a11bef0 - Scott Chacon, 6 years ago : first commit

git log --pretty=format 實用選項 列出 format 一些更實用的選項。

表格 1. git log --pretty=format 實用選項
選項 輸出說明

%H

該提交 SHA-1 雜湊值

%h

該提交簡短的 SHA-1 雜湊值

%T

「樹(tree)」物件的 SHA-1 雜湊值

%t

「樹」物件簡短的 SHA-1 雜湊值

%P

親代(parent)提交的 SHA-1 雜湊值

%p

親代提交簡短的 SHA-1 雜湊值

%an

作者名字

%ae

作者電子郵件

%ad

作者日期(依據 --date 選項值而有不同的格式)

%ar

作者日期,相對時間格式。

%cn

提交者名字

%ce

提交者電子郵件

%cd

提交者日期

%cr

提交者日期,相對時間格式。

%s

標題

你可能會好奇「作者(author)」與「提交者(committer)」之間的差別, 作者是最初修改的人,而提交者則是最後套用該工作成果的人; 因此,如果你送出某個專案的補綴,而該專案其中一個核心成員套用該補綴,則你與該成員都有功勞——你是作者,而該成員則是提交者。 我們會在 分散式的 Git 提到更多它們之間的差別。

onelineformat 和另一個 log 選項 --graph 結合在一起使用時將特別有用, 該選項會附加一個還不錯的 ASCII 圖形用來顯示分支及合併的歷史。

$ git log --pretty=format:"%h %s" --graph
* 2d3acf9 ignore errors from SIGCHLD on trap
*  5e3ee11 Merge branch 'master' of git://github.com/dustin/grit
|\
| * 420eac9 Added a method for getting the current branch.
* | 30e367c timeout code and tests
* | 5a09431 add timeout protection to grit
* | e1193f8 support for heads with slashes in them
|/
* d6016bc require time for xmlschema
*  11d191e Merge branch 'defunkt' into local

當下一個章節談到分支(branching)和合併(merging)時,這種輸出型式將會變得更為有趣。

這些只是一些簡單的 git log 格式化輸出選項——還有更多其它的; git log 的常用選項 列出我們目前涵蓋的以及一些你可能常常會用到的格式化選項,以及它們會如何改變 log 命令的輸出格式。

表格 2. git log 的常用選項
選項 說明

-p

顯示每筆提交的補綴。

--stat

顯示每筆提交中更動檔案的統計及摘要資訊。

--shortstat

只顯示 --stat 提供的的訊息中關於更動、插入、刪除的文字。

--name-only

在提交訊息後方顯示更動的檔案列表。

--name-status

在檔案列表顯示「新增」、「更動」、「刪除」等資訊。

--abbrev-commit

只顯示 SHA-1 校驗碼的前幾位數,而不是顯示全部 40 位數。

--relative-date

以相對時間格式顯示日期(例如:「2 weeks ago」),而不是使用完整的日期格式。

--graph

在輸出的日誌旁邊顯示分支及合併歷史的 ASCII 圖形。

--pretty

以其它格式顯示提交。選項包括 oneline、short、full、fuller 及可自訂格式的 format。

限制日誌的輸出

除了輸出格式的選項以外,git log 還有一些有用的輸出限制選項——也就是讓你能夠只顯示一個子集合的提交; 你先前已看過其中一個——用 -2 選項只顯示最後二筆提交, 事實上,你可以用 -<n>,其中 n 是任意整數,用來顯示最後 n 筆提交; 實際上,你可能不太會那麼常用到它,因為 Git 預設把輸出導向分頁器,所以你一次只能看到一頁的日誌輸出內容。

然而,像 --since--until 這些限制時間的選項就很有用; 例如,以下命令列出最近兩週以來的提交:

$ git log --since=2.weeks

這個命令支援各種格式——你可以指定特定的日期格式(例如:"2008-01-15"),或者相對日期格式(例如:"2 years 1 day 3 minutes ago")。

你也可以過濾列表中符合某些搜尋條件的提交; --author 選項允許你過濾特定作者,而 --grep 選項允許你以關鍵字搜尋提交訊息。 (注意:如果你想要同時比對作者及提交訊息,你必需加上 --all-match,否則只要滿足其中一個條件的提交都會被列出來。)

另一個實用的選項是 -S,用來尋找所修改的內容中被加入或移除某字串的提交; 擧例,如果你想要找出最後一個有加入或移除某個特定函數參照的提交,你可以使用:

$ git log -Sfunction_name

最後一個實用的 git log 過濾選項是路徑, 如果你指定一個目錄或檔名,你可以列出只對這些檔案有修改記錄的提交; 這個選項永遠放在最後一個,並且通常使用二個連接號(--)將路徑與其它選項隔開。

我們在 Options to limit the output of git log 中列出這些選項和一些其它常用選項供你參考。

表格 3. Options to limit the output of git log
選項 說明

-(n)

只顯示最後 n 筆提交。

--since, --after

列出特定日期後的提交。

--until, --before

列出特定日期前的提交。

--author

列出作者名字符合指定字串的提交。

--committer

列出提交者名字符合指定字串的提交。

--grep

列出提交訊息中符合指定字串的提交。

-S

列出修改檔案中有加入或移除指定字串的提交。

例如:如果你想檢視 Git 原始碼的測試檔案中(譯註:它們都放在資料夾 t/),由 Junio Hamano 在 2008 年 10 月份所提交,但不包含「合併提交」的提交。可執行以下的命令:

$ git log --pretty="%h - %s" --author=gitster --since="2008-10-01" \
   --before="2008-11-01" --no-merges -- t/
5610e3b - Fix testcase failure when extended attributes are in use
acd3b9e - Enhance hold_lock_file_for_{update,append}() API
f563754 - demonstrate breakage of detached checkout with symbolic link HEAD
d1a43f2 - reset --hard/read-tree --reset -u: remove unmerged new paths
51a94af - Fix "checkout --track -b newbranch" on detached HEAD
b0ad11e - pull: allow "git pull origin $something:$current_branch" into an unborn branch

在 Git 原始碼接近 40,000 筆提交歷史記錄中,這個命令列出其中符合條件的 6 筆。