Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make git highlight tab characters in a diff?

Tags:

git

git-diff

I'm trying to ensure that I don't commit code that uses tab characters for indentation. This is a soft constraint that I'm applying to my own commits (right now we don't have a standard for indentation characters, but I'd like to use spaces, since there's no disagreement on the width of a space, but some people use width-4 tabs versus width-8 tabs).

The easiest way to check such constraints is often to look at the actual output of git diff every time you are about to commit and see if there are any problems. For example, for me, by default, trailing whitespace is highlighted and windows newlines are also visible in the diff, so if I'm about to accidentally commit code with trailing whitespace, I will be alerted to this. Is there a way to make tab characters also show up in git diff?

like image 671
jonderry Avatar asked Apr 06 '11 23:04

jonderry


2 Answers

Git learned the tab-in-indent whitespace category in 1.7.2 (2010 July 21).
From Documentation/RelNotes/1.7.2.txt:

  • The whitespace rules used in "git apply --whitespace" and "git diff" gained a new member in the family (tab-in-indent) to help projects with policy to indent only with spaces.

It is controlled and used in the same ways as the other whitespace checking options.

The highlighting in git diff is the same as the other whitespace errors.
Checking is available with git diff --check.
Et cetera.

Add tab-in-indent to the value of the core.whitespace configuration variable to enable it (probably either in one or more specific repositories or in your “global” (per-use) configuration).

set-show-tabs() {
    global=
    test "$1" = -g || test "$1" = --global && global=--global
    cws=$(git config $global core.whitespace)
    case "$cws" in
        tab-in-indent,*|*,tab-in-indent|*,tab-in-indent,*) ;;
        *) git config $global core.whitespace "$cws"${cws:+,}tab-in-indent ;;
    esac
}
set-show-tabs           # only in local repository
set-show-tabs --global  # for all your Git activities
# or just edit it manually with "git config [--global] --edit"

Or, you can set it for individual commands (git -c is also from 1.7.2):

git -c core.whitespace=tab-in-indent diff --check

You could use something like this in a pre-commit hook to check for tabs without having it in any of your actual repository configuration files.

like image 165
Chris Johnsen Avatar answered Nov 17 '22 14:11

Chris Johnsen


To locate lines with tabs:

git grep -n --cached 'LITERAL TAB HERE'

In bash or zsh you can enter a literal tab with Ctrl-V Ctrl-I. That command will show you all files+lines with tabs.

If you want to enforce your policy by preventing a commit with tabs, put this in .git/hooks/pre-commit and mark it executable (chmod +x):

#!/bin/sh
allowtabs=$(git config hooks.allowtabs)
if [ "$allowtabs" != "true" ] &&
   git diff --cached | egrep '^\+.* '>/dev/null
then
   cat<<END;
Error: This commit would contain a tab, which is against this repo's policy.

If you know what you are doing you can force this commit with:

  git commit --no-verify

Or change the repo policy like so:

  git config hooks.allowtabs true
END
  exit 1
fi

There's a literal tab between the * and the ' on the git diff --cached | egrep line. You can get this in Vim with Ctrl-V Ctrl-I, or Emacs with C-q C-i.

What it does is look for a new line in the diff (starting with "+") which contains a tab. You could put the git grep line in the error message if you want to show the offending tabs in the hook.

I've put this hook on github here.

like image 12
Matt Curtis Avatar answered Nov 17 '22 15:11

Matt Curtis