This is what the --word-diff git diff option does. Although not to the default level of detail.
For differences in a single --word-diff-regex like this, you will also need --word-diff-regex . (I have '([^[:alnum:]]|[^[:space:]])' in the git alias here, which seems to do it, though. Although it wasnβt when I wrote it.)
You can also shorten --word-diff=color --word-diff-regex='...' to --color-words='...' .
See if this does what you want:
$ cat worddiff.awk BEGIN { RS="\n?~\n" FS="\n" } # Special case the diff header/chunk header lines. /^diff --git/ { print next } { delete outs for (i=1; i<=NF; i++) { if ($i ~ /^[-+]/) { mode = substr($i, 1, 1) $i = ((mode=="-")?red:green) substr($i, 2) reset outs[mode] = outs[mode] $i reset outs["set" mode]++ } else { gsub(/^ /, "", $i) outs["-"] = outs["-"] $i outs["+"] = outs["+"] $i } } # If we didn't have any changes then this is a context line and we need to # print it out. if (!outs["set-"] && !outs["set+"]) { print " " outs["-"] next } if (outs["set-"]) { print red "-" reset outs["-"] } if (outs["set+"]) { print green "+" reset outs["+"] } }
Used as:
git diff --word-diff=porcelain | awk -v red="$(tput setaf 1)" -v green="$(tput setaf 2)" -v reset="$(tput sgr0)" -f worddiff.awk
or
git diff --word-diff-regex='([^[:alnum:]]|[^[:space:]])' --word-diff=porcelain | awk -v red="$(tput setaf 1)" -v green="$(tput setaf 2)" -v reset="$(tput sgr0)" -f worddiff.awk
This awk might have been cleaner, and there would have been an unexplored non-GNU awk split to clear the array, which I cannot remember if the problem is delete a .
Edit: updated code above to match the latest version of gist. The original special case model was overly permissive. The source code did not handle the added blank lines correctly. The updated code does not, but does everything possible that I consider possible, given the well-known limitations --word-diff=porcelain .
Etan reisner
source share