Git - how to view the change history of a method / function?

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

I know that code analysis will require git and the analysis will be different for different languages, but the declarations of methods / functions look very similar in most languages, so I thought that maybe someone implemented this function.

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

+77
git function methods objective-c history
Jan 24 '11 at 11:26
source share
5 answers

In recent versions of git log you recognize the special form of the -L option:

-L: <funcname>: <file>

Trace the evolution of the string range given by "<start>,<end>" (or the regular expression name <funcname> ) within the <file> . You cannot specify path delimiters. Currently, this is limited to a walk, starting with one revision, i.e. You can give only zero or one positive revision arguments. You can specify this option several times ....
If ":<funcname>" is specified instead of <start> and <end> , this is a regular expression that indicates the range from the first line of funcname that matches <funcname> , up to the next line of funcname. ":<funcname>" searches from the end of the previous -L range, if any, otherwise from the beginning of the file. "^:<funcname>" searches from the beginning of the 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 this function.

+74
Nov 27 '15 at 8:21
source share

Using git gui blame difficult to use in scripts, and while git log -G and git log --pickaxe can show you when a method definition appeared or disappeared, I did not find a way to make them list all the changes made in the body of your method.

However, you can use the gitattributes and textconv to put together a solution that does just that. Although these features were originally designed to help you work with binary files, they also work here.

The key is to have Git remove all lines from the file, except those that are of interest to you, before performing any diff operations. Then git log , git diff , etc. Only the area you are interested in will be seen.

Here are the outlines of what I am doing in another language; You can customize it for your needs.

  • Write a short shell script (or another program) that takes one argument - the name of the source file and displays only the interesting part of this file (or nothing if none of them are interesting). For example, you can use sed as follows:

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

     $ git config diff.my_filter.textconv /path/to/my_script 
  • Tell Git to use this filter before calculating the diff for the corresponding file.

     $ echo "my_file diff=my_filter" >> .gitattributes 
  • Now if you use -G. (pay attention to . ) to list all the commits that make visible changes when applying the filter, you will have exactly those commits that interest you. other options that use Git diff routines, such as --patch , will also get this limited view.

     $ git log -G. --patch my_file 
  • Voila!

One useful enhancement you might want to make is for your script filter to accept the method name as its first argument (and the second as a file). This allows you to specify a new method of interest by simply calling git config , instead of having to edit your script. For example, you can say:

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

Of course, the script filter can do whatever you like, accept more arguments, or something else: there is more flexibility than what I showed here.

+15
Jun 04 '13 at 23:45
source share

git log has the option '-G', which can be used to find all the differences.

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

Just give it the correct regular expression for the name of the function 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 
+10
Sep 05 '11 at 17:12
source share

The closest thing you can do is determine the position of your function in the file (for example, let's say your i_am_buggy function is on lines 241-263 of foo/bar.c ), and then run something as a result:

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

This will open less (or equivalent pager). Now you can enter /i_am_buggy (or your pager equivalent) and start /i_am_buggy changes.

This may even work, depending on the style of your code:

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

This limits the search from the first hit of this regular expression (ideally, a function declaration) to thirty lines after that. The end argument can also be a regular expression, although finding that with regexp is an iffier clause.

+9
Feb 07 '14 at 9:45
source share

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

+2
Jan 24 '11 at 11:28
source share



All Articles