Git file History provides information about the commit history associated with a file. To use it: Go to your project's Repository > Files. In the upper right corner, select History.
`git log` command is used to view the commit history and display the necessary information of the git repository. This command displays the latest git commits information in chronological order, and the last commit will be displayed first.
If you have the hash for a commit, you can use the git show command to display the changes for that single commit. The output is identical to each individual commit when using git log -p .
If you want to see only the last change, you can use git log -p -1 -- b .
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.
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.
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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With