版本控制的目的就是为了记录代码的修改历史。这让你可以查看别人写了什么代码,什么时候bug出现,回滚有问题的修改。如果你不知道在通过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
这个参数对于查看项目主要概况非常有用。
Decorating
很多时候如果能查看每个提交相关的分支或标签信息非常有用。–decorate参数让git log
可以展示指向提交的所有的相关信息(例如:分支,标签信息等)。
它可以和其他参数一起使用。比如,执行git log --oneline --decorate
将会输出像下面这样的格式化提交历史:
0e25143 (HEAD, master) 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
我们可以看到最顶上的提交是被checkout 过来的(注意HEAD),并且在master分枝上。第二个提交有另外一个叫做feature的分支指向它。第四个提交被标记为v0.9。
分支、标签、头(HEAD)以及提交历史是Git仓库包含几乎所有的信息。因此这让你能够完整的查看仓库的逻辑结构。
Diffs
git log包含查看每个提交不同的参数选项。通常使用的选项有 --stat
和 -p
。
--stat
选项展示每个文件被提交被每个提交插入和删除的数量(注意修改一行被看作为插入一行或者删除一行)。这对于想查看每个条修改一个文件的概述非常有用。例如下面的提交被添加67行和删除了38行到hello.by文件中:
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选项来按每个作者提交数量排序。
图表格式(Graphs)
–graph 选项绘制一个ASCII图像来展示提交历史的分支结构。它经常和 –oneline和 –decorate两个选项一起使用,这样会更容易查看哪个提交属于哪个分支:
git log --graph --oneline --decorate
对于一个只有两个分支的仓库来说,这个命令将输出如下结果:
* 0e25143 (HEAD, master) 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这两个提交在feature分支上,其余的在master分支上。
虽然这对简单的项目来说是个很好用的选择,但你可能会更喜欢gitk
或SourceTree
这些更强大的可视化工具来分析大型项目。
自定义格式
对于其他的git log格式需求,你都可以使用--pretty=format:"<string>"
选项。它允许你使用像printf一样的占位符来输出提交。
比如,下面命令中的%cn、%h 和%cd这三种占位符会被分别替换为作者名字、缩略标识和提交日期。
git log --pretty=format:"%cn committed %h on %cd"
This results in the following format for each commit:
每个提交日志输出格式如下:
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 操作文档(manual page)Pretty Formats 片段找到.
除了让你只看到关注的信息,这个–pretty=format:”
过滤提交历史
Formatting how each commit gets displayed is only half the battle of learning git log
. The other half is understanding how to navigate the commit history. The rest of this article introduces some of the advanced ways to pick out specific commits in your project history using git log
. All of these can be combined with any of the formatting options discussed above.
格式化提交输出只是学习git log一半任务。另一半是理解如何浏览整个提交历史。接下来的文章会介绍如何用git log选择项目历史中的特定提交。所有的用法都可以和上面讨论过的格式化选项结合起来。
按数量
git log最基础的过滤选项是限制显示的提交数量。当你只对最近几次提交感兴趣时,它可以节省你一页一页查看的时间。
你可以在后面加上-
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"
注意--since
、--until
标记和--after
、--before
标记的作用分别是相似的。
按作者
当你只想看某一特定作者的提交的时候,你可以使用--author
标记。它接受正则表达式,返回所有作者名字满足这个规则的提交。如果你知道那个作者的确切名字你可以直接传入文本字符串:
git log --author="John"
它会显示所有作者叫John的提交。作者名不一定是全匹配,只要包含那个子串就会匹配。
你也可以用正则表达式来创建更复杂的检索。比如,下面这个命令检索名叫Mary或John的作者的提交。
git log --author="John\|Mary"
注意作者的邮箱地址也算作是作者的名字,所以你也可以用这个选项来按邮箱检索。
如果你的工作流区分提交者和作者,--committer
也能以相同的方式使用。
按提交日志信息
按提交信息来过滤提交,你可以使用–grep标记。它和上面的–author标记差不多,只不过它搜索的是提交信息而不是作者。
比如说,你的团队规范要求在提交信息中包括相关的issue编号,你可以用下面这个命令来显示这个issue相关的所有提交:
git log --grep="JRA-224:"
你也可以传入-i
参数来忽略大小写匹配。
按文件
很多时候,你只对某个特定文件的更改感兴趣。为了显示某个特定文件的历史,你只需要传入文件路径。比如说,下面这个命令返回所有和foo.py和bar.py文件相关的提交:
git log -- foo.py bar.py
–告诉git log接下来的参数是文件路径而不是分支名。如果分支名和文件名不可能冲突,你可以省略–。
按文件内容
我们还可以根据源代码中某一行的增加和删除来搜索提交。这被称为pickaxe,它接受形如-S”
git log -S "Hello, World!"
如果你想用正则表达式而不是字符串来搜索,你可以使用-G “
这是一个非常强大的调试工具,它能让你定位到所有影响代码中特定一行的提交。它甚至可以让你看到某一行是什么时候复制或者移动到另一个文件中去的。
按范围
你可以传入范围来筛选提交。这个范围由下面这样的格式指定,其中
git log <since>..<until>
这个命令在你使用分支引用作为参数时特别有用。这是显示两个分支之间区别最简单的方式。看看下面这个命令:
git log master..feature
其中的master..feature范围包含了在feature分支而不在master分支中所有的提交。换句话说,这个命令可以看出从master分支fork到feature分支后发生了哪些变化。它可以这样可视化:
注意如果你更改范围的前后顺序(feature..master),你会获取到master分支而非feature分支上的所有提交。如果git log输出了全部两个分支的提交,这说明你的提交历史已经分叉了。
过滤合并提交
git log输出时默认包括合并提交。但是,如果你的团队采用强制合并策略(意思是merge你修改的上游分支而不是将你的分支rebase到上游分支),你的项目历史中会有很多外来的提交。
你可以通过--no-merges
标记来排除这些提交:
git log --no-merges
另一方面,如果你只对合并提交感兴趣,你可以使用--merges
标记:
git log --merges
它会返回所有包含两个父节点的提交。
总结
你现在应该对使用git log来格式化输出和选择你要显示的提交的用法比较熟悉了。它允许你查看你项目历史中任何需要的内容。
这些技巧是你Git工具箱中重要的部分,不过注意git log往往和其他Git命令连着使用。当你找到了你要的提交,你把它传给git checkout
、git revert
或是其他控制提交历史的工具。所以,请继续坚持Git高级用法的学习。