查看历史
本节部分内容参考自 Pro Git 和 git-recipes,在原文基础上有一定修改。
git log
在提交了若干更新,又或者克隆了某个项目之后,你也许想回顾下提交历史。完成这个任务最简单而又有效的工具是 git log
命令。
下面是一个典型的 git log
输出:
$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <[email protected]>
Date: Mon Mar 17 21:52:11 2008 -0700
changed the version number
commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <[email protected]>
Date: Sat Mar 15 16:40:33 2008 -0700
removed unnecessary test
commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <[email protected]>
Date: Sat Mar 15 10:31:28 2008 -0700
first commit
不传入任何参数的默认情况下,git log
会按时间先后顺序列出所有的提交,最近的更新排在最上面。正如你所看到的,这个命令会列出每个提交的 SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明。
有的时候,在 Windows 上使用
git log
时,会在输出一段信息后卡住。这是因为git log
在输出过长时,会调用分页器来实现分屏输出,但 Git for Windows 自带的分页器有一定的不兼容。这种情况下,可以使用git config --global core.pager cat
来禁用分页功能。
筛选历史
git log -n <limit>
显示前 <limit>
个提交。比如 git log -n 3
只会显示 3 个提交。-n 3
也可以写成 -3
。
git log --author="<pattern>"
搜索特定作者的提交。<pattern>
可以是字符串或正则表达式。
git log --grep="<pattern>"
搜索特定提交信息的提交。<pattern>
可以是字符串或正则表达式。
git log <since>..<until>
只显示发生在 <since>
和 <until>
之间的提交。两个参数可以是提交 ID、分支名、HEAD 或是任何一种引用。
git log <file>
只显示包含特定文件的提交。查找特定文件的历史这样做会很方便。
git log --since=<since>
git log --until=<until>
仅显示指定时间之后或之前的提交。<since>
和 <until>
可以为多种时间格式,可以是类似 "2008-01-15" 的具体的某一天,也可以是类似 "2 years 1 day 3 minutes ago" 的相对日期。
git log -S <name>
仅显示添加或删除特定字符串的提交。比如,搜索代码中添加或删除了对某一个特定函数的引用的提交。
显示更多信息
-p
或 --patch
选项会显示每次提交所引入的差异(按补丁的格式输出)。
$ git log -p -1
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <[email protected]>
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 = "[email protected]"
s.summary = "A simple gem for using Git in Ruby code."
--stat
选项可以显示每次提交的简略统计信息,包括所有被修改过的文件、有多少文件被修改了以及被修改过的文件的哪些行被移除或是添加。
$ git log --stat -1
commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <[email protected]>
Date: Sat Mar 15 10:31:28 2008 -0700
first commit
README | 6 ++++++
Rakefile | 23 +++++++++++++++++++++++
lib/simplegit.rb | 25 +++++++++++++++++++++++++
3 files changed, 54 insertions(+)
格式化输出
--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
下面列出了 --format
接受的常用格式占位符的写法及其代表的意义。
占位符 | 说明 |
---|---|
%H | 提交的完整哈希值 |
%h | 提交的短哈希值 |
%T | 树的完整哈希值 |
%t | 树的短哈希值 |
%P | 父提交的完整哈希值 |
%p | 父提交的简写哈希值 |
%an | 作者名字 |
%ae | 作者的电子邮件地址 |
%ad | 作者修订日期(可以用 --date=选项 来定制格式) |
%ar | 作者修订日期,按多久以前的方式显示 |
%cn | 提交者的名字 |
%ce | 提交者的电子邮件地址 |
%cd | 提交日期 |
%cr | 提交日期(距今多长时间) |
%s | 提交说明 |
你一定奇怪作者和提交者之间究竟有何差别,其实作者指的是实际作出修改的人,提交者指的是最后将此工作成果提交到仓库的人。所以,当你为某个项目发布补丁,然后某个核心成员将你的补丁并入项目时,你就是作者,而那个核心成员就是提交者。关于其中具体的区别,我们会在以后的章节中详细讨论。
当 format
与另一个 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
下面是我很喜欢的一种 log 格式,在纵览项目历史时很有用:
git log --no-merges --color --graph --date=format:'%Y-%m-%d %H:%M:%S' --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cd) %C(bold blue)<%an>%Creset' --abbrev-commit
可以为这一长串命令起一个别名:
git config --global alias.ls "log --no-merges --color --graph --date=format:'%Y-%m-%d %H:%M:%S' --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cd) %C(bold blue)<%an>%Creset' --abbrev-commit"
之后,就可以用 git ls
来快速调用这个命令。
$ git ls -10
* e7a595e - (HEAD -> 查看历史) :adhesive_bandage: 更正关于 Linux 上的文本编辑器的描述 (2022-06-17 23:19:29) <忘忧北萱草>
* 0089bc1 - :sparkles: 更新关于 GPG 出错的解决方案 (2022-06-17 23:16:33) <忘忧北萱草>
* 23b7ae1 - :sparkles: 提交更改 (2022-06-17 18:20:09) <忘忧北萱草>
* 4fb486c - :sparkles: 本项目的 gitmoji 规范 (2022-06-17 16:08:40) <忘忧北萱草>
* 35ecf52 - :adhesive_bandage: 修正关于储存库中文件储存方式的描述 (2022-06-17 15:57:25) <忘忧北萱草>
* b571156 - :zap: 添加 giscus 支持,以及修复导航按钮问题 (2022-06-17 01:59:31) <忘忧北萱草>
* 4e84d9d - :sparkles: 管理暂存区 (2022-06-16 23:05:09) <忘忧北萱草>
* ad3b4fc - :pencil2: 规范标点的使用 (2022-06-16 19:13:06) <忘忧北萱草>
* 64273e0 - :memo: 增加 badges 和链接 (2022-06-16 17:28:53) <忘忧北萱草>
* 30cae30 - :lipstick: 优化点击跳转的平滑滚动的方式和效果 (2022-06-16 16:38:37) <忘忧北萱草>
在钩子中使用 git log
后来我发现在
pre-push
钩子里使用交互式命令会破坏一些自动化工具的使用,所以是否使用下面的钩子,还是要看你自己的情况。
上一节我们说过,必须重视每一次提交,保证不完整的提交记录不会被推送到远程。
但是,Git 并非一个所见即所得的系统,有时候你做出了一些更改,并不能立刻想到结果是到底是什么样的。这时 git log
会是很好的帮助,它可以帮你检查你做出的更改是否有问题。只要更改还留在本地,你永远有修正的机会。
不过,假如在提推送前你忘记了用 git log
查看一下,就有可能发生一些不好的事情。所以,我们需要一个东西,来提醒我们在每次推送之前 git log
一下。这种东西就是 Git 钩子。
关于钩子的详细说明,将会在以后的章节涉及。这里就简单举一个使用钩子的实例。
储存库所使用的钩子存放在 .git/hooks
目录中。将其中 pre-push.sample
文件改名为 pre-push
,去掉 .sample
来启用它。这个钩子会在每次推送前被调用。
将 pre-push
的内容修改为:
#!/bin/bash
remote="$1"
url="$2"
echo "You are pushing to $remote($url), please check the commits history: "
git log --no-merges --color --graph --date=format:'%Y-%m-%d %H:%M:%S' --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cd) %C(bold blue)<%an>%Creset' --abbrev-commit -10
echo ""
read -r -p "Type 'y' to continue or 'n' to abort: " confirm < /dev/tty
if [[ $confirm =~ ^[Yy]$ ]]; then
exit 0
else
echo "Abort."
exit 1
fi
这样,每次推送前,都会自动显示最近10条提交记录,并询问是否继续,这就给了我们反悔的机会。
$ git push
You are pushing to origin([email protected]:Wybxc/git-remake-guide.git), please check the commits history:
* e7a595e - (HEAD -> master) :adhesive_bandage: 更正关于 Linux 上的文本编辑器的描述 (2022-06-17 23:19:29) <忘忧北萱草>
* 0089bc1 - :sparkles: 更新关于 GPG 出错的解决方案 (2022-06-17 23:16:33) <忘忧北萱草>
* 23b7ae1 - :sparkles: 提交更改 (2022-06-17 18:20:09) <忘忧北萱草>
* 4fb486c - :sparkles: 本项目的 gitmoji 规范 (2022-06-17 16:08:40) <忘忧北萱草>
* 35ecf52 - :adhesive_bandage: 修正关于储存库中文件储存方式的描述 (2022-06-17 15:57:25) <忘忧北萱草>
* b571156 - :zap: 添加 giscus 支持,以及修复导航按钮问题 (2022-06-17 01:59:31) <忘忧北萱草>
* 4e84d9d - :sparkles: 管理暂存区 (2022-06-16 23:05:09) <忘忧北萱草>
* ad3b4fc - :pencil2: 规范标点的使用 (2022-06-16 19:13:06) <忘忧北萱草>
* 64273e0 - :memo: 增加 badges 和链接 (2022-06-16 17:28:53) <忘忧北萱草>
* 30cae30 - :lipstick: 优化点击跳转的平滑滚动的方式和效果 (2022-06-16 16:38:37) <忘忧北萱草>
Type 'y' to continue or 'n' to abort: y
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 882 bytes | 882.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To [email protected]:Wybxc/git-remake-guide.git
* [new branch] master -> master
branch 'master' set up to track 'origin/master'.
如果你觉得这个钩子很好,并且想要给其他的仓库也启用,你可以修改 Git 创建新储存库所用的模板仓库,它的目录在 /usr/share/git-core/templates
或者 <Git for Windows 目录>/mingw64/share/git-core/templates
。这会影响之后新建或者新克隆的储存库,而之前已经建立的储存库是不受影响的。