Git-如何查看方法/功能的更改历史记录?


91

因此,我发现了一个有关如何查看文件更改历史记录的问题,但是此特定文件的更改历史记录非常庞大,我实际上只对特定方法的更改感兴趣。那么是否有可能仅查看该特定方法的更改历史记录?

我知道这将需要git来分析代码,并且对于不同的语言,分析也会有所不同,但是在大多数语言中,方法/函数的声明看起来非常相似,所以我认为也许有人实现了此功能。

我目前使用的语言是Objective-C,而我目前使用的SCM是git,但是我想知道此功能是否适用于任何SCM /语言。


1
我已经在Git GSoG提案中看到了这种功能。
六。

这是您在谈论的提案吗?list-archives.org/git/…–
Erik B


@lpapp这里的问题是10个月前提出的,另一个问题应标记为这个问题的伪造(如果它们完全是伪造的)。
肮脏的流量

2
@lpapp这是两个完全不同的问题。您可能编写了一个脚本,该脚本将函数名解析为一系列行,然后使用该问题中的技术来获取这些行的历史记录,但其本身无法回答该问题。
Erik B

Answers:


97

最新版本git log学习了-L参数的特殊形式:

-L:<函数名>:<文件>

追踪内"<start>,<end>"(或函式名称regex <funcname>)所指定行范围的演变<file>。您不得提供任何pathspec限制器。当前,这仅限于从单个修订版开始的遍历,即,您只能给出零个或一个正修订版参数。您可以多次指定此选项。
...
如果“:<funcname>”代替<start>和给出<end>,则它是一个正则表达式,表示从匹配的第一个funcname行<funcname>到下一个funcname行的范围。“:<funcname>”从上一个-L范围的末尾(如果有)搜索,否则从文件的开头搜索。“^:<funcname>”从文件开头搜索。

换句话说:如果您要求Git to git log -L :myfunction:path/to/myfile.c,它将立即愉快地打印该功能的更改历史记录。


15
这对于开箱即用的Objective-C可能有效,但是如果您要针对其他语言(例如Python,Ruby等)执行此操作,则可能需要在.gitattributes文件中添加适当的配置,以便git识别功能/方法使用该语言的声明。对于python使用* .py diff = python,对于ruby使用* .rb diff = ruby
samaspin

1
git如何跟踪功能?
nn0p

我假设@ nn0p具有几种语言的语法知识,因此知道如何隔离函数并跟踪其更改。
JasonGenX

4
扩展@samaspin的注释,对于其他语言,您可以在这里参考文档:git-scm.com/docs/gitattributes#_generating_diff_text
edhgoose

对于使用嵌套花括号(常规表达式无法正常处理)的Scala和Java甚至C语言来说,这是行不通的,并且即使在函数移动到文件中后,start,end形式也不起作用。并在同一提交中进行了修改。
罗宾·格林

16

使用git gui blame难以利用的脚本,并同时git log -Ggit log --pickaxe可以各自显示您何时该方法的定义出现或消失,我还没有找到任何办法使它们列出来所做的所有更改身体的方法。

但是,您可以使用gitattributestextconv属性组合实现此目的的解决方案。尽管这些功能最初是为了帮助您使用二进制文件,但它们在这里同样适用。

关键是让Git从文件中删除所有您感兴趣的行,然后再执行任何diff操作。然后git log,,git diff等只会看到您感兴趣的区域。

这是我用另一种语言所做的工作的概述;您可以根据自己的需要进行调整。

  • 编写一个简短的shell脚本(或其他程序),该脚本带有一个参数(源文件的名称),并且仅输出该文件的有趣部分(如果没有有趣的部分,则不输出)。例如,您可以使用sed以下方式:

    #!/bin/sh
    sed -n -e '/^int my_func(/,/^}/ p' "$1"
  • textconv为新脚本定义一个Git 过滤器。(有关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"

当然,筛选器脚本可以执行您喜欢的任何操作,接受更多参数或执行其他操作:除了我在此处显示的内容以外,还有很多灵活性。


1
接受一个以上的参数对我来说不起作用,但是将函数名称加在硬名称上可以很好地工作,这确实很棒!
qwertzguy 2014年

很棒,尽管我不知道在许多不同的方法之间切换是多么的不方便。另外,您是否知道可以提取整个类C函数的程序?
nafg

12

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

5
我没有运行该命令,但在我看来,该命令仅会显示与正则表达式匹配的行的提交,而这并不是整个方法/函数。
Erik B

如果您需要更多背景信息,则可以替换--oneline-p
lfender6445

3
但是,如果对该方法进行了20行更改,该怎么办?
nafg

+1。对我而言,最佳答案有效,但仅显示最新提交。可能由于变基或功能移动了几次,不确定。通过搜索实际的代码行而不是其所在的功能(尽管只有一个代码),此答案使我可以轻松地发现所需的提交。值得庆幸的是,我通常会编写有用的提交消息!
戴夫S

11

您可以做的最接近的事情是确定函数在文件中的位置(例如,说您的函数i_am_buggy在的第241-263行foo/bar.c),然后执行以下操作:

git log -p -L 200,300:foo/bar.c

这将打开较少(或等效的寻呼机)。现在,您可以输入/i_am_buggy(或与您的寻呼机等效)并开始逐步进行更改。

这甚至可能有效,具体取决于您的代码样式:

git log -p -L /int i_am_buggy\(/,+30:foo/bar.c

这将搜索从该正则表达式的第一次匹配(最好是您的函数声明)搜索到其后的三十行。结束参数也可以是一个正则表达式,尽管检测的是与正则表达式的是iffier命题。


甜!仅供参考,这是Git v1.8.4中的新功能。(猜猜我应该升级。)虽然更精确的解决方案会很好……就像有人编写了Paul Whittaker的答案一样。
格雷格价格

@GregPrice 显然,搜索的边缘甚至可以是正则表达式,因此您至少可以有一个或多或少的精确起点。
badp 2014年

哦,哇 实际上:不用编写自己的正则表达式,只需说出-L ":int myfunc:foo/bar.c"并限制使用该名称的函数即可。这太棒了-感谢您的指导!现在,如果仅功能检测更加可靠...
Greg Price

3

正确的方法是git log -L :function:path/to/file按照eckes答案中的说明使用。

但是此外,如果您的函数很长,那么对于每个可能仅涉及这些行之一的提交,您可能只想查看各种提交所引入的更改,而不是整个函数行(包括未修改的)。像平常一样diff

通常git log可以查看与的差异-p,但这不适用于-L。因此,您grep git log -L只需要显示涉及的行和commits / files标头即可将它们上下文化。这里的窍门是只匹配终端彩色线,并--color使用正则表达式添加开关。最后:

git log -L :function:path/to/file --color | grep --color=never -E -e "^(^[\[[0-9;]*[a-zA-Z])+" -3

请注意,它^[应该是实际的,字面的^[。您可以通过按bash中的^ V ^ [来键入它们,即Ctrl+ VCtrl+ [。参考这里

也是最后一个-3开关,允许在每条匹配的行之前和之后打印3行输出上下文。您可能需要对其进行调整。


2

git blame显示最后更改文件每一行的人;您可以指定要检查的行,以避免使行的历史超出您的功能范围。


4
git gui blame您可以浏览旧版本。
六。

0
  1. 显示函数历史与git log -L :<funcname>:<file>作为表现出eckes的回答git的文档

    如果未显示任何内容,请参阅定义自定义的粗体标题*.java diff=java以在.gitattributes 文件中添加类似内容以支持您的语言。

  2. 显示提交之间的函数历史 git log commit1..commit2 -L :functionName:filePath

  3. 显示重载的函数历史记录(可能有许多具有相同名称但具有不同参数的函数) git log -L :sum\(double:filepath

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.