Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Limit Git Diff to one or more functions?

I set *.py diff=python in .git/info/attributes. So Git knows where function boundaries. git diff -W can even make sure the whole function is shown.

But is there a way to limit the output of a git diff to just a particular function (or more than one)?

(Failing that, I guess it's awk...)

EDIT This would also be useful for git log and git rev-list: don't show me every commit that modifies views.py, show me commits that modify a certain function in it. (Yes, in an ideal world, views.py wouldn't be a 2000 line behemoth frequently modified by 8 different developers...)

like image 863
Steve Bennett Avatar asked May 07 '12 07:05

Steve Bennett


2 Answers

Ok, thanks to Birei, we have a solution.

Use the awk script in that answer, combined with a bit of bash:

~/scripts/grit:

#!/bin/bash
cmd=$1
shift 1
if [ "$cmd" = "" ]; then
  git
# other commands not relevant to this question go here
elif [ $cmd = "funcdiff" ]; then
  git show "$1:$3" | awk -f ~/scripts/getfunc.awk -v f=$4 > /tmp/.tmp1
  git show "$2:$3" | awk -f ~/scripts/getfunc.awk -v f=$4 > /tmp/.tmp2
  git diff -W --no-index /tmp/.tmp1 /tmp/.tmp2 

else
  git $cmd $@
fi

Example usage: grit funcdiff 009e75 8b7a14 ./staging.py write_uploaded

This could also be added as a git alias in ~/.gitconfig

like image 91
Steve Bennett Avatar answered Oct 15 '22 20:10

Steve Bennett


I didn't find any other option (other than the --function-context or its -W short option, already mentioned) able to restrict a diff output to a single function.

And even that -W option isn't always enough, knowing that a 'function' can vary greatly from language to language, as illustrated in this blog post:

I’ve found this option rather unreliable, at least within a large PHP class.
My tests found --function-context often results in displaying almost all of the original file, and git appears ignorant of PHP’s function boundaries.
The number of context lines before and after a change seem random, and the diff doesn’t necessarily always show all lines of the function, either.

The original patch message that introduced this change sheds some light:

This implementation has the same shortcoming as the one in grep, namely that there is no way to explicitly find the end of a function.
That means that a few lines of extra context are shown, right up to the next recognized function begins.

So it appears detecting a function’s boundaries is difficult for git.
It seems in this instance, git never detects a function boundary and gives us the context of the entire file.


As the OP Steve Bennett points out, a potential solution would be to define a git alias which would extract the function in the revision before and after modification, in order to diff on those 2 'temp' files.
Example in "Creating Git Aliases" and "Bash script to select a single Python function from a file".

This is an ad-hoc solution which will be able to parse the specific type of source the OP happens to work with in his repo.

like image 43
VonC Avatar answered Oct 15 '22 20:10

VonC