With git I can set a custom diff tool that is used for certain file extensions by the following in .git/config
[diff "csv_diff"]
command = Tools/csv_diff
and this in .gitattributes
(in the root of the repository)
*.csv diff=csv_diff
This works when using git diff
, but it doesn't work with git show
. My question is, how do I use a custom tool with git show
?
Looks like you're looking for the --ext-diff
option.
Here's what git show
docs say about it:
--ext-diff
Allow an external diff helper to be executed. If you set an external diff driver with gitattributes
, you need to use this option with git-log
and friends.
Like @LucasTrzesniewski said, you can use --ext-diff
from the command line to set a diff for the current session.
You can also use the .gitattributes to set the git-diff perfile.
A git diff implementation exists of 2 parts:
- A definition in
$GIT_DIR/config
or $HOME/.gitconfig
- A bound between a file and a definition in
gitattributes
Git has choosing for this design to separate the executable code from the source code, this makes it impossible for a git clone
or other git command to run any harmful code.
Writing a definition
To write a definition, we start with a header consisting of [diff "namehere"]
, then followed by a line-break.
The next line consists of the command definition, this line is as follows: command = commandlinehere
. This command is then called with 7 arguments if it is ran, these are documented for the GIT_EXTERNAL_DIFF enviroment vriable in the docs.
GIT_EXTERNAL_DIFF
When the environment variable GIT_EXTERNAL_DIFF is
set, the program named by it is called, instead of the diff invocation
described above. For a path that is added, removed, or modified,
GIT_EXTERNAL_DIFF
is called with 7 parameters:
path old-file old-hex old-mode new-file new-hex new-mode where:
<old|new>-file are files GIT_EXTERNAL_DIFF can use to read the
contents of <old|new>,
<old|new>-hex are the 40-hexdigit SHA-1 hashes,
<old|new>-mode are the octal representation of the file modes.
The file parameters can point at the user’s working file (e.g.
new-file in "git-diff-files"), /dev/null (e.g. old-file when a new
file is added), or a temporary file (e.g. old-file in the index).
GIT_EXTERNAL_DIFF
should not worry about unlinking the temporary file, it is removed when GIT_EXTERNAL_DIFF
exits.
For a path that is unmerged, GIT_EXTERNAL_DIFF
is called with 1
parameter, <path>.
For each path GIT_EXTERNAL_DIFF
is called, two environment variables,
GIT_DIFF_PATH_COUNTER
and GIT_DIFF_PATH_TOTAL
are set.
The total example looks like this:
[diff "jcdiff"]
command = j-c-diff
Writing the gitattributes
We need to modify our gitattributes to use our custom driver. The gitattributes file consist of a syntax similar to filename value [value2 [value3 [value4 [...]]]]
.
Examples:
* diff=jcdiff
We to use our custom git diff for every file.
*.java diff=javadiff
*.python diff=pythondiff
Use javadiff for java files, pythondiff for python files.
* diff=globaldiff
*.java diff=javadiff
Use javadiff for java files, globaldiff for remaining files.
Configuring git to automatically set --ext-diff
You can add an alias using git config alias.showobject 'show --ext-diff'
to define a new command called git showobject
that automatically uses our filter.
As an alternate answer for others in search of using a diff tool like meld with git show
git difftool --tool=meld HEAD~..HEAD
Most of the time I like to see my small diffs on the command line because it's quick, but every once in a while I do want to boot up a diff tool to inspect things a little deeper - especially with the work of others. But this excludes the ability to use .gitattributes
because this would then be the default behavior.
In order to show a particular commit or branch, then I've created this alias in my ~/.gitconfig
[alias]
showm = "!f(){ if [ -z $1 ]; then c='HEAD'; else c=$1; fi; git difftool --tool=meld -y $c~..$c; }; f"
This will launch meld to show the diffs introduced by that commit:
git showm <branch or hash>
Without an argument, it will use HEAD
as a default:
git showm
As a bonus, you can follow that up with a bash alias to get tab completion for branch names by adding this to the ~/.bashrc
alias showm='git showm'
__git_complete showm _git_show
Its very simple, you yust have the wrong command-key in your git config.
It should be like this:
[diff "csv_diff"]
textconv = Tools/csv_diff
This works in git show
and all other places where a diff is displayed (even in gitk
).
I tried this with git version 2.24.1.windows.2
and this configfiles:
gitconfig
[diff "zip"]
textconv = unzip -c -a
[diff "tgz"]
binary = true
textconv = tar -xvzO -f
[diff "gz"]
binary = true
textconv = gunzip -c
gitattributes
*.zip diff=zip
*.tgz diff=tgz
*.tar.gz diff=tgz
*.sql.gz diff=gz
If your command don`t likes to have the filename as last parameter you can do somethime like this:
[diff "sqlite3"]
binary = true
textconv = "f() { sqlite3 $1 --readonly .dump; }; f"
Where the $1
stands for the place where the filename is inserted.
Maybe you must enclose $1
into single quotes to support filenames with spaces.