156

Is there a way to limit git diff to changed files?

I'd like to see the differences between two commits, but exclude paths that don't exist in one or the other (additions/deletions). The following Perl one-liner illustrates most of what I want:

git diff master.. | perl -lnwe 'print unless /^(new|deleted) file/../^diff/ and not /^diff/'

But that leaves diff --git a/path b/path lines for the files that were new or deleted. Plus it'd be much nicer if I didn't have to parse (also fails if any hunk contains anything matching /^diff/, for example).

Another alternative I tried was:

git diff --name-status (args) | perl -lnwe 'print if s/^M\s+//' | xargs git diff (args) --

Its output is better, but it still feels hackish.

benizi
  • 4,046
  • 5
  • 28
  • 25

5 Answers5

286

You are looking for --diff-filter=M to show only files Modified between the two branches.

From man git-diff

--diff-filter=[ACDMRTUXB*]

Select only files that are

  • A Added
  • C Copied
  • D Deleted
  • M Modified
  • R Renamed
  • T have their type (mode) changed
  • U Unmerged
  • X Unknown
  • B have had their pairing Broken
  • * All-or-none

Any combination of the filter characters may be used.

When * (All-or-none) is added to the combination, all paths are selected if there is any file that matches other criteria in the comparison; if there is no file that matches other criteria, nothing is selected.

Also, these upper-case letters can be downcased to exclude. E.g. --diff-filter=ad excludes added and deleted paths.

ruohola
  • 21,987
  • 6
  • 62
  • 97
zen
  • 12,613
  • 4
  • 24
  • 16
  • 2
    Please avoid a stupid error of mine when using --diff-filter=AMR to omit deleted files: If you are removing a file 'x' then git diff HEAD HEAD~1 --name-only --diff-filter=AMR will still list 'x'. Why? Because _from_ HEAD _towards_ HEAD~1 the file was added, not removed. – Christoph Grimmer Apr 23 '14 at 08:42
  • 2
    Description for T is confusing. From `man git diff` "have their type (i.e. regular file, symlink, submodule, ...) changed (T)," – grimsock Oct 16 '15 at 19:48
  • If you want to use use `R` (renamed files) you need to use the `-M` expanded it is known as `--find-renames` – ccjjmartin Aug 15 '17 at 01:18
  • where are these different types documented? basically, A, D, M, T, and R are straightforward I'd love to know what C, U, X, and B imply. – DanCat Apr 30 '19 at 22:13
  • 4
    Nice and another answer point out that lowercase means exclusion. Very handy to exclude deleted files. – Philippe Rathé Feb 24 '20 at 22:34
28

As Git 2.10 (Q3 2016) will remind us, there is an easier way to "show everything except added/deleted files." (actually since Git 1.8.5, July 2013)

 git diff --diff-filter=ad master..

See commit 16726cf (14 Jul 2016) by Junio C Hamano (gitster).
(Merged by Junio C Hamano -- gitster -- in commit 2f8c654, 08 Aug 2016)

diff: document diff-filter exclusion

In v1.8.5 days, 7f2ea5f (diff: allow lowercase letter to specify what change class to exclude, 2013-07-17) taught the "--diff-filter" mechanism to take lowercase letters as exclusion, but we forgot to document it.

So the documentation on diff-options now (finally) includes:

These upper-case letters can be downcased to exclude.
E.g. --diff-filter=ad excludes added and deleted paths.

Make sure to use Git 2.36 (Q2 2022).

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
5

You can use the --diff-filter flag to do precisely this. git diff --diff-filter=CMRTUXB master.. should show everything except added/deleted files.

Lily Ballard
  • 182,031
  • 33
  • 381
  • 347
5

To see all modified and new files you can use

git diff --name-only --diff-filter=ACMR PREV_VERSION master

PREV_VERSION is the hash of your first commit.

To get an export as zip you can use this code

git archive --output=export.zip HEAD $(git diff --name-only --diff-filter=ACMR PREV_VERSION HEAD)

Note: .gitignore is not in export.zip

iwg
  • 498
  • 3
  • 3
0

I've used Notepad++ (Windows), and these regular expressions to filter out extension types and certain paths from a diff file.

^Index.*\.(dll|pdb|exe|txt|zip|log|ism|resx|tlog|htm|lib)$[\s\S.]*?^Index
^Index: Shared/.+$[\s\S.]*?^Index
^Index: Next/source/Utility/.+$[\s\S.]*?^Index

Only problem is, when it reaches the end. You have to 'ctrl+home' and go again until it finds nothing.

(Replace whats found with 'Index')