所以我找到了关于如何查看文件的更改历史记录的问题,但是这个特定文件的更改历史记录很大,我真的只对特定方法的更改感兴趣。那么就可以看到这种特定方法的变化历史了吗?
我知道这需要git来分析代码,并且分析对于不同的语言会有所不同,但是在大多数语言中方法/函数声明看起来非常相似,所以我想也许有人已经实现了这个功能。
我目前使用的语言是Objective-C,我目前使用的SCM是git,但我很想知道这个功能是否适用于任何SCM /语言。
答案 0 :(得分:67)
git log
的最新版本学习了-L
参数的特殊形式:
-L:< funcname>:< file>
跟踪
"<start>,<end>"
中<funcname>
(或函数名称正则表达式<file>
)给出的行范围的演变。你可能不会给任何pathpec限制器。目前这仅限于从单个修订开始的步行,即,您可能只提供零个或一个正修订参数。您可以多次指定此选项 ...
如果“:<funcname>”
代替<start>
和<end>
,则它是一个正则表达式,表示从匹配<funcname>
的第一个funcname行到下一个funcname的范围线。“:<funcname>”
从上一个-L
范围的末尾搜索(如果有的话),否则从文件的开头搜索。“^:<funcname>”
从文件开头搜索。
换句话说:如果你问Git git log -L :myfunction:path/to/myfile.c
,它现在会很高兴地打印出该函数的更改历史记录。
答案 1 :(得分:15)
使用git gui blame
很难在脚本中使用,虽然git log -G
和git log --pickaxe
可以在方法定义出现或消失时向您展示,但我没有找到任何方法使它们列出对方法的正文所做的所有更改。
但是,您可以使用gitattributes
和textconv
属性将解决方案拼凑在一起。虽然这些功能最初旨在帮助您使用二进制文件,但它们在这里也可以正常工作。
关键是让Git在执行任何差异操作之前从文件中除去你感兴趣的所有行。然后git log
,git diff
等只会看到您感兴趣的区域。
以下是我用另一种语言做的概述;你可以根据自己的需要调整它。
编写一个简短的shell脚本(或其他程序),它接受一个参数 - 源文件的名称 - 并仅输出该文件的有趣部分(如果没有任何内容,则不输出任何内容)。例如,您可以使用sed
,如下所示:
#!/bin/sh
sed -n -e '/^int my_func(/,/^}/ p' "$1"
为新脚本定义Git textconv
过滤器。 (有关详细信息,请参阅gitattributes
手册页。)过滤器的名称和命令的位置可以是您喜欢的任何内容。
$ git config diff.my_filter.textconv /path/to/my_script
在计算相关文件的差异之前,告诉Git使用该过滤器。
$ echo "my_file diff=my_filter" >> .gitattributes
现在,如果您使用-G.
(请注意.
)列出在应用过滤器时产生可见更改的所有提交,那么您将完全拥有这些提交感兴趣的。使用Git的diff例程的任何其他选项,例如--patch
,也会得到这个受限制的视图。
$ git log -G. --patch my_file
瞧!
您可能想要做的一个有用的改进是让您的过滤器脚本将方法名称作为其第一个参数(并将文件作为其第二个参数)。这使您可以通过调用git config
来指定感兴趣的新方法,而不必编辑脚本。例如,您可能会说:
$ git config diff.my_filter.textconv "/path/to/my_command other_func"
当然,过滤器脚本可以做任何你喜欢的事情,拿出更多的参数,或者其他什么:除了我在这里展示的内容之外,还有很多灵活性。
答案 2 :(得分:10)
git log有一个选项'-G'可用于查找所有差异。
-G查找添加或删除的行与之匹配的差异 给定
<regex>
。
给它一个你关心的函数名的正确的正则表达式。例如,
$ git log --oneline -G'^int commit_tree'
40d52ff make commit_tree a library function
81b50f3 Move 'builtin-*' into a 'builtin/' subdirectory
7b9c0a6 git-commit-tree: make it usable from other builtins
答案 3 :(得分:9)
你可以做的最接近的事情是确定你的函数在文件中的位置(例如,你的函数i_am_buggy
在foo/bar.c
的第241-263行),然后运行一些效果的:
git log -p -L 200,300:foo/bar.c
这将打开更少(或相当的寻呼机)。现在,您可以输入/i_am_buggy
(或等效的寻呼机)并开始逐步完成更改。
这可能会起作用,具体取决于您的代码风格:
git log -p -L /int i_am_buggy\(/,+30:foo/bar.c
这将搜索从该正则表达式的第一次命中(理想情况下是您的函数声明)限制为之后的30行。结束参数也可以是正则表达式,尽管使用regexp检测 是一个更有效的命题。
答案 4 :(得分:3)
正确的方法是使用eckes answer中解释的select etunimi, count(*)
from jasenet
group by etunimi
。
但另外,如果你的函数很长,你可能只希望看到各种提交引入的更改,而不是整个函数行,包括未修改的,对于每个提交可能只触及其中一行。像普通 // Loader
$thread = new MyThread($loader)
$loader = new Loader($registry);
$registry->set('load', $loader);
一样。
通常git log -L :function:path/to/file
可以查看与diff
的差异,但这不适用于git log
。
因此,您必须-p
-L
仅显示涉及的行和提交/文件标题以将它们上下文化。这里的诀窍是只匹配终端彩色线,添加grep
开关和正则表达式。最后:
git log -L
请注意,--color
应该是实际的,文字git log -L :function:path/to/file --color | grep --color=never -E -e "^(^[\[[0-9;]*[a-zA-Z])+" -3
。您可以按^ V ^ [在bash中键入它们,即 Ctrl + V , Ctrl + [ 。参考here。
同样最后^[
开关,允许在每条匹配线之前和之后打印3行输出上下文。您可能希望根据需要进行调整。
答案 5 :(得分:2)
git blame显示上次更改文件的每一行的人;您可以指定要检查的行,以避免获取函数外的行的历史记录。
答案 6 :(得分:0)
显示git log L :<funcname>:<file>
中的功能历史记录,如eckes's answer和git doc
如果没有显示任何内容,请参考Defining a custom hunk-header在文件
*.java diff=java
中添加类似.gitattributes
的内容以支持您的语言。
显示使用git log commit1..commit2 -L :functionName:filePath
的两次提交之间的函数历史记录
使用git log -L :sum\(double:filepath