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

发布于 2024-10-14 03:04:08 字数 243 浏览 5 评论 0原文

所以我发现了关于如何查看文件的更改历史记录的问题,但是这个特定文件的更改历史记录是巨大的,我真的只对特定方法的更改感兴趣。那么是否可以查看该特定方法的更改历史记录?

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

我当前使用的语言是 Objective-C,我当前使用的 SCM 是 git,但我有兴趣知道任何 SCM/语言是否存在此功能。

So I found the question about how to view the change history of a file, but the change history of this particular file is huge and I'm really only interested in the changes of a particular method. So would it be possible to see the change history for just that particular method?

I know this would require git to analyze the code and that the analysis would be different for different languages, but method/function declarations look very similar in most languages, so I thought maybe someone has implemented this feature.

The language I'm currently working with is Objective-C and the SCM I'm currently using is git, but I would be interested to know if this feature exists for any SCM/language.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

烟酉 2024-10-21 03:04:08

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

-L ::<文件>

跟踪由 ","(或函数名称正则表达式 )给出的行范围的演变<文件>。您不能给出任何路径规范限制器。目前这仅限于从单个修订开始的遍历,即您只能给出零个或一个正修订参数。您可以多次指定此选项。
...
如果用 “: 代替 ,则它是一个正则表达式表示从匹配 的第一个 funcname 行到下一个 funcname 行的范围。 “: 从前一个 -L 范围的末尾(如果有)搜索,否则从文件开头搜索。 “^: 从文件开头搜索。

换句话说:如果你要求 Git git log -L :myfunction:path/to/myfile.c ,它现在会愉快地打印该函数的更改历史记录。

Recent versions of git log learned a special form of the -L parameter:

-L :<funcname>:<file>

Trace the evolution of the line range given by "<start>,<end>" (or the function name regex <funcname>) within the <file>. You may not give any pathspec limiters. This is currently limited to a walk starting from a single revision, i.e., you may only give zero or one positive revision arguments. You can specify this option more than once.
...
If “:<funcname>” is given in place of <start> and <end>, it is a regular expression that denotes the range from the first funcname line that matches <funcname>, up to the next funcname line. “:<funcname>” searches from the end of the previous -L range, if any, otherwise from the start of file. “^:<funcname>” searches from the start of file.

In other words: if you ask Git to git log -L :myfunction:path/to/myfile.c, it will now happily print the change history of that function.

流云如水 2024-10-21 03:04:08

您能做的最接近的事情就是确定函数在文件中的位置(例如,假设您的函数 i_am_buggy 位于 foo/bar.c 的第 241-263 行) ,然后运行一些命令,其效果如下:

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

这将打开 less (或等效的寻呼机)。现在您可以输入 /i_am_buggy (或您的寻呼机等效项)并开始逐步完成更改。

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

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

这会将搜索从该正则表达式的第一次命中(理想情况下是您的函数声明)限制为之后的三十行。 end 参数也可以是正则表达式,尽管用正则表达式检测是一个不确定的命题。

The closest thing you can do is to determine the position of your function in the file (e.g. say your function i_am_buggy is at lines 241-263 of foo/bar.c), then run something to the effect of:

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

This will open less (or an equivalent pager). Now you can type in /i_am_buggy (or your pager equivalent) and start stepping through the changes.

This might even work, depending on your code style:

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

This limits the search from the first hit of that regex (ideally your function declaration) to thirty lines after that. The end argument can also be a regexp, although detecting that with regexp's is an iffier proposition.

生生不灭 2024-10-21 03:04:08

在脚本中使用 git guiblame 很难使用,而 git log -G 和 git log --pickaxe 都可以向您展示当方法定义出现或消失时,我还没有找到任何方法让它们列出对方法的主体所做的所有更改。

但是,您可以使用 gitattributestextconv 属性来拼凑出一个解决方案来实现这一点。尽管这些功能最初是为了帮助您处理二进制文件,但它们在这里也同样有效。

关键是让 Git 在执行任何 diff 操作之前从文件中删除除您感兴趣的行之外的所有行。然后 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. --修补我的文件
    
  • 瞧!

您可能想要进行的一个有用的改进是让过滤器脚本将方法名称作为其第一个参数(并将文件作为第二个参数)。这使您只需调用 git config 即可指定感兴趣的新方法,而不必编辑脚本。例如,您可能会说:

$ git config diff.my_filter.textconv "/path/to/my_command other_func"

当然,过滤器脚本可以做任何您喜欢的事情,接受更多参数,或者其他什么:除了我在这里展示的之外,还有很多灵活性。

Using git gui blame is hard to make use of in scripts, and whilst git log -G and git log --pickaxe can each show you when the method definition appeared or disappeared, I haven't found any way to make them list all changes made to the body of your method.

However, you can use gitattributes and the textconv property to piece together a solution that does just that. Although these features were originally intended to help you work with binary files, they work just as well here.

The key is to have Git remove from the file all lines except the ones you're interested in before doing any diff operations. Then git log, git diff, etc. will see only the area you're interested in.

Here's the outline of what I do in another language; you can tweak it for your own needs.

  • Write a short shell script (or other program) that takes one argument -- the name of a source file -- and outputs only the interesting part of that file (or nothing if none of it is interesting). For example, you might use sed as follows:

    #!/bin/sh
    sed -n -e '/^int my_func(/,/^}/ p' "$1"
    
  • Define a Git textconv filter for your new script. (See the gitattributes man page for more details.) The name of the filter and the location of the command can be anything you like.

    $ git config diff.my_filter.textconv /path/to/my_script
    
  • Tell Git to use that filter before calculating diffs for the file in question.

    $ echo "my_file diff=my_filter" >> .gitattributes
    
  • Now, if you use -G. (note the .) to list all the commits that produce visible changes when your filter is applied, you will have exactly those commits that you're interested in. Any other options that use Git's diff routines, such as --patch, will also get this restricted view.

    $ git log -G. --patch my_file
    
  • Voilà!

One useful improvement you might want to make is to have your filter script take a method name as its first argument (and the file as its second). This lets you specify a new method of interest just by calling git config, rather than having to edit your script. For example, you might say:

$ git config diff.my_filter.textconv "/path/to/my_command other_func"

Of course, the filter script can do whatever you like, take more arguments, or whatever: there's a lot of flexibility beyond what I've shown here.

心的位置 2024-10-21 03:04:08

git log 有一个选项“-G”可用于查找所有差异。

-G 查找添加或删除的行与
给定 .

只需给它一个您关心的函数名称的正确正则表达式即可。例如,

$ 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

git log has an option '-G' could be used to find all differences.

-G Look for differences whose added or removed line matches the
given <regex>.

Just give it a proper regex of the function name you care about. For example,

$ 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
无人问我粥可暖 2024-10-21 03:04:08

正确的方法是使用 git log -L :function:path/to/fileeckes 答案中所述

但此外,如果您的函数很长,您可能只想查看各个提交引入的更改,而不是整个函数行(包括未修改的),因为每个提交可能只涉及这些行之一。就像普通的 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

请注意,^[ 应该是实际的、文字的^[。您可以通过在 bash 中按 ^V^[ 来输入它们,即 Ctrl + VCtrl + [ 。请参考此处

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

The correct way is to use git log -L :function:path/to/file as explained in eckes answer.

But in addition, if your function is very long, you may want to see only the changes that various commit had introduced, not the whole function lines, included unmodified, for each commit that maybe touch only one of these lines. Like a normal diff does.

Normally git log can view differences with -p, but this not work with -L.
So you have to grep git log -L to show only involved lines and commits/files header to contextualize them. The trick here is to match only terminal colored lines, adding --color switch, with a regex. Finally:

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

Note that ^[ should be actual, literal ^[. You can type them by pressing ^V^[ in bash, that is Ctrl + V, Ctrl + [. Reference here.

Also last -3 switch, allows to print 3 lines of output context, before and after each matched line. You may want to adjust it to your needs.

渔村楼浪 2024-10-21 03:04:08
  1. 使用 git log -L ::显示函数历史记录,如 eckes的回答git doc

    如果没有显示任何内容,请参阅定义自定义 hunk-header 添加一些内容例如 *.java diff=java.gitattributes 文件以支持您的语言。

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

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

  1. Show function history with git log -L :<funcname>:<file> as showed in eckes's answer and git doc

    If it shows nothing, refer to Defining a custom hunk-header to add something like *.java diff=java to the .gitattributes file to support your language.

  2. Show function history between commits with git log commit1..commit2 -L :functionName:filePath

  3. Show overloaded function history (there may be many function with same name, but with different parameters) with git log -L :sum\(double:filepath

乖乖 2024-10-21 03:04:08

gitblame 显示最后更改每一行的人文件的;您可以指定要检查的行,以避免获取函数外部行的历史记录。

git blame shows you who last changed each line of the file; you can specify the lines to examine so as to avoid getting the history of lines outside your function.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文