Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to combine output of `git diff --name-status` and `git diff --stat` commands?

Tags:

git

shell

diff

With git diff --name-status command I can see names of files with file status like this:

M       .bashrc
D       .ghc/.ghci.conf.un~
D       .ghc/ghci_history
M       .life
A       .profile
M       .spacemacs

With git diff --stat I can see statistics of line count and file changes:

 .bashrc             |   3 ++-
 .ghc/.ghci.conf.un~ | Bin 13912 -> 0 bytes
 .ghc/ghci_history   | 100 --------------------------------------------------------------------------------------------
 .life               |   2 ++
 .profile            |  23 +++++++++++++++++++++
 .spacemacs          |   3 +++

Is there any way to combine outputs of both commands? I would like to have something like this:

M  .bashrc             |   3 ++-
D  .ghc/.ghci.conf.un~ | Bin 13912 -> 0 bytes
D  .ghc/ghci_history   | 100 --------------------------------------------------------------------------------------------
M  .life               |   2 ++
A  .profile            |  23 +++++++++++++++++++++
M  .spacemacs          |   3 +++

Sure, I can do it manually by string calling both command and then manipulating strings. But I'm not sure how reliable and consistent outputs for these commands. Maybe it's documented somewhere. Could you, please, provide a shell command that will allow me to see such diffs from the terminal?

like image 275
Shersh Avatar asked Jan 02 '23 05:01

Shersh


2 Answers

DIFF=origin/master..HEAD
join -t $'\t' -1 2 -2 1 -o 1.1,2.1,2.2 \
        <(git diff --name-status $DIFF | sort -k2)
        <(git diff --stat=$((COLUMNS-4)),800 $DIFF | sed -e '$d' -e 's/^ *//;s/ /\t/' | sort) \
        | sed 's/\t/ /g'

Or, fully POSIX in an [alias] section of ~/.gitconfig

ndiff = "!f() { TAB=`printf '\t'`; COLUMNS=`stty size|cut -d' ' -f2`; cd $GIT_PREFIX; git diff --name-status $1 | sort -k2 > /tmp/.tmpgitndiff ; git diff --stat=$COLUMNS,800 $1 |sed -e '$d' -e \"s/^ *//;s/ /${TAB}/\" | sort | join -t \"${TAB}\" -1 2 -2 1 -o 1.1,2.1,2.2 /tmp/.tmpgitndiff - | sed \"s/${TAB}/ /g\"; rm -f /tmp/.tmpgitndiff; }; f"
$ git ndiff origin/master..HEAD -- dev/ # example
M dev/main.scss   |   9 +
A dev/rs.js       |  19 ++
like image 82
drzraf Avatar answered Jan 05 '23 10:01

drzraf


The quick-and-dirty was is to use wdiff:

$ wdiff -n -w '' -x '' -y '' -z '' <(git diff --name-status) <(git diff --stat)
vvv 2018-06-26 10:08:27-0700
M       foo/baz.py   | 19 +++++++++++--------
M       foo/bar.py   | 37 ++++++++-----------------------------
M       foo/qux.py   |  2 +-
 3 files changed, 20 insertions(+), 38 deletions(-)

The -[w-z] options set the delimiters for start/end of insertion/deletion.

-n ensures that output is linewise ... which probably doesn't matter when -[w-z] are passed, but is a good habit for wdiff in general.

Theoretically, this is prone to error if your filename looks like anything else on the line. Fortunately, good practice tends to eschew filenames like M, |, 19, and +++++++++++--------


The more correct way would be to use paste, but that would require passing the output through sed afterward to remove the duplicate parts.

like image 43
o11c Avatar answered Jan 05 '23 10:01

o11c