4

Is there a good way to use git to identify all the modified functions in each revision in the history? I've tried using the -p switch, but it doesn't seem to work in the same way that svn's show-c-function parameter works.

My assumption is that I'll want to use "git diff HEAD~i HEAD~i-1 -p" for increasing values of i. Am I missing some parameters that will help identify diff's best guess on the functions that were modified?

swrittenb
  • 326
  • 2
  • 13
  • Can you explain a little more clearly what you're looking for? What is the show-c-function behavior from Subversion that you're trying to replicate? How would you like it to identify functions changed? What would you want the output to look like? – Brian Campbell Apr 19 '11 at 19:30
  • For each revision, if a .c file was affected and some change occurred inside of a function, I'd like to have the corresponding function definition. For example, if int foo()'s body was changed, I'd like to see "int foo()" in a similar fashion to svn's show-c-function. – swrittenb Apr 19 '11 at 19:31
  • I wonder if something specifically built for javascript was there. that would be great – sktguha Apr 21 '17 at 09:34
  • For Java, see prototype at https://github.com/monperrus/git-api-diff – Martin Monperrus Apr 15 '18 at 13:13

3 Answers3

9

Here is a magic chant to list functions within a git diff *

git diff |                  \
grep -E '^(@@)' |           \
grep "(" |                  \
sed 's/@@.*@@//' |          \
sed 's/(.*//' |             \
awk -F " " '{print $NF}' |  \
uniq

...and what it does is...

  1. Picks the current diff,
  2. next picks only lines with "hunk-headers" ,
  3. next picks only lines with opening parenthesis (as potentially containing function names),
  4. next ignores the hunk headers,
  5. next ignores the text after the opening parenthesis,
  6. next picks only the word immediately before the opening parenthesis,
  7. and lastly ignores multiple occurrences of the same word in the list.

Voila! you have a list of functions being modified by the current git diff.


* Verified using git version 2.7.4 on Ubuntu 16.04 running bash.

TheCodeArtist
  • 21,479
  • 4
  • 69
  • 130
  • Also, it doesn't work if the function definition is printed in the diff as then it isn't printed as a header. It works well to extract from the headers. – Loren Oct 18 '17 at 19:45
  • 1
    For this to work, you mist have a `.gitattributes` file specifying the language per file so diff finds the right headers. Instructions on creating one: https://stackoverflow.com/a/7347993/3854385 – Loren Oct 18 '17 at 20:16
  • Also for C/C++ can improve by stripping leading * & – zr. Jul 07 '18 at 06:20
4

Here's a quick and dirty attempt at what I think you're going for. It does a git log to show all revisions, -p to include the diff in the log, a grep to only include the lines containing the commit ID and the hunk headers, and uses sed to filter out the line numbers, leaving only the guess at the function name that Git writes after the hunk header.

git log -p | grep -E '^(commit|@@)' | sed 's/@@.*@@//'
Brian Campbell
  • 322,767
  • 57
  • 360
  • 340
0

You can list all modified functions in a revision by using git textconv filters. The idea is to create a specific filter that lists all functions/methods, and for all functions, a checksum of the body. This gives this kind of filtered textconv view:

m() 12
bar() 42

(here m() is a function signature, 12 is a checksum of its body))

When git diff uses this filter on the two versions before and after the revision:

  • if a function is added, a line is added in the diff

Example: foo is added

m() 12
+ foo() 24 
bar() 42
  • if a function is modified, the checksum changes, and a line is updated in the diff

Example: the body of foo is modified

m() 12
- foo() 23 
+ foo() 24 
bar() 42

How to do that?

  1. Create the filter: java-ls-methods.groovy is an implementation of such a filter using Groovy and Spoon
  2. Register this filter in git: git config diff.java-ls-methods.textconv /home/path/to/java-ls-methods.groovy
  3. Associate this filter with Java files: echo "*.java diff=java-ls-methods" >> .gitattributes
  4. Make the diff: git diff (diff against last commit) or git diff master (diff against another branch)
  5. Once your diff is done, comment the line in .gitattributes to go back to a normal diff

Credits: solution inspired from https://stackoverflow.com/a/16929266

Martin Monperrus
  • 1,845
  • 2
  • 19
  • 28