1. 概述
在本教程中,我们将学习如何在 Git 提交历史中搜索特定文本模式。重点将放在如何使用 git log
命令,在提交信息(commit message)或提交差异(commit diff)中查找包含特定字符串的提交。
2. 使用 git log
搜索提交信息或差异
在使用 Git 时,我们经常需要查找包含特定文本的提交。这在查找引入 bug 的提交、或者查找某个功能变更的代码时非常有用。
下面是一个 Git 提交的示例:
$ git show 20ec5cf2aaf273eaa941337af1213b8033fab2b5
commit 20ec5cf2aaf273eaa941337af1213b8033fab2b5
Author: Ilotana Ainebab <anebab@example.com>
Date: Thu Dec 26 13:22:48 2019 +0300
Simplify nil check for slice
len() for nil slices is defined as zero (gosimple)
diff --git a/runtime/ui/key/binding.go b/runtime/ui/key/binding.go
index 8697145..5d4605a 100644
--- a/runtime/ui/key/binding.go
+++ b/runtime/ui/key/binding.go
@@ -65,7 +65,7 @@ func NewBindingFromConfig(gui *gocui.Gui, influence string, configKeys []string,
if err != nil {
return nil, err
}
- if keys != nil && len(keys) > 0 {
+ if len(keys) > 0 {
parsedKeys = keys
break
}
Git 提交对象包含提交哈希、作者、日期等元信息,以及提交信息正文和差异内容(diff)。
我们可以使用 git log
命令来搜索提交信息和 diff 内容。
git log
命令默认按时间顺序展示提交日志,从当前分支最新的提交开始,直到最早的一次提交。它还支持一些选项,比如 --grep
、-S
和 -G
,用于根据文本模式过滤提交。
接下来我们将详细介绍这些选项的使用方法。
3. --grep
选项
git log
支持通过 --grep
选项搜索提交信息中包含特定字符串的提交。
例如,我们可以查找提交信息中包含 “Simplify” 的提交:
$ git log --grep Simplify
commit 20ec5cf2aaf273eaa941337af1213b8033fab2b5
Author: Anatoli Babenia <ababenia@example.com>
Date: Thu Dec 26 13:22:48 2019 +0300
Simplify nil check for slice
len() for nil slices is defined as zero (gosimple)
commit 68acfcdd64131693c198bb6a415c301b04f7d128
Merge: 3752d64 1fa41a3
Author: Alex Goodman <agoodman@example.com>
Date: Sun Jul 21 15:48:25 2019 -0400
Merge pull request #206 from muesli/linter-fixes
Simplify code
--grep
接受正则表达式作为参数,因此我们可以使用正则表达式进行更灵活的匹配。
例如,匹配 “Simplify” 或 “Simplified”:
$ git log --grep Simpl\w*
commit 20ec5cf2aaf273eaa941337af1213b8033fab2b5
Author: Anatoli Babenia <ababenia@example.com>
Date: Thu Dec 26 13:22:48 2019 +0300
Simplify nil check for slice
len() for nil slices is defined as zero (gosimple)
commit 68acfcdd64131693c198bb6a415c301b04f7d128
Merge: 3752d64 1fa41a3
Author: Alex Goodman <agoodman@example.com>
Date: Sun Jul 21 15:48:25 2019 -0400
Merge pull request #206 from muesli/linter-fixes
Simplify code
commit 4ab1ce983b5c05a2cfe2efc90201a3181f89c808
Merge: 0ca94f2 04d4881
Author: Alex Goodman <agoodman@example.com>
Date: Sun Jul 21 15:45:53 2019 -0400
Merge pull request #202 from muesli/simplified-fixes
Simplified boolean comparisons
最后一个提交信息中包含 “Simplified”,也匹配了正则表达式 Simpl\w*
。
3.1. 忽略大小写匹配
git log --grep
支持通过 -i
选项进行大小写不敏感的匹配:
$ git log -i --grep simplified
该命令将匹配所有提交信息中包含 “simplified” 的提交,无论大小写。
3.2. 正则表达式类型
Linux 系统支持多种正则表达式类型:
- 基本正则表达式(BRE):默认使用
- 扩展正则表达式(ERE):使用
-E
选项启用 - Perl 兼容正则表达式(PCRE):使用
-P
选项启用
示例:
# 使用 ERE
$ git log -E --grep (simplified|simplify)
# 使用 PCRE
$ git log -P --grep simplified(?=code)
# 固定字符串匹配
$ git log -F --grep simplif.*
使用 -F
可以禁用正则表达式,仅匹配固定字符串。
3.3. --grep
的常见误解
一个常见的误解是:认为 git log --grep
会搜索所有 git log
输出内容,包括 diff。但其实:
✅ --grep
只搜索提交信息,不搜索 diff 内容
❌ 即使加上 -p
也不会搜索 diff
例如:
$ git log -p
commit 2f477ef3b6db96040e1dd908a958566b4f5f0e77 (HEAD -> master)
Author: mjchi7 <mjchi7@example.com>
Date: Sun Apr 2 09:59:16 2023 +0800
initialize repository
Setting up the project
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..0349a44
--- /dev/null
+++ b/main.py
@@ -0,0 +1 @@
+import json
如果我们尝试用 --grep json
搜索 diff 中的 “json”:
$ git log -p --grep json
⚠️ 该命令不会返回任何结果,因为 “json” 不在提交信息中。
4. Git 的 Pickaxe 功能
如果要搜索 diff 内容,需要使用 Git 的 Pickaxe 功能。
Pickaxe 功能用于查找某个字符串在文件中被添加、删除或移动的提交。它通过检查 diff 来实现匹配。
git log
提供了两个选项来使用 Pickaxe 功能:
-S
:当字符串的出现次数发生变化时匹配-G
:只要 diff 中出现该字符串就匹配
4.1. 字符串出现次数变化 (-S
)
-S
选项仅在提交中字符串的出现次数发生变化时才匹配。
假设我们有如下提交历史:
commit 8fe0d4e37bf00f20798e9db8cb383f76f0b72c6e (HEAD -> master)
Author: mjchi7 <mjchi7@example.com>
Date: Sat Apr 1 11:08:34 2023 +0800
remove import
diff --git a/main.py b/main.py
index d820b59..e69de29 100644
--- a/main.py
+++ b/main.py
@@ -1 +0,0 @@
-import matplotlib.pyplot as plt
commit 909b0a026e4115d6ee29a9fd9eeeee389806eccc
Author: mjchi7 <mjchi7@example.com>
Date: Sat Apr 1 11:08:10 2023 +0800
modify import line
diff --git a/main.py b/main.py
index 0e92f4a..d820b59 100644
--- a/main.py
+++ b/main.py
@@ -1 +1 @@
-import matplotlib.pyplot
+import matplotlib.pyplot as plt
commit 60d9e1be2d0607d8443f1481aee0c8ad3cb0dda8
Author: mjchi7 <mjchi7@example.com>
Date: Sat Apr 1 11:07:31 2023 +0800
add new file
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..0e92f4a
--- /dev/null
+++ b/main.py
@@ -0,0 +1 @@
+import matplotlib.pyplot
运行:
$ git log -S matplotlib
commit 8fe0d4e37bf00f20798e9db8cb383f76f0b72c6e (HEAD -> master)
Author: mjchi7 <mjchi7@example.com>
Date: Sat Apr 1 11:08:34 2023 +0800
remove import
commit 60d9e1be2d0607d8443f1481aee0c8ad3cb0dda8
Author: mjchi7 <mjchi7@example.com>
Date: Sat Apr 1 11:07:31 2023 +0800
add new file
⚠️ 第二个提交未被匹配,因为其中 “matplotlib” 的出现次数未发生变化。
如果希望将参数作为正则表达式处理,可以加上 --pickaxe-regex
:
$ git log --pickaxe-regex -S "(matplotlib|mpl)"
4.2. 字符串出现在 diff 中 (-G
)
-G
与 -S
不同,只要 diff 中包含指定字符串,就匹配。
继续使用上面的例子:
$ git log -G matplotlib
commit 8fe0d4e37bf00f20798e9db8cb383f76f0b72c6e (HEAD -> master)
Author: mjchi7 <mjchi7@example.com>
Date: Sat Apr 1 11:08:34 2023 +0800
remove import
commit 909b0a026e4115d6ee29a9fd9eeeee389806eccc
Author: mjchi7 <mjchi7@example.com>
Date: Sat Apr 1 11:08:10 2023 +0800
modify import line
commit 60d9e1be2d0607d8443f1481aee0c8ad3cb0dda8
Author: mjchi7 <mjchi7@example.com>
Date: Sat Apr 1 11:07:31 2023 +0800
add new file
✅ 所有三个提交都被匹配,因为它们的 diff 中都包含 “matplotlib”。
⚠️ -G
默认就将参数视为正则表达式,不需要额外标志。
5. 总结
在本文中,我们学习了如何在 Git 提交历史中搜索字符串:
- ✅
git log --grep
:搜索提交信息中的字符串 - ✅
git log -S
:搜索 diff 中字符串出现次数变化的提交 - ✅
git log -G
:搜索 diff 中出现指定字符串的所有提交
掌握这些命令可以显著提高我们在 Git 仓库中定位变更的效率。