Better git(1) diffs
Good old POSIX diff(1) can output diffs (patch files)
in serveral formats, "normal", ed(1), and the more useful
ones: copied context and the newer unified context.
git-diff(1) however can only output in unified context,
often it's quite good (although it is not fully-reverseble
if you ignore whitespace differences), however it can
become quite messy at times because it mixes the old
version and the new version in the same part of each hunk,
where as copied context first displays the old version
of the hunk and then the new version of the hunk (if
there is nothing removed however the old version is
skipped, and if there is nothing added, the new version
is skipped). In others words, copied context is similar
to side-by-side, except vertical. You can add the following
script to your PATH as git-cdiff, which
will let you type git cdiff instead of
git diff if you want to see your changes in
copied context format rather than unified context format.
#!/bin/sh
if test -z "${GIT_CDIFF_CONTEXT}"; then
git difftool -y -x "diff -c --color=always" "$@"
elif printf '%s' "${GIT_CDIFF_CONTEXT}" | grep -q '^-'; then
git difftool -y -x "diff ${GIT_CDIFF_CONTEXT} --color=always" "$@"
else
git difftool -y -x "diff -C${GIT_CDIFF_CONTEXT} --color=always" "$@"
fi | {
# this part of the pipeline is optional,
# it just makes GNU diff colouring bit nicer
if test "$TERM" = linux; then
sed '/^\(\x1b\[[0-9;]*m\)* /s/\x1b\[[0-9;]*m//g'
else
sed '/^\(\x1b\[[0-9;]*m\)* /s/^/\x1b\[2m/g'
fi
} | {
# this part of the pipeline is optional (and breaks diff format),
# it adds line number to the margin
if printf '%s' "${GIT_CDIFF_CONTEXT}" | grep -q '^-'; then
exec cat
fi
if test "$TERM" = linux; then
linecolour="35"
else
linecolour="2;35"
fi
lineno=x
while IFS= read -r line; do
if printf '%s\n' "$line" | \
sed 's/\x1b\[[0-9;]*m//g' | \
grep -q '^\(\*\*\* \|--- \)[0-9]*,[0-9]* \(\*\*\*\*\|----\)$'
then
lineno="$(printf '%s' "$line" | \
sed 's/\x1b\[[0-9;]*m//g' | \
sed 's/^\(\*\*\* \|--- \)\([0-9]*\),.*$/\2/')"
printf '%s\n' "$line"
elif test ! "$lineno" = x &&
printf '%s\n' "$line" | \
sed 's/\x1b\[[0-9;]*m//g' | \
grep -q '^\(!\|+\|-\| \) '
then
printf '\e[%sm%5i \e[m%s\n' "$linecolour" "$lineno" "$line"
lineno=$(( $lineno + 1 ))
else
lineno=x
printf '%s\n' "$line"
fi
done
} | {
if test -t 1; then
less -FRX
else
cat
fi
}