简体   繁体   English

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

[英]Git - how do I view the change history of a method/function?

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

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.我目前使用的语言是 Objective-C,我目前使用的 SCM 是 git,但我很想知道这个功能是否适用于任何 SCM/语言。

Recent versions of git log learned a special form of the -L parameter:最近版本的git log学习了-L参数的特殊形式:

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

Trace the evolution of the line range given by "<start>,<end>" (or the function name regex <funcname> ) within the <file> .跟踪<file>"<start>,<end>" (或函数名正则表达式<funcname> )给出的行范围的演变。 You may not give any pathspec limiters.您不能提供任何路径规范限制器。 This is currently limited to a walk starting from a single revision, ie, 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>”代替<start><end> ,它是一个正则表达式,表示从匹配<funcname>第一个 funcname 行到下一个 funcname 行的范围。 “:<funcname>” searches from the end of the previous -L range, if any, otherwise from the start of file. “:<funcname>”从前一个-L范围的末尾开始搜索,如果有的话,否则从文件的开头开始。 “^:<funcname>” searches from the start of file. “^:<funcname>”从文件开头搜索。

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.换句话说:如果您要求 Git git log -L :myfunction:path/to/myfile.c ,它现在会很高兴地打印该函数的更改历史记录。

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.使用git gui blame很难在脚本中使用,虽然git log -Ggit log --pickaxe可以分别显示方法定义出现或消失的时间,但我还没有找到任何方法让它们列出所有更改制作到你的方法的主体

However, you can use gitattributes and the textconv property to piece together a solution that does just that.但是,您可以使用gitattributestextconv属性将解决方案拼凑在一起。 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.关键是在执行任何差异操作之前,让 Git 从文件中删除除您感兴趣的行之外的所有行。 Then git log , git diff , etc. will see only the area you're interested in.然后git loggit diff等将只看到您感兴趣的区域。

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).编写一个简短的 shell 脚本(或其他程序),它接受一个参数——源文件的名称——并只输出该文件的有趣部分(如果没有有趣的部分,则不输出)。 For example, you might use sed as follows:例如,您可以按如下方式使用sed

     #!/bin/sh sed -n -e '/^int my_func(/,/^}/ p' "$1"
  • Define a Git textconv filter for your new script.为您的新脚本定义一个 Git textconv过滤器。 (See the gitattributes man page for more details.) The name of the filter and the location of the command can be anything you like. (有关更多详细信息,请参阅gitattributes手册页。)过滤器的名称和命令的位置可以是您喜欢的任何内容。

     $ git config diff.my_filter.textconv /path/to/my_script
  • Tell Git to use that filter before calculating diffs for the file in question.在计算相关文件的差异之前,告诉 Git 使用该过滤器。

     $ echo "my_file diff=my_filter" >> .gitattributes
  • Now, if you use -G.现在,如果您使用-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 的差异例程的任何其他选项,例如--patch ,也将获取此受限视图。

     $ 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.这使您只需调用git config指定感兴趣的新方法,而不必编辑脚本。 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.当然,过滤器脚本可以做任何你喜欢的事情,接受更多的参数,或者其他什么:除了我在这里展示的之外,还有很多灵活性。

git log has an option '-G' could be used to find all differences. git log有一个选项 '-G' 可用于查找所有差异。

-G Look for differences whose added or removed line matches the given <regex> . -G 查找添加或删除的行与给定<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

The closest thing you can do is to determine the position of your function in the file (eg say your function i_am_buggy is at lines 241-263 of foo/bar.c ), then run something to the effect of:您可以做的最接近的事情是确定您的函数在文件中的位置(例如,您的函数i_am_buggy位于foo/bar.c ),然后运行以下内容:

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.现在您可以输入/i_am_buggy (或您的寻呼机等效项)并开始逐步完成更改。

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.这将搜索从该正则表达式(最好是您的函数声明)的第一次命中限制为之后的 30 行。 The end argument can also be a regexp, although detecting that with regexp's is an iffier proposition. end 参数也可以是正则表达式,尽管用正则表达式检测是一个更确定的命题。

The correct way is to use git log -L :function:path/to/file as explained in eckes answer .正确的方法是使用git log -L :function:path/to/fileeckes 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.就像普通的diff一样。

Normally git log can view differences with -p , but this not work with -L .通常git log可以查看与-p差异,但这不适用于-L So you have to grep git log -L to show only involved lines and commits/files header to contextualize them.因此,您必须grep git log -L仅显示涉及的行和提交/文件标题以将它们上下文化。 The trick here is to match only terminal colored lines, adding --color switch, with a regex.这里的技巧是只匹配终端彩色线,添加--color开关,和一个正则表达式。 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 + [ .您可以通过在 bash 中按 ^V^[ 来输入它们,即Ctrl + VCtrl + [ Reference here .参考这里

Also last -3 switch, allows to print 3 lines of output context, before and after each matched line.最后一个-3开关,允许在每个匹配行之前和之后打印 3 行输出上下文。 You may want to adjust it to your needs.您可能需要根据自己的需要进行调整。

  1. Show function history with git log -L :<funcname>:<file> as showed in eckes's answer and git doc使用git log -L :<funcname>:<file>显示函数历史记录,如eckes 的回答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.如果它什么也没显示,请参阅定义自定义 hunk-header以将*.java diff=java类的内容添加到.gitattributes文件以支持您的语言。

  2. Show function history between commits with git log commit1..commit2 -L :functionName:filePath使用git log commit1..commit2 -L :functionName:filePath显示提交之间的函数历史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使用git log -L :sum\\(double:filepath

git blame shows you who last changed each line of the file; git blame显示谁最后更改了文件的每一行; you can specify the lines to examine so as to avoid getting the history of lines outside your function.您可以指定要检查的行,以避免在函数之外获取行的历史记录。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用方法更改指针? - How do I use a method to change a pointer? 如何从视图控制器中包含的视图中调用方法? - How Do I call a method from a view contained in a view controller ? 如何从另一个视图控制器调用方法 - How do I call a method from another view controller 如何在traitCollectionDidChange的视图控制器中更改UIImageView图像 - How do I change UIImageView image in view controller in traitCollectionDidChange 如何在地图套件视图中更改注释的图钉颜色 - How do I change the pin color of an annotation in map kit view 如何更改由UIPageViewController管理的视图控制器的背景颜色? - How do I change the background color of a view controller managed by a UIPageViewController? 弹出到视图控制器,如何在弹出的视图控制器中调用方法? - Popping to view controller, how do I call a method in the view controller I am popping to? 如何使方法更改根视图 - How to make an method change the root view 如何在&#39;loadView&#39;外部创建的按钮方法中更改&#39;self.view&#39; - How can I change 'self.view' within a button method created outside of 'loadView' 如何将父视图控制器设置为对象,以便可以调用其方法之一? - How do I set the parent view controller as an object so I can call one of it's method?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM