bashgitgit-diff

Allow different behaviour for external diff tool if git command is piped


I'm using difftastic for better visualisation of my diffs in my terminal. Which means my config is

git config --global diff.external difft

However, when the output is not a tty, I'd rather have git use it's internal diff tool (e.g. the same as doing git diff --no-ext-diff but without me having to type that). So basically

$ git diff # please use difft
# git diff | cat # please use no external diff tool

However, I'm struggling with that because I cannot find a way to bubble up this information to my diff tool. Let's say I have some pseudo diff tool that actually just shows content of argv, first line of argc and check if its stdout is a tty:

#!/usr/bin/env ruby

require "io/console"
require "logger"
require "pp"

f = File.open("mygitdiff.log", "a")
f.puts("\n---- #{Time.now}")
PP.pp(ARGV, f)
PP.pp(gets, f)
f.puts("STDOUT.tty? #{STDOUT.tty?}")

This script prints the same log whether I am piping or not:

---- 2022-08-02 18:57:30 +0200
["bin/new",
 "/var/folders/v5/1p20ylgn0db5621r8wtdg5v80000gn/T//37FrIz_new",
 "c2a6c5aafc3485755f774cb3efcae4a2819a777f",
 "100755",
 "bin/new",
 "0000000000000000000000000000000000000000",
 "100755"]
"#!/usr/bin/env ruby\n"
STDOUT.tty? false

---- 2022-08-02 18:57:34 +0200
["bin/new",
 "/var/folders/v5/1p20ylgn0db5621r8wtdg5v80000gn/T//jaEmlN_new",
 "c2a6c5aafc3485755f774cb3efcae4a2819a777f",
 "100755",
 "bin/new",
 "0000000000000000000000000000000000000000",
 "100755"]
"#!/usr/bin/env ruby\n"
STDOUT.tty? false

As you can see there is no major difference there. Do you have any other idea how to achieve that goal?

Also note that the first line of argv, I don't understand at all what it means


Solution

  • A solution is to create a new git bin file, and put it in your path somewhere before the original git path (for me /usr/bin). The wrapper will decide whether an external diff tool should be used depending on the stdout state:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[]) {
        if (isatty(fileno(stdout)) && isatty(fileno(stderr))) {
            setenv("GIT_EXTERNAL_DIFF", "difft", 1);
        }
    
        execvp("/usr/bin/git", argv);
    }
    

    source