高级 Git 日志
任何版本控制系统的目的都是记录对代码的变更。这使您能够返回项目历史记录,看看谁贡献了什么,找出错误是在哪里引入的,并恢复有问题的变更。但是,如果您不知道如何浏览,那么拥有这些历史记录也没有用。这就是 git log 命令的用武之地。
到目前为止,您应该已经知道用于显示提交的基本 git log 命令了。但是,您可以通过向 git log 传递许多不同的参数来改变这个输出。
git log 的高级功能可以分为两类:格式化每个提交的显示方式,以及筛选输出中包含哪些提交。这两种技能相结合,让您有能力返回您的项目,找到您可能需要的任何信息。
格式化日志输出
首先,本文将介绍格式化 git log
输出的多种方式。其中大多数以标记的形式出现,允许您从 git log
请求更多或更少的信息。
如果您不喜欢默认的 git log
格式,可以使用 git config
别名功能为下面讨论的任何格式化选项创建快捷方式。有关如何设置别名,请参阅 git config 命令。
Oneline
--oneline
标记将每个提交压缩为一行。默认情况下,它只显示提交 ID 和提交消息的第一行。典型的 git log --oneline
输出将类似于下方的内容:
0e25143 Merge branch 'feature'
ad8621a Fix a bug in the feature
16b36c6 Add a new feature
23ad9ad Add the initial code base
这对于获得项目的高级概述非常有用。
相关资料
如何移动完整的 Git 存储库
查看解决方案
了解 Bitbucket Cloud 的 Git
装饰
很多时候,知道每个提交与哪个分支或标记相关联是很有用的。--decorate
标记让 git log
显示指向每次提交的所有引用(例如分支、标签标记等)。
这可以与其他配置选项结合使用。例如,运行 git log --oneline --decorate
会格式化提交历史记录,方式类似于:
0e25143 (HEAD, main) Merge branch 'feature'
ad8621a (feature) Fix a bug in the feature
16b36c6 Add a new feature
23ad9ad (tag: v0.9) Add the initial code base
这让您知道顶层提交也会签出(用 HEAD
表示),它也是 main
分支的尖端。第二次提交有另一个分支指向它,叫做 feature
,最后第四次提交被标记为 v0.9
。
分支、标记、HEAD
和提交历史记录几乎是 Git 存储库中包含的所有信息,因此这可以让您更全面地了解仓库的逻辑结构。
差异
git log
命令包含许多选项,用于显示每次提交的差异。两个最常见的选项是 --stat
和 -p
。
--stat
选项显示每次提交修改的每个文件的插入和删除次数(请注意,修改一行表示为 1 次插入和 1 次删除)。当您想要摘要来总结每次提交引入的变更时,这会很有用。例如,以下提交在 hello.py
文件中添加了 67 行并删除了 38 行:
commit f2a238924e89ca1d4947662928218a06d39068c3
Author: John <john@example.com>
Date: Fri Jun 25 17:30:28 2014 -0500
Add a new feature
hello.py | 105 ++++++++++++++++++++++++-----------------
1 file changed, 67 insertion(+), 38 deletions(-)
文件名旁边的 +
和 -
符号表示每个文件被提交修改的相对变更次数。这让您知道在哪里可以找到每次提交变更。
如果您想查看每次提交引入的实际变更,可以将 -p
选项传递给 git log
。这会输出代表该提交的整个补丁:
commit 16b36c697eb2d24302f89aa22d9170dfe609855b
Author: Mary <mary@example.com>
Date: Fri Jun 25 17:31:57 2014 -0500
Fix a bug in the feature
diff --git a/hello.py b/hello.py
index 18ca709..c673b40 100644
--- a/hello.py
+++ b/hello.py
@@ -13,14 +13,14 @@ B
-print("Hello, World!")
+print("Hello, Git!")
对于有大量变更的提交,生成的输出可能会变得很长而且很笨拙。通常,如果您显示的是完整的补丁,您可能是在搜索特定的变更。为此,您想使用 pickaxe 选项。
Shortlog
git shortlog
命令是 git log
的特殊版本,旨在创建版本公告。它按作者对每个提交分组,并显示每条提交消息的第一行。这是查看谁在做什么的简单方法。
例如,如果两个开发人员为一个项目贡献了 5 次提交,则 git shortlog
的输出可能如下所示:
Mary (2):
Fix a bug in the feature
Fix a serious security hole in our framework
John (3):
Add the initial code base
Add a new feature
Merge branch 'feature'
默认情况下,git shortlog
按作者姓名对输出进行排序,但您也可以传递 -n
选项,按每位作者的提交次数进行排序。
图
--graph
选项绘制一个 ASCII 图,表示提交历史记录的分支结构。它通常与 --oneline
和 --decorate
命令结合使用,以便更容易查看哪个提交属于哪个分支:
git log --graph --oneline --decorate
对于一个只有 2 个分支的简单存储库,这将产生以下结果:
* 0e25143 (HEAD, main) Merge branch 'feature'
|\
| * 16b36c6 Fix a bug in the new feature
| * 23ad9ad Start a new feature
* | ad8621a Fix a critical security issue
|/
* 400e4b7 Fix typos in the documentation
* 160e224 Add the initial code base
星号显示提交在哪个分支上,因此上图告诉我们 23ad9ad
和 16b36c6
提交位于主题分支上,其余的都在 main
分支上。
虽然对于简单的存储库来说,这是一个不错的选择,但对于分支较多的项目,最好使用功能更全的可视化工具,比如 gitk
或 Sourcetree。
自定义格式
对于所有其他 git log
格式化需求,您可以使用 --pretty=format:"
选项。这使您可以使用 printf
风格的占位符随心所欲地显示每个提交。
例如,以下命令中的 %cn
、%h
和 %cd
字符分别替换为提交者名称、缩写的提交哈希和提交者日期。
git log --pretty=format:"%cn committed %h on %cd"
这会导致每次提交都采用以下格式:
John committed 400e4b7 on Fri Jun 24 12:30:04 2014 -0500 John committed 89ab2cf on Thu Jun 23 17:09:42 2014 -0500 Mary committed 180e223 on Wed Jun 22 17:21:19 2014 -0500 John committed f12ca28 on Wed Jun 22 13:50:31 2014 -0500
占位符的完整列表可以在完整格式部分找到,该部分在 git log
手册页中。
除了允许您仅查看您感兴趣的信息外,--pretty=format:"
选项在您尝试将 git log
输出传送到另一个命令中时特别有用。
过滤提交历史记录
格式化每个提交显示方式只是学习 git log
难题的一半。另一半是了解如何浏览提交历史记录。本文的其余部分介绍了一些使用 git log
在项目历史记录中挑选特定提交的高级方法。所有这些都可以与上面讨论的任何格式选项结合使用。
按数量筛选
git log
最基本的筛选选项是限制显示的提交数量。如果您只对最后几次提交感兴趣,这就省去了查看页面中所有提交的麻烦。
您可以通过添加 -
选项来限制 git log
的输出。例如,以下命令将仅显示最近的 3 次提交。
git log -3
按日期筛选
如果您要查找特定时间范围内的提交,则可以使用 --after
或 --before
标记按日期筛选提交。两者都接受各种日期格式作为参数。例如,以下命令仅显示在 2014 年 7 月 1 日(含)之后创建的提交:
git log --after="2014-7-1"
您也可以传递相对引用,比如 "1 week ago"
和 "yesterday"
:
git log --after="yesterday"
要搜索在两个日期之间创建的提交,可以同时提供 --before
和 --after
日期。例如,要显示在 2014 年 7 月 1 日到 2014 年 7 月 4 日之间添加的所有提交,您可以使用以下内容:
git log --after="2014-7-1" --before="2014-7-4"
对于有大量变更的提交,生成的输出可能会变得很长而且很笨拙。通常,如果您显示的是完整的补丁,您可能是在搜索特定的变更。为此,您想使用 pickaxe 选项。
按作者筛选
当您只查找特定用户创建的提交时,请使用 --author
标记。它接受正则表达式,并返回作者与该模式匹配的所有提交。如果您确切地知道您在找谁,您可以使用普通的旧字符串代替正则表达式:
git log --author="John"
这将显示作者名字包含 John 的所有提交。作者姓名不必完全匹配,只需要包含指定的短语即可。
您也可以使用正则表达式来创建更复杂的搜索。例如,以下命令搜索由 Mary 或 John 提交的内容。
git log --author="John\|Mary"
请注意,作者的电子邮件也包含在作者的姓名中,因此您也可以使用此选项通过电子邮件进行搜索。
如果您的工作流程将提交者和作者分开,则 --committer
标记的运行方式相同。
按消息筛选
要按提交消息筛选提交,请使用 --grep
标记。其工作原理与上面讨论的 --author
标记类似,但它与提交消息匹配,而不是与作者匹配。
例如,如果您的团队在每条提交消息中都包含相关的问题编号,则可以使用以下方法拉取与该问题相关的所有提交:
git log --grep="JRA-224:"
您也可以将 -i
参数传递给 git log
,使其在模式匹配时忽略大小写差异。
按文件筛选
很多时候,您只对特定文件发生的变更感兴趣。要显示与文件相关的历史记录,您要做的就是传入文件路径。例如,以下内容返回影响 foo.py
或 bar.py
文件的所有提交:
git log -- foo.py bar.py
--
参数用于告诉 git log
后续参数是文件路径而不是分支名称。如果不可能将其与分支混在一起,则可以省略 --
。
按内容筛选
也可以搜索引入或删除特定源代码行的提交。这被称为 pickaxe,采用 -S"
的形式。例如,如果您想知道 Hello,World! 字符串什么时候添加到项目中的任何文件中,您可以使用以下命令:
git log -S"Hello, World!"
如果要使用正则表达式而不是字符串进行搜索,则可以改用 -G"
标标记。
这是一个非常强大的调试工具,因为它可以让您找到影响特定代码行的所有提交。它甚至可以显示何时将一行复制或移动到另一个文件中。
按范围筛选
您可以将一系列提交传递给 git log
,以仅显示该范围内包含的提交。范围采用以下格式指定,其中
和
是提交引用:
git log ..
当您使用分支引用作为参数时,此命令特别有用。这是显示两个分支之间差异的简单方法。考虑以下命令:
git log main..feature
main..feature
范围包含 feature
分支中但不在 main
分支中的所有提交。换句话说,这是自 feature
脱离 main
分支以来所取得的进展。您可以将其可视化为以下内容:
请注意,如果您切换范围的顺序 (feature..main
),您将在 main
中获得所有提交,但不会在 feature
中获得。如果 git log
输出两个版本的提交,则表明您的历史记录存在分歧。
筛选合并提交
默认情况下,git log
在其输出中包含合并提交。但是,如果您的团队有一个始终合并的政策(也就是说,您将上游的变更合并到主题分支中,而不是将主题分支重新建立在上游分支上),那么您的项目历史记录中就会有很多无关的合并提交。
您可以通过传递 --no-merges
标记来阻止 git log
显示这些合并提交:
git log --no-merges
另一方面,如果您只对合并提交感兴趣,您可以使用 --merges
标记:
git log --merges
这将返回所有至少有两个父项的提交。
摘要
使用 git log
的高级参数来格式化其输出并选择要显示的提交,您现在应该觉得很便捷,这使您能够从项目历史记录中准确提取所需内容。
这些新技能是 Git 工具包的重要组成部分,但请记住,git log
经常与其他 Git 命令一起使用。找到要查找的提交后,通常将其传递给 git checkout
、git revert
或其他工具来操作提交历史记录。所以,一定要继续学习 Git 的高级功能。
分享此文章
下一主题
推荐阅读
将这些资源加入书签,以了解 DevOps 团队的类型,或获取 Atlassian 关于 DevOps 的持续更新。