Git:显示指定文件中单行的所有变化,覆盖整个git历史记录

152

我搜索了一下,不确定是否可能,但是还是试试吧:

我有一个(javascript)文件(比如/lib/client.js),其中我给一个变量分配了一个唯一标识符,就像这样:var identifier = "SOME_IDENTIFIER";

你可以把这个标识符看作是一个版本号:定期地,我们会将此变量更改为新的标识符。

我想找到我们曾经使用过的所有唯一标识符。我该如何在 git 中实现这一点?

我想可能有一种方法可以搜索 git 历史记录,并打印与 "var identifier =" 匹配的行。然后我可以手动去重这个列表。

无论如何,我很感激任何见解。谢谢。


3
可能是检索文件中特定行的提交日志?的重复问题。 - Aron Rotteveel
6个回答

163

从Git 1.8.4开始,有一种更直接回答你问题的方式。

假设行110是说var identifier = "SOME_IDENTIFIER";的那一行,请按照以下操作进行:

git log -L110,110:/lib/client.js

这将返回涉及到该行代码的每个提交。

请参阅git-log命令行参数中-L的文档


61

请查看git-loggit-diffcore手册。我认为以下命令可以实现此功能,但可能不完全正确:

git log -G "var identifier =" file.js

编辑:下面是一个简单的Bash脚本,可以显示实际行数。这可能更符合你的需求。

for c in $(git log -G "something" --format=%H -- file.js); do
    git --no-pager grep -e "something" $c -- file.js
done
它使用git log -G查找有趣的提交,使用--format=%H生成提交哈希列表。然后迭代每个有趣的提交,请求git grep显示包含正则表达式的文件和提交哈希前缀的行。

编辑:根据评论建议改用-G而不是-S


@Rob - 谢谢这个 - 对你的脚本做了一点小修改 - 仅仅显示文件名只会展示只影响该文件的提交 - 如果一个提交涉及其他文件,它不会被列出。 - Adrian Cornish
@AdrianCornish - 很高兴它有所帮助。我认为 OP 只想查看一个文件,但您是完全正确的,删除文件名可能是一个更普遍有用的脚本。 - rob
我遇到了一个更加困难的情况。所涉及的文件已经从路径a/file移动到路径b/file。现在,当我在路径b中进行操作时,它只显示文件从路径a移动到路径b时的更改。如果我在路径a中进行操作,它会告诉我:fatal: ambiguous argument 'file': unknown revision or path not in the working tree. - Andy Song
@AndySong - 如果你要搜索的字符串足够独特,也许你可以省略文件名,仍然能找到你要找的内容。 - rob
对我来说更方便的是,在每次提交后插入一个空行,并枚举每一行:sfile=path/to/some_file; sfind='string_to_find'; for c in $(git log -G $sfind --format=%H -- $sfile); do git --no-pager grep -e $sfind -n $c -- $sfile; echo; done - John_West

14

你也可以使用 gitk 来完成这个操作:

gitk file.js
在“提交”下拉菜单中,选择“添加/删除字符串:”,在其旁边的文本框中输入“var identifier =”,所有添加或删除包含该字符串的行的提交记录将被突出显示。

这有助于定位添加了包含“var identifier =”的行的提交,但不会显示修改此行的后续提交。 - findchris
2
你尝试过使用 git blame file.js 或者 git gui blame file.js 吗? - Ethan Brown
1
我知道 git blame 的作用;我正在寻找完整的修订历史记录,而不是单个差异。 - findchris
1
git gui blame file.js 可以做到这一点...它会显示文件的所有修订版本以及谁进行了更改;您只需通过历史记录向后点击即可。 - Ethan Brown
最终我使用gitk进行了可视化的步骤跟踪。我想可能有一些优雅的git技巧可以做到这一点,但是gitk已经足够好了。谢谢。 - findchris

10
如果你稍微参考 @rob 的回答,git log 基本上可以为你完成这个功能,如果你只需要一个可视化的比较。
git log -U0 -S "var identifier =" path/to/file

-U0 表示以补丁模式(-p)输出,并显示补丁周围零行上下文。

您甚至可以在分支之间做到这一点:

git log -U0 -S "var identifier =" branchname1 branchname2 -- path/to/file

可能有一种方法可以抑制差异头,但我不知道有哪种方法。


对我有用!谢谢。 - Roberto Bonini

5
magit 中,您可以使用以下方法实现此操作。
l, =L

然后它会要求您提供文件和起始、结束行。


0

我想列出Linux内核所使用的所有宠物名字。这个设置在内核Git仓库Makefile中(尽管这不是完整历史记录)。我不想依赖于特定的行号,而是想要行的实际内容而不是提交引用,并且我想要删除重复项而不影响顺序。我想到了这个:

git log --format=format:%H Makefile | xargs -I{} git show {}:Makefile | awk -F '=' '/^NAME = /{print $NF}' | awk '!x[$0]++'

首先使用git log获取影响该文件的提交,然后通过git show获取该提交下的文件内容,并将其传递给awk来提取感兴趣的行和第二个 awk去重列表。

以防有用到任何人。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接