如何在 Git 历史记录中 grep(搜索)提交的代码
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2928584/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to grep (search) committed code in the Git history
提问by Ortwin Gentz
I have deleted a file or some code in a file sometime in the past. Can I grep in the content (not in the commit messages)?
过去某个时候我删除了一个文件或文件中的某些代码。我可以在内容中(而不是在提交消息中)grep 吗?
A very poor solution is to grep the log:
一个非常糟糕的解决方案是 grep 日志:
git log -p | grep <pattern>
However, this doesn't return the commit hash straight away. I played around with git grep
to no avail.
但是,这不会立即返回提交哈希。我玩了git grep
也没有用。
回答by Jeet
To search for commit content(i.e., actual lines of source, as opposed to commit messages and the like), you need to do:
要搜索提交内容(即,实际的源代码行,而不是提交消息等),您需要执行以下操作:
git grep <regexp> $(git rev-list --all)
git rev-list --all | xargs git grep <expression>
will work if you run into an "Argument list too long" error.
git rev-list --all | xargs git grep <expression>
如果您遇到“参数列表太长”错误,它将起作用。
If you want to limit the search to some subtree (for instance, "lib/util"), you will need to pass that to the rev-list
subcommand and grep
as well:
如果要将搜索限制为某个子树(例如,“lib/util”),则需要将其传递给rev-list
子命令grep
以及:
git grep <regexp> $(git rev-list --all -- lib/util) -- lib/util
This will grep through all your commit text for regexp
.
这将遍历您的所有提交文本regexp
。
The reason for passing the path in both commands is because rev-list
will return the revisions list where all the changes to lib/util
happened, but also you need to pass to grep
so that it will only search in lib/util
.
在这两个命令中传递路径的原因是因为rev-list
将返回lib/util
发生所有更改的修订列表,但您还需要传递到grep
以便它仅在lib/util
.
Just imagine the following scenario: grep
might find the same <regexp>
on other files which are contained in the same revision returned by rev-list
(even if there was no change to that file on that revision).
想象一下以下场景:grep
可能会<regexp>
在返回的同一修订版中包含的其他文件上找到相同的内容rev-list
(即使该修订版上的该文件没有更改)。
Here are some other useful ways of searching your source:
以下是一些其他有用的搜索来源的方法:
Search working tree for text matching regular expression regexp:
搜索与正则表达式正则表达式匹配的文本的工作树:
git grep <regexp>
Search working tree for lines of text matching regular expression regexp1 or regexp2:
在工作树中搜索与正则表达式 regexp1 或 regexp2 匹配的文本行:
git grep -e <regexp1> [--or] -e <regexp2>
Search working tree for lines of text matching regular expression regexp1 and regexp2, reporting file paths only:
在工作树中搜索匹配正则表达式 regexp1 和 regexp2 的文本行,仅报告文件路径:
git grep -l -e <regexp1> --and -e <regexp2>
Search working tree for files that have lines of text matching regular expression regexp1 and lines of text matching regular expression regexp2:
在工作树中搜索具有匹配正则表达式 regexp1 的文本行和匹配正则表达式 regexp2 的文本行的文件:
git grep -l --all-match -e <regexp1> -e <regexp2>
Search working tree for changed lines of text matching pattern:
搜索工作树以查找更改的文本匹配模式行:
git diff --unified=0 | grep <pattern>
Search all revisions for text matching regular expression regexp:
搜索匹配正则表达式 regexp 的文本的所有修订:
git grep <regexp> $(git rev-list --all)
Search all revisions between rev1 and rev2 for text matching regular expression regexp:
搜索 rev1 和 rev2 之间的所有修订版本以查找匹配正则表达式 regexp 的文本:
git grep <regexp> $(git rev-list <rev1>..<rev2>)
回答by VonC
You should use the pickaxe (-S
)option of git log
.
To search for Foo
:
搜索Foo
:
git log -SFoo -- path_containing_change
git log -SFoo --since=2009.1.1 --until=2010.1.1 -- path_containing_change
See Git history - find lost line by keywordfor more.
有关更多信息,请参阅Git 历史记录 - 按关键字查找丢失的行。
As Jakub Nar?bskicommented:
正如Jakub Nar?bski评论的那样:
this looks for differences that introduce or remove an instance of
<string>
. It usually means "revisions where you added or removed line with 'Foo'".the
--pickaxe-regex
option allows you to use extended POSIX regex instead of searching for a string. Example (fromgit log
):git log -S"frotz\(nitfol" --pickaxe-regex
这会查找引入或删除
<string>
. 它通常意味着“您添加或删除带有‘Foo’的行的修订版”。该
--pickaxe-regex
选项允许您使用扩展的 POSIX 正则表达式而不是搜索字符串。示例(来自git log
):git log -S"frotz\(nitfol" --pickaxe-regex
As Robcommented, this search is case-sensitive - he opened a follow-up questionon how to search case-insensitive.
回答by Tyler Holien
My favorite way to do it is with git log
's -G
option (added in version 1.7.4).
我最喜欢的方法是使用git log
's-G
选项(在 1.7.4 版中添加)。
-G<regex>
Look for differences whose added or removed line matches the given <regex>.
There is a subtle difference between the way the -G
and -S
options determine if a commit matches:
-G
和-S
选项确定提交是否匹配的方式之间存在细微差别:
- The
-S
option essentially counts the number of times your search matches in a file before and after a commit. The commit is shown in the log if the before and after counts are different. This will not, for example, show commits where a line matching your search was moved. - With the
-G
option, the commit is shown in the log if your search matches any line that was added, removed, or changed.
- 该
-S
选项主要计算提交前后文件中搜索匹配的次数。如果前后计数不同,则提交将显示在日志中。例如,这不会显示与您的搜索匹配的行被移动的提交。 - 使用该
-G
选项,如果您的搜索与添加、删除或更改的任何行匹配,则提交将显示在日志中。
Take this commit as an example:
以这次提交为例:
diff --git a/test b/test
index dddc242..60a8ba6 100644
--- a/test
+++ b/test
@@ -1 +1 @@
-hello hello
+hello goodbye hello
Because the number of times "hello" appears in the file is the same before and after this commit, it will not match using -Shello
. However, since there was a change to a line matching hello
, the commit will be shown using -Ghello
.
因为在这次提交前后“hello”在文件中出现的次数是相同的,所以使用-Shello
. 但是,由于行匹配发生了更改hello
,因此将使用 显示提交-Ghello
。
回答by Bartek Skwira
If you want to browse code changes (see what actually has been changed with the given word in the whole history) go for patch
mode - I found a very useful combination of doing:
如果您想浏览代码更改(查看整个历史记录中给定单词的实际更改内容),请转到patch
模式 - 我发现了一个非常有用的组合:
git log -p
# Hit '/' for search mode.
# Type in the word you are searching.
# If the first search is not relevant, hit 'n' for next (like in Vim ;) )
回答by Edward Anderson
git log
can be a more effective way of searching for text across all branches, especially if there are many matches, and you want to see more recent (relevant) changes first.
git log
可以是在所有分支中搜索文本的更有效方式,尤其是在有很多匹配项并且您希望首先查看更多最近(相关)更改的情况下。
git log -p --all -S 'search string'
git log -p --all -G 'match regular expression'
These log commands list commits that add or remove the given search string/regex, (generally) more recent first. The -p
option causes the relevant diff to be shown where the pattern was added or removed, so you can see it in context.
这些日志命令列出添加或删除给定搜索字符串/正则表达式的提交,(通常)首先是最近的。该-p
选项会导致相关差异显示在添加或删除模式的位置,因此您可以在上下文中查看它。
Having found a relevant commit that adds the text you were looking for (for example, 8beeff00d), find the branches that contain the commit:
找到添加了您要查找的文本的相关提交(例如 8beeff00d)后,找到包含该提交的分支:
git branch -a --contains 8beeff00d
回答by ripper234
I took Jeet's answerand adapted it to Windows (thanks to this answer):
我接受了Jeet 的回答并将其改编为 Windows(感谢这个回答):
FOR /F %x IN ('"git rev-list --all"') DO @git grep <regex> %x > out.txt
Note that for me, for some reason, the actual commit that deleted this regex did not appear in the output of the command, but rather one commit prior to it.
请注意,对我而言,出于某种原因,删除此正则表达式的实际提交并未出现在命令的输出中,而是出现在它之前的一个提交中。
回答by Christophe Roussy
Search in any revision, any file:
在任何修订版、任何文件中搜索:
git rev-list --all | xargs git grep <regexp>
Search only in some given files, for exampleXML files:
仅在某些给定文件中搜索,例如XML 文件:
git rev-list --all | xargs -I{} git grep <regexp> {} -- "*.xml"
The result lines should look like this: 6988bec26b1503d45eb0b2e8a4364afb87dde7af:bla.xml: text of the line it found...
结果行应如下所示: 6988bec26b1503d45eb0b2e8a4364afb87dde7af:bla.xml: 它找到的行的文本...
You can then get more information like author, date, and diff using git show
:
然后,您可以使用以下命令获取更多信息,例如作者、日期和差异git show
:
git show 6988bec26b1503d45eb0b2e8a4364afb87dde7af
回答by watashiSHUN
For simplicity, I'd suggest using GUI: gitk - The Git repository browser. It's pretty flexible
为简单起见,我建议使用 GUI:gitk - The Git repository browser。它非常灵活
And you can navigate through the results using the up/down arrows.
您可以使用向上/向下箭头浏览结果。
回答by dotNET
For anyone else trying to do this in Sourcetree, there is no direct command in the UI for it (as of version 1.6.21.0). However, you can use the commands specified in the accepted answer by opening Terminalwindow (button available in the main toolbar) and copy/pasting them therein.
对于尝试在Sourcetree 中执行此操作的任何其他人,UI 中没有针对它的直接命令(从 1.6.21.0 版开始)。但是,您可以通过打开终端窗口(主工具栏中可用的按钮)并在其中复制/粘贴它们来使用已接受答案中指定的命令。
Note: Sourcetree's Searchview can partially do text searching for you. Press Ctrl+ 3to go to Search view (or click Search tab available at the bottom). From far right, set Search type to File Changesand then type the string you want to search. This method has the following limitations compared to the above command:
注意:Sourcetree 的搜索视图可以为您进行部分文本搜索。按Ctrl+3转到“搜索”视图(或单击底部可用的“搜索”选项卡)。从最右边,将搜索类型设置为文件更改,然后键入要搜索的字符串。与上述命令相比,此方法具有以下限制:
- Sourcetree only shows the commitsthat contain the search word in one of the changed files. Finding the exact file that contains the search text is again a manual task.
- RegEx is not supported.
- Sourcetree 仅显示在已更改文件之一中包含搜索词的提交。查找包含搜索文本的确切文件又是一项手动任务。
- 不支持正则表达式。
回答by surajs1n
Whenever I find myself at your place, I use the following command line:
每当我发现自己在您的位置时,我都会使用以下命令行:
git log -S "<words/phrases i am trying to find>" --all --oneline --graph
Explanation:
解释:
git log
- Need I write more here; it shows the logs in chronological order.-S "<words/phrases i am trying to find>"
- It shows all those Git commits where any file (added/modified/deleted) has the words/phrases I am trying to find without '<>' symbols.--all
- To enforce and search across all the branches.--oneline
- It compresses the Git log in one line.--graph
- It creates the graph of chronologically ordered commits.
git log
- 需要我在这里写更多;它按时间顺序显示日志。-S "<words/phrases i am trying to find>"
- 它显示了所有那些 Git 提交,其中任何文件(添加/修改/删除)都包含我试图在没有“<>”符号的情况下找到的单词/短语。--all
- 在所有分支机构中执行和搜索。--oneline
- 它在一行中压缩 Git 日志。--graph
- 它创建按时间顺序提交的图表。