173

On doing git diff --stat some files are listed with full path from repository base but some files are listed as:

.../short/path/to/filename. 

That is the path starts with ... and only short path is shown.

I would like git diff to list full file path for all files for it to be easily processed by a script. Is there some way I can get git diff to always show full path

8 Answers 8

175

By default git diff truncates its output to fit into a 80-column terminal.

You can override this by specifying values using the --stat option:

--stat[=<width>[,<name-width>[,<count>]]] Generate a diffstat. You can override the default output width for 80-column terminal by --stat=<width>. The width of the filename part can be controlled by giving another width to it separated by a comma. By giving a third parameter <count>, you can limit the output to the first <count> lines, followed by ... if there are more. These parameters can also be set individually with --stat-width=<width>, --stat-name-width=<name-width> and --stat-count=<count>. 

For example, by setting the output value to a very large number:

git diff --stat=10000 

Note that produces the path relative to the root of the git repository.

(For scripting you might want to use git diff-tree directly since it's more of a "plumbing" command, although I suspect you'll be fine either way. Note that you need the same extra text with --stat when using git diff-tree. The essential difference between using the git diff "porcelain" front end, and the git diff-tree plumbing command, is that git diff looks up your configured settings for options like diff.renames to decide whether to do rename detection. Well, that, plus the front end git diff will do the equivalent of git diff-index if you're comparing a commit with the index, for instance. In other words, git diff reads your config and invokes the right plumbing automatically.)

Sign up to request clarification or add additional context in comments.

10 Comments

git diff --numstat is the same as diff-tree
Note that to limit the width of the last part (+++/---) you can use a separate --stat-graph-width=... switch. Note also that setting high --stat-graph-width= and --stat-name-width= is not enough, you must also set --stat-width= big enough to cover the two.
@jakub.g: good point. Based on a bit of digging in the git source, this went in with git 1.7.10.
Is there any way to globalize this? Typing it every time is crazy.
@bfontaine: Yes: git diff-tree always compares two existing tree objects inside the repository. That is, it cannot look outside the repository at all, nor can it look at the index, so --no-index is not available here. It's a bit of a problem since there's no --porcelain option to git diff though! The workaround, if you really need one, is to create a tree object from some directory in the file system (using a temporary index and git write-tree).
|
38

For script processing, it might be better to use one of the following:

# list just the file names git diff --name-only path/to/modified/file path/to/renamed/file # list the names and change statuses: git diff --name-status M path/to/modified/file R100 path/to/existing/file path/to/renamed/file # list a diffstat-like output (+ed lines, -ed lines, file name): git diff --numstat 1 0 path/to/modified/file 0 0 path/to/{existing => renamed}/file 

These each become more handy for robust script processing when combined with the -z option, which uses NUL as the field terminators.

2 Comments

According to my tests you do not receive the full path of the resource using these commands. For now I only see relative paths for deleted files. I don't know if this is only the case for these files.
All outpu will return paths relative to git rev-parse --show-toplevel. The original problem was referring to truncated paths, which is a problem in diffstats, particularly for long filenames or a low value for --stat-name-width. The commands above will not truncate the paths, but will show the "full" path as requested, albeit still relative to the repository root.
21

For Bash users, you can use the $COLUMNS variable to automatically fill the available terminal width:

git diff --stat=$COLUMNS 

Very long path names might still be truncated; in this case, you can reduce the width of the +++/--- part using --stat-graph-width, for example this limits it to 1/5 of the terminal width:

git show --stat=$COLUMNS --stat-graph-width=$(($COLUMNS/5)) 

For a more generic solution, you could use the output of tput cols to determine the terminal width.

6 Comments

Is there any way to globalize --stat=$COLUMNS,$COLUMNS? Typing it every time is crazy.
@Rudie add export COLUMNS to your ~/.bashrc, and in your ~/.gitconfig under [alias], add smart-diff = ! "gitsmartdiff() { git diff $2 --stat=$COLUMNS,$COLUMNS; }; gitsmartdiff"
@user151841 That changes only diff. I want it to work for merges and pulls etc too. (Can't even manually do it there.) I don't think GIT supports it.
@Rudie Well, after the pull or merge is complete, you can diff between the previous and the new hashes.
@user151841 Sure, but merging already gives a stat summary. Without parameters/config. It'd be great if all 'stat summaries' used the same config.
|
8

There’s an option --name-only: git diff --name-only. The option is also supported by other git commands like show and stash.

Paths don’t get shortened with the option.

1 Comment

There's also a corresponding option for git diff-tree but there are other options you need to specify like git diff-tree --name-only -r --no-commit-id HEAD. See my answer stackoverflow.com/a/67330880/1507124 for more info
3

A simple solution I found was to do this: (only works on *nix, sorry no osx)

git diff --stat=$COLUMNS --relative | head -n -1 | cut -c 2- | xargs -d '\n' -P4 printf "$(pwd)/%s\n" 

This version works for both, but it doesn't look great on osx.

git diff --stat=$COLUMNS --relative | sed -e '$ d' | cut -c 2- | xargs -n4 -I{} echo "$(pwd)/{}" 

1 Comment

I found that just using --relative helped me immensely. (I already use the --stat width options.
3

git diff is a porcelain (user friendly) command. For scripting purposes, you probably want to use the corresponding plumbing command git diff-tree.

You can get git diff-tree to output the full paths, relative to the git repository, using a combination of the --name-only, -r and --no-commit-id options.

Examples

Paths of files changed in the "last" (the HEAD) commit of the current branch.

git diff-tree --name-only -r --no-commit-id HEAD 

Paths of files in the last commit on the main branch

git diff-tree --name-only -r --no-commit-id main 

Paths of files of the last three commits on the main branch

git diff-tree --name-only -r main main~3 

Paths of the files of the last commit under path src/

git diff-tree --name-only -r --no-commit-id main src/ 

Absolute paths of the files changed in the last commit on the current branch

git diff-tree --name-only -r --no-commit-id --line-prefix=`git rev-parse --show-toplevel`/ HEAD 

Explanation

git diff-tree compares the blobs of two treeish objects.

A commit is a treeish object, which points to the objects in the repository root. Directories are also treeish objects whereas files are blobs.

Running git diff-tree HEAD will compare the blobs of HEAD and HEAD~1 and contain the difference in blobs of the repository root. To see all the changed files that are not in the root, we need to descend into the directory treeish objects. This is achieved using the -r (as in recurse) option.

Note that this allows one two compare arbitrary directories in arbitrary commits.

By default, if only one commit object is specified, it's compared to its parent. Ie, running git diff-tree HEAD is equivalent to git diff-tree HEAD HEAD~1. If you only specified one commit as the treeish object, the parent commit id is displayed. Using --no-commit-id gets rid of this.

git-diff-tree prints a lot of information we don't want (ids, permissions, whether it's an add, delete, modification). We just want the name, so we use --name-only.

If we wanted absoluted paths, we need to prefix all lines using something like git rev-parse --show-toplevel. This gets the absolute path of the repository, without the trailing /. So we add that.

--line-prefix=`git rev-parse --show-toplevel`/ 

Comments

0

I created the following git alias:

diffstat = ! "gitdiffstat() { git diff --stat=$(tput cols) ${1:-master} ; }; gitdiffstat" 

It reads the column count from the tput cols command. It defaults to diffing against master, but you can optionally specify another branch.

$ git diffstat .gitalias | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 

Comments

-1

I found that the behaviour of diff --stat changed somewhere around git 1.7.10 where previously it would shorten file paths to a fixed width by default - it now displays as much as your terminal window will allow. If you are experiencing this problem, make sure you upgrade to 1.8.0 or newer.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.