• Uncategorized

About git : Using-git-to-identify-all-modified-functions-in-a-revision

Question Detail

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?

Question Answer

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}' |  \

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

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/@@.*@@//'

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

You may also like...

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.