11

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...)

Steve Bennett
  • 114,604
  • 39
  • 168
  • 219

2 Answers2

2

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

Community
  • 1
  • 1
Steve Bennett
  • 114,604
  • 39
  • 168
  • 219
1

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.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Yeah, I'm now trying another tack, using git alias with a script to parse the file: http://stackoverflow.com/questions/10512351/bash-script-to-select-a-single-python-function-from-a-file I was inspired by this post, which I ran into completely randomly: http://davidwalsh.name/git-aliases – Steve Bennett May 09 '12 at 08:32
  • @SteveBennett Interesting approach. I have included it in the answer for more visibility, and to contrast this ad-hoc solution with the lack of a more "generic" feature. – VonC May 09 '12 at 08:54