章节 ▾ 第二版

2.3 Git 基础 - 查看提交历史

查看提交历史

在你创建了若干次提交,或者克隆了一个含有提交历史的仓库之后,你可能希望回顾一下所发生的事情。要做到这一点,最基本且最强大的工具就是 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

    Change version number

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

    Remove unnecessary test

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

    Initial commit

默认情况下,不带任何参数的 git log 命令会按逆时间顺序(即最新提交在前)列出该仓库中的提交。如你所见,此命令会列出每个提交的 SHA-1 校验和、作者姓名和电子邮件、提交日期以及提交信息。

git log 命令提供了大量各式各样的选项,可以精确地显示你想要查找的信息。在这里,我们将向你展示一些最常用的选项。

其中一个更有用的选项是 -p--patch,它会显示每次提交引入的差异(补丁输出)。你还可以限制显示的日志条目数量,例如使用 -2 只显示最后两个条目。

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

    Change 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

    Remove 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

此选项显示相同的信息,但每个条目后都直接跟着一个差异。这对于代码审查或快速浏览协作者添加的一系列提交中发生的事情非常有用。你还可以将一系列摘要选项与 git log 一起使用。例如,如果你想查看每个提交的缩略统计信息,可以使用 --stat 选项

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

    Change 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

    Remove 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

    Initial commit

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

如你所见,--stat 选项会在每个提交条目下方打印一个修改文件的列表,显示有多少文件被更改,以及这些文件中添加和删除了多少行。它还会将信息的摘要放在末尾。

另一个非常有用的选项是 --pretty。此选项会将日志输出更改为默认格式以外的格式。有几个预设的选项值可供你使用。此选项的 oneline 值会将每个提交打印在一行上,如果你要查看大量提交,这会非常有用。此外,shortfullfuller 值会以大致相同的格式显示输出,但信息量分别更少或更多。

$ git log --pretty=oneline
ca82a6dff817ec66f44342007202690a93763949 Change version number
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Remove unnecessary test
a11bef06a3f659402fe7563abf99ad00de2209e6 Initial commit

最有趣的选项值是 format,它允许你指定自己的日志输出格式。这在为机器解析生成输出时特别有用——因为你明确指定了格式,所以你确切知道它不会随 Git 的更新而改变。

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

git log --pretty=format 的有用格式占位符 列出了 format 接受的一些更有用的占位符。

表 1. git log --pretty=format 的有用格式占位符
占位符 输出描述

%H

提交哈希值

%h

缩写提交哈希值

%T

树哈希值

%t

缩写树哈希值

%P

父提交哈希值

%p

缩写父提交哈希值

%an

作者姓名

%ae

作者电子邮件

%ad

作者日期(格式遵循 --date=option 选项)

%ar

作者日期,相对格式

%cn

提交者姓名

%ce

提交者电子邮件

%cd

提交者日期

%cr

提交者日期,相对格式

%s

主题

你可能想知道 作者提交者 之间的区别。作者是最初编写作品的人,而提交者是最后应用该作品的人。因此,如果你向一个项目提交一个补丁,然后一位核心成员应用了该补丁,你们两人都会获得贡献——你作为作者,核心成员作为提交者。我们将在 分布式 Git 中更详细地介绍这种区别。

onelineformat 选项值与另一个名为 --graphlog 选项结合使用时特别有用。此选项会添加一个漂亮的小型 ASCII 图形,显示你的分支和合并历史

$ git log --pretty=format:"%h %s" --graph
* 2d3acf9 Ignore errors from SIGCHLD on trap
*  5e3ee11 Merge branch 'master' of https://github.com/dustin/grit.git
|\
| * 420eac9 Add 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

当我们进入下一章的分支和合并时,这类输出会变得更加有趣。

这些只是 git log 的一些简单的输出格式化选项——还有很多其他的。git log 的常用选项 列出了我们目前已介绍的选项,以及一些其他可能有用的常用格式化选项,以及它们如何改变 log 命令的输出。

表 2. git log 的常用选项
选项 描述

-p

显示每个提交引入的补丁。

--stat

显示每个提交中修改文件的统计信息。

--shortstat

仅显示 --stat 命令中的更改/插入/删除行。

--name-only

在提交信息后显示修改文件的列表。

--name-status

显示受影响的文件列表,同时包含添加/修改/删除信息。

--abbrev-commit

只显示 SHA-1 校验和的前几个字符,而不是全部 40 个字符。

--relative-date

以相对格式(例如,“2 周前”)显示日期,而不是使用完整的日期格式。

--graph

在日志输出旁边显示分支和合并历史的 ASCII 图形。

--pretty

以备选格式显示提交。选项值包括 onelineshortfullfullerformat(你可以指定自己的格式)。

--oneline

同时使用 --pretty=oneline --abbrev-commit 的简写形式。

限制日志输出

除了输出格式化选项之外,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 选项允许你在提交信息中搜索关键字。

注意

你可以指定 --author--grep 搜索条件的多个实例,这将把提交输出限制为匹配 任何 --author 模式和 任何 --grep 模式的提交;然而,添加 --all-match 选项会进一步将输出限制为只匹配 所有 --grep 模式的提交。

另一个非常有用的过滤器是 -S 选项(俗称 Git 的“pickaxe”选项),它接受一个字符串,并只显示那些改变了该字符串出现次数的提交。例如,如果你想找到最后一次添加或删除特定函数引用的提交,你可以调用

$ git log -S function_name

传递给 git log 作为过滤器的最后一个真正有用的选项是路径。如果你指定一个目录或文件名,你可以将日志输出限制为对这些文件引入更改的提交。这总是最后一个选项,通常前面会加上双破折号 (--) 来将路径与选项分开

$ git log -- path/to/file

限制 git log 输出的选项 中,我们将列出这些以及其他一些常用选项供你参考。

表 3. 限制 git log 输出的选项
选项 描述

-<n>

只显示最后 n 个提交。

--since, --after

将提交限制为在指定日期之后进行的提交。

--until, --before

将提交限制为在指定日期之前进行的提交。

--author

只显示作者条目匹配指定字符串的提交。

--committer

只显示提交者条目匹配指定字符串的提交。

--grep

只显示提交信息中包含指定字符串的提交。

-S

只显示添加或删除与字符串匹配的代码的提交。

例如,如果你想查看 Git 源代码历史中哪些修改了测试文件的提交是由 Junio Hamano 在 2008 年 10 月提交且不是合并提交的,你可以运行类似这样的命令

$ git log --pretty="%h - %s" --author='Junio C Hamano' --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 次提交。

提示
阻止显示合并提交

根据你仓库中使用的工作流,你的日志历史中可能很大一部分提交只是合并提交,这些提交通常信息量不大。为了防止合并提交使你的日志历史变得杂乱,只需添加 log 选项 --no-merges 即可。

scroll-to-top