如何使用grep Git提交某个单词的差异或内容

h4cxqtbf  于 2023-02-28  发布在  Git
关注(0)|答案(9)|浏览(146)

在Git代码库中,我想列出所有包含某个单词的提交。

git log -p | grep --context=4 "word"

但它不一定给予文件名(除非它与我搜索的单词相距不到五行。

git grep "word"

但它只给我现在的文件而不是历史。
我如何搜索整个历史记录,以便我可以跟踪一个特定的字的变化?我打算搜索我的代码库的出现字跟踪变化(搜索文件历史记录)。

mepcadol

mepcadol1#

如果您想查找 * commit message * 包含给定单词的所有提交,请使用

$ git log --grep=word

如果你想找到所有在 * 文件内容 * 中添加或删除了"word"的提交(更准确地说:其中"word"的出现次数改变),即搜索 * commit contents *,使用所谓的"pickaxe"搜索

$ git log -Sword

在现代Git中也有

$ git log -Gword

查找添加或删除的行与"word"匹配的 * 差异 *(还有 * 提交内容 *)。
需要注意的几点:

  • 默认情况下,-G接受正则表达式,而-S接受字符串,但可以使用--pickaxe-regex修改它以接受正则表达式。
  • -S查找"word"出现次数发生变化的提交,而-G查找"word"出现在diff中的提交。
  • 这意味着-S<regex> --pickaxe-regex-G<regex>做的事情并不完全相同。

git diff documentation对此差异有一个很好的解释:
为了说明-S<regex> --pickaxe-regex-G<regex>之间的区别,考虑在同一个文件中有以下差异的提交:

+    return frotz(nitfol, two->ptr, 1, 0);
...
-    hit = frotz(nitfol, mf2.ptr, 1, 0);

虽然git log -G"frotz\(nitfol"会显示这个提交,但git log -S"frotz\(nitfol" --pickaxe-regex不会(因为该字符串的出现次数没有改变)。
这将显示包含搜索词的提交,但是如果你想看到这些提交中的实际变化,你可以使用--patch

$ git log -G"searchTerm" --patch

然后,这可以通过管道传输到grep,以隔离输出,只显示带有该搜索词的提交比较行。常见的用例是显示提交中带有该搜索词的比较行,包括给定的提交-本例中为3b5ab0f2a1-如下所示:

$ git log 3b5ab0f2a1^.. -G"searchTerm" --patch | grep searchTerm
dtcbnfnu

dtcbnfnu2#

git log的pickaxe将查找包含git log -Sword的“word”更改的提交

7xzttuei

7xzttuei3#

经过大量的实验,我可以推荐以下代码,它显示了引入或删除包含给定regexp的行的提交,并显示了每个提交中的文本更改,用颜色显示了添加和删除的单词。

git log --pickaxe-regex -p --color-words -S "<regexp to search for>"

虽然需要一段时间才能运行...- )

wqlqzqxt

wqlqzqxt4#

另一种方法/语法是:git log -S "word"
像这样,您可以搜索git log -S "with whitespaces and stuff @/#ü !"

kadbb459

kadbb4595#

您可以尝试以下命令:

git log --patch --color=always | less +/searching_string

或按以下方式使用grep

git rev-list --all | GIT_PAGER=cat xargs git grep 'search_string'

在要搜索的父目录中运行此命令。

jgovgodb

jgovgodb6#

要在正则表达式上使用布尔连接器:

git log --grep '[0-9]*\|[a-z]*'

这个正则表达式在提交消息中搜索正则表达式[0-9]* 或[a-z]*。

mepcadol

mepcadol7#

这在与BFG(Git filter分支--不要与 * git-filter-branch * 混淆)和git-filter-repo结合使用时很有用,它只获取文件路径,以便您可以将其提供给我刚才提到的两个工具之一。

A.相对、唯一、排序、路径:

# Get all unique filepaths of files matching 'password'
# Source: https://stackoverflow.com/a/69714869/10830091
git rev-list --all | (
    while read revision; do
        git grep -F --files-with-matches 'password' $revision | cat | sed "s/[^:]*://"
    done
) | sort | uniq

B.唯一的、已排序的文件名(非路径):

# Get all unique filenames matching 'password'
# Source: https://stackoverflow.com/a/69714869/10830091
git rev-list --all | (
    while read revision; do
        git grep -F --files-with-matches 'password' $revision | cat | sed "s/[^:]*://"
    done
) | xargs basename | sort | uniq

第二个命令对BFG很有用,因为它只接受文件名,而不接受存储库相对/系统绝对路径。
就这样。享受使用这些Bash片段给我带来的痛苦吧。我讨厌Bash,那么我为什么还要继续使用它呢?

夹层

仅获取文件名/路径

以下选项的含义相同(git-rep文档):

  • -l
  • --files-with-matches
  • --name-only

只显示包含Blockquote的文件名,而不是显示每一个匹配行

你的模式是:A.正则表达式与B.固定字符串?

至于-F,它只是意味着使用一个固定的字符串而不是正则表达式来解释模式。
这里还有一个有用的提示:您可以使用-i--ignore-case来区分大小写。

去掉那个愚蠢的前导提交哈希

sed "s/[^:]*://"

Source .

为他们提供独特的路径!

| sort | uniq

谁想要重复的路径?不是你,不是我!哦嘿看,他们也排序了!享受吧。
来源:我。从我记事起我就一直在用这个。(man sortman uniq

不带路径的文件名怎么办?

xargs basename

你可能会认为| basename可以工作,但事实并非如此。它不接受标准输入,而是作为命令行参数。下面是an explanation。想想看!basename基本上返回的是没有前导路径的词干文件名。man basename

对于方法A.,我希望使用绝对路径而不是相对路径。

当然,只要在末尾加上一个realpath。就像这样:

) | sort | uniq | xargs realpath

当然,你必须使用xargs,因为realpath不使用标准输入作为输入,它使用命令行参数,就像dirname一样。

灵感

  • 看看这个真棒alternative answer
    • 在所有Git历史中搜索字符串 *
    • 仅使用Git grep的文件名 *
vu8f3i0k

vu8f3i0k8#

vim-fugitive对于Vim中的这种检查是通用的。
使用:Ggrep来实现这一点。要了解更多信息,您可以安装vim-逃亡者并通过:help Grep查找tourorial。本期节目:exploring-the-history-of-a-git-repository将指导您完成所有这些操作。

p4rjhz4m

p4rjhz4m9#

如果你想搜索敏感数据,以便将其从Git历史记录中删除(这也是我登陆这里的原因),可以使用一些工具。GitHub as a dedicated help page for that issue
以下是文章的主旨:
BFG Repo-Cleaner是git filter-branch的一个更快、更简单的替代方法,可以用来移除不需要的数据。例如,要移除包含敏感数据的文件,并保留最新提交的内容不变,请运行:

bfg --delete-files YOUR-FILE-WITH-SENSITIVE-DATA

要替换passwords.txt中列出的所有文本(无论它位于存储库历史记录中的何处),请运行:

bfg --replace-text passwords.txt

请参阅BFG Repo-Cleaner's documentation了解完整的使用和下载说明。

相关问题