3

The --unified=<n> option lets you set the number of lines; is there a way to do the same for characters?

example

limit the context around the changes to X character(s) when using git diff --color-words=. file.ext

special case to take into account

a change is within the context of the previous and/or next change

use case

diffing a minified file containing one long line

TL;DR

I want to snip everything in the line except the changes and their context.

  • related: unix.stackexchange.com/q/286601/7579 – Knu Jan 19 at 17:10
  • 1
    To be honest, I missed the point of you question. Do you really want a solution supporting colours? – doak Feb 12 at 22:04
  • Knu, never mind, updated answer should satisfy needs. – doak Feb 12 at 23:11
0

This script will do the job, at least as long escape sequences (for colouring) are as expected. Call it e.g. as git-diff-word-context -U 5. It accepts all arguments git diff would accept and intercepts -U (respectively --unified=) to set the number of characters. It just utilises grep to fulfil the task:

#!/usr/bin/env bash

ESCAPE=$'\e'
START_DIFF="$ESCAPE\\[3[12]m"
END_DIFF="$ESCAPE\\[m"
NOESCAPE="[^$ESCAPE]"

CONTEXT="20"
STDIN=false
ARGS=()
while [ "${1::1}" = "-" ]; do
    case "$1" in
        "-U"|"--unified")
            CONTEXT="$2"
            shift
            ;;
        "-U"*)
            CONTEXT="${1#-U}"
            ;;
        "--unified="*)
            CONTEXT="${1#--unified=}"
            ;;
        "--stdin")
            STDIN=true
            ;;
        "--")
            break
            ;;
        *)
            ARGS+=("$1")
            ;;
    esac
    shift
done

set -o pipefail

ok() {
    "$@"
    true
}

if $STDIN; then
    cat
else
    git diff --color-words='[^\n]' "${ARGS[@]}" "$@"
fi |
ok grep -oP "$NOESCAPE{0,$CONTEXT}(($START_DIFF[^$ESCAPE]+$END_DIFF)+$NOESCAPE{0,$CONTEXT})+"

The easiest way to call it is to configure a Git alias e.g. with git config alias.diffwc '!path/to/git-diff-word-context'.

You can also use it as a filter call it with option --stdin, for example git show --color-words | git-diff-word-context --stdin -U5.

To configure it as an external diff driver, you need to take additional measures (refer to GIT_EXTERNAL_DIFF within man git). Passing arbitrary arguments to git diff is IMHO especially difficult in that case.

Example

example output

  • My BSD grep 2.5.1 doesn't have a P option so git-diff-word-context -U 5 file.ext failed. – Knu Feb 13 at 5:28
  • It is quite easy to convert the used Perl regular expression to POSIX confirming ones. Please state your requirements in your question. – doak Feb 13 at 12:32
  • You seem to use FreeBSD, is this correct? ("This option is not supported in FreeBSD.") It is hard to find a solution without knowledge of constraints. – doak Feb 13 at 12:37
  • This is the line without Perl regular expressions: ok grep -o ".\\{0,$CONTEXT\\}\\($START_DIFF[^$ESCAPE]\\+$END_DIFF\\)\\+.\\{0,$CONTEXT\\}" – doak Feb 13 at 12:41
  • I tried the version "without Perl regular expressions" and it doesn't diff at a char level: it's not as granular as --color-words=.. – Knu Feb 13 at 14:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.