311

How can I exclude an entire directory from my Git diff (in this case /spec)?

I'm creating a diff for our entire software release using the git diff command. However, the changes to the spec folder are irrelevant for this procedure, and just create headaches. Now I know I can do

git diff previous_release..current_release app/

This would create a diff for all the changes in the app directory, but not for instance, in the lib/ directory. How can I accomplish this task?

I just want to be clear, I know I can just string the parameters of all of my directories on the end, minus /spec. I was hoping there was a way to truly exclude a single directory in the command.

2
  • 4
    I found this amazing question because I was aiming to ignore submodules. In this case, if you are as naive as me, this question can be more helpful. Commented Aug 23, 2012 at 20:53
  • That's strange that we still have no native Git switch for doing this on Sep 2016 Commented Sep 12, 2016 at 15:20

7 Answers 7

531

Based on this answer, you can also use:

git diff previous_release..current_release -- . ':!spec'

This is a newish Git feature which allows excluding certain paths. It should be more reliable than various shell one-liners.

I'm posting this here because this question is still the #1 hit for "git diff exclude path".

Since Git 2.13 (Q2 2017), you can replace ! with ^. The latter doesn't need quotes. So you can write it as:

git diff previous_release..current_release -- . :^spec
Sign up to request clarification or add additional context in comments.

12 Comments

Love this answer. If adding options then do so before the double dash. Eg: git diff previous_release current_release --name-status -- . ':!spec'
What worked for me git diff --stat dev -- . ':!/Mopy/Docs/*'. What did not work for me git diff dev --stat -- . ':!('Mopy/Docs/Wrye Bash General Readme.html'|'Mopy/Docs/Wrye Bash Advanced Readme.html')' and variations
Can also exclude multiple items like so: git diff previous_release current_release -- . ':!file_a' ':!file_b'
This works for me without needing any . after the --. Just git diff [..arguments...] -- ':!thing-to-exclude'
The manpage this is documented in is gitglossary.
|
151

Assuming you use Bash, and you've enabled extended globbing (shopt -s extglob), you could handle that from the shell side:

git diff previous_release current_release !(spec)

Saves you having to list all other things.

Or, shell-agnostic:

git diff previous_release current_release --name-only | grep -v '^spec/' \
    | xargs git diff previous_release current_release --

You could wrap that up in a one-liner shell script to save yourself having to retype the arguments.

7 Comments

P.S. globbing doesn't match hidden files, so if you're obsessive, you might want to tack on .!(.|) to match everything starting with a . besides . and ...
This doesn't seem to work for files that are brand new or deleted across branches. I get errors that halt execution of the script, saying it can't diff against it.
@Graham: I believe that the -- I just added should fix that.
Awesome answer. I only wanted names to show (not the actual diff) so I had to add --name-only at the very end as well.
After playing around with it, just wanna add that if you change the name of a file, it will throw an error but all you need to do is add -- path/of/new/file and it will figure it out :)
|
51

If you want to specify more than one path to exclude in a Git diff, you just add additional exclusion parameters to the end, e.g., to exclude everything in vendor and bin directories from the stats:

git diff --stat previous_release..current_release -- . ':!vendor' ':!bin'

Comments

46

Relative to the Git root directory

git diff accepts an optional exclude

git diff -- ":(exclude)thingToExclude"

You might want to add some wild cards

git diff -- ":(exclude)*/thingToExclude/*"

Target specific file types

git diff -- ":(exclude)*/$1/*.png"

Some syntactic sugar applied

git diff -- ":!/\$1/"

Or drop a little script for your dotfiles

Such as the $HOME/.bash_profile or $HOME/.zshrc files

gde() {
    : '
        git diff exclude files or folders
        usage:
        gde fileOrFolderNameToExclude
    '
    git diff -- ":!/\$1/"
}

2 Comments

Is this documented anywhere in the official docs? For some reason, I see no mention of this parameter. git-scm.com/docs/git-diff
Not directly but here's the documentation git-scm.com/docs/gitglossary#Documentation/…
38

You can try and unset the diff attribute for any files within the lib directory.
.gitattributes:

lib/* -diff

racl101 adds in the comments:

Just to add to this, for those of you who want to limit the git diff output of files of a specific type, within a specific directory and its subdirectories, like all the JavaScript generated by Webpack's bundling of your .js files, for example, you can add this to .gitattributes:

dist/js/**/*.js -diff

Then you don't see all that noise in your git diff output and it just shows as: Binary files ... differ which is more helpful.

6 Comments

this would remove spec from all of my diffs though. I still want to see my diffs in the spec folder normally, just not when i'm running this 'release' diff
@Mystr: You could set that .gitattributes file in a special branch made only for this kind of 'release' diff ;) Rebase that special branch on top of current_release and do your diff from there.
This, too doesn't seem to work for files that are deleted across branches. Files which were removed still show the complete diff.
Doesn't work for me. Are _ paths special? _site/* -diff
@MariusAndreiana No, '_' is not special. Can you check which gitattributes rule apply for a file of that folder with: git-scm.com/docs/git-check-attr
|
32

Git diff now accepts a custom exclusion format: git diff -- ':(exclude)lib/*'

Be careful if you have a lot of repetitive folder names ('/app', '/lib', etc.), as this will exclude files relative to the current working directory and the Git root directory.

5 Comments

are you missing a dot, shouldn't it rather be git diff -- . ':(exclude)lib/*'?
@NicolasDermine No, though what you wrote is equivalent. The "includes" portion of the path is also optional. That's why you can just do git diff for everything relative to your current path, rather than requiring git diff -- .
Note: on windows machines, use double quotes, like git diff -- ":(exclude)lib/*"
No idea why, but for me it works only with the dot, as suggested by @NicolasDermine . I use Cmder on win10.
When the folder to exclude was not a direct subfolder of the root folder of the diff I had to precede it with */ also. Ex. git diff -- . ":!*/lib/*" Using ! is shorthand for (exclude)
-11
git diff app lib

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.