32

I would like the results of git diff to be filtered by the file name.

In particular, I want a diff for all of the files named "AssemblyInfo.cs", but located anywhere within the git repository.

I am using git on Cygwin, if that makes a difference.

Zantier
  • 833
  • 1
  • 8
  • 18

6 Answers6

39

The simplest method is to simply use a wildcard:

git diff -- '*AssemblyInfo.cs'


At least this works on my Git v1.8.4, bash 3.2, and zsh 5.7.

ijoseph
  • 6,505
  • 4
  • 26
  • 26
AggieBlue
  • 534
  • 5
  • 11
19

File arguments to git diff need to be delimited by -- - try this:

find . -name <pattern> | xargs git diff --

xargs makes sure spaces, tabs, newlines, etc are handled correctly.

You could debug it with the --name-status argument to git diff. You could also try:

git diff --name-only | grep <pattern>

[edit] Try:

git diff --name-status -- `find . -name '<pattern>'`
ebg@taiyo(98)$ git diff --name-status -- `find . -name '*.scm'`
M       scheme/base/boolean.scm
M       surf/compiler/common.scm
M       surf/compiler/compile.scm
M       surf/compiler/expand.scm
GoZoner
  • 67,920
  • 20
  • 95
  • 145
  • This seems to do the same as just `git diff`, but leaves out the last file. – Zantier Mar 15 '13 at 18:25
  • Maybe the last file didn't change. Please debug with my suggestions above. If it is still unclear, post the output of my debug suggestions in your original question. – GoZoner Mar 15 '13 at 18:31
  • `git diff --name-only | grep AssemblyInfo.cs` indeed gives the correct file names, as I would expect, but I need full diff output. Both `find . -name AssemblyInfo.cs | xargs git diff --` and `find . -name AssemblyInfo.cs | xargs git diff --name-status --` are giving files that are not "AssemblyInfo.cs" (such as .sql files). – Zantier Mar 19 '13 at 09:36
  • I was having the same problem with the edit. I have resolved it now and added my own answer. – Zantier Mar 19 '13 at 17:26
  • 2
    The proper 'StackOverflow' approach is to say "Thank you Gozoner, based on your answer I've figured it out" and then reward me with the checkmark. Not to post your own answer. – GoZoner Mar 19 '13 at 17:33
  • 2
    Sorry, how rude of me! Thanks for your help. This was the solution that finally worked for me: `find . -name "AssemblyInfo.cs" -print0 | xargs -0 git diff --` – Zantier Mar 19 '13 at 17:51
6

Probably the simplest option is to use:

git diff "*/*AssemlyInfo.cs"

works as of git 2.20.1

rkwatra
  • 195
  • 1
  • 3
  • 5
    It should be `"**/*AssemblyInfo.cs"` to search for files anywhere in the repository, and not under only 1 level nested directories. Once this correction done, it's the best answer to the question and should be the accepted answer. – papillon Mar 23 '20 at 09:43
0

You can use pipeline

find . -name AssemblyInfo.cs | git diff

Use find to filter all the files named "AssemblyInfo.cs", then use the output as the parameter of git diff.

pktangyue
  • 8,326
  • 9
  • 48
  • 71
  • 1
    This doesn't seem to be filtering the diff. I did line counts just to check: `$ git diff | wc -l 1110 $ find . -name AssemblyInfo.cs | git diff | wc -l 1110` – Zantier Mar 15 '13 at 18:03
  • @Zantier what is the output of `find . -name AssemblyInfo.cs`? – pktangyue Mar 15 '13 at 18:05
  • `find . -name AssemblyInfo.cs` is working correctly, giving the paths to all the "AssemblyInfo.cs" files. – Zantier Mar 15 '13 at 18:06
  • @Zantier I don't know why you add `wc -l 1110`, and what does `1110` means? – pktangyue Mar 15 '13 at 18:07
  • Sorry, I'm pretty new to StackOverflow, and didn't know I couldn't put it on a separate line. It's the output of the command. Both commands have a line count of 1110. – Zantier Mar 15 '13 at 18:16
0

While the answer given by GoZoner works for some (hundred?) files, it executes git diff multiple times (in the case of xargs) or fails (in the case of git diff … -- `find …`) if there is a large number of files to diff. This might be a problem or not, depending on your use case.

A possible solution is to create a commit containing only changes to files of interest and diff the commits. Based on an answer on unstaging files matching some pattern I came up with this solution:

git co <new_branch> --detach
git reset --soft <old_branch>

Now git status --porcelain | grep <pattern> shows all files that should be compared. All other files can be listed by passing -v to grep, i.e. git status --porcelain | grep -v <pattern>. This files need to be reset to the state of <old_branch>:

# Remove the destination of renamed and copied files not matching <pattern>
git status --porcelain | grep -v <pattern> | grep '^R \|^C ' | sed 's/.* -> //' | xargs git rm -f --
# Remove added files not matching <pattern>
git status --porcelain | grep -v <pattern> | grep '^A ' | cut -c 4- | xargs git rm -f --
# Restore deleted files not matching <pattern>
git status --porcelain | grep -v <pattern> | grep '^M \|^D ' | cut -c 4- | xargs git checkout HEAD --

(Note that using xargs is not a problem in this case, as calling git rm and git checkout multiple times is ok.)

Now the index (and working copy) only contains changes to the files matched by <pattern>. The next thing to do is to commit this changes:

git commit -m "Changes between <old_branch> and <new_branch> in files matching <pattern>"

That's it! Now we can use git diff as usual:

git diff HEAD^..HEAD

You can use all options or arguments you like.

Note: This solution is not tested extensively and may fail e.g. on files with special characters or other special cases… Suggestions to improve the solution are welcome ;-)

Community
  • 1
  • 1
siegi
  • 5,646
  • 2
  • 30
  • 42
0
find . -iregex AssemblyInfo\.cs -exec git diff {} +

you can replace the AssemblyInfo\.cs with your regex.

shampoo
  • 1,173
  • 12
  • 22