How to not leave trailing whitespace (using your editor or Git)

Updated . Posted . Visible to the public.

There is no reason to leave trailing whitespace characters in your project's files, so don't add any.

A git diff --check will tell you if there are any and you should not commit when you see them. So go ahead and switch your editor/IDE to automatically remove them for you.
Below are a few instructions on how to get them removed by your favorite IDE or editor.

Note that except for RubyMine, the following changes will remove trailing white-space on all lines, not only those that you changed.
While this should not be a problem if your project is always clean of trailing spaces, it may not be what you want if you are in the wild west.

In that case you need to take care not to commit trailing spaces. Always git diff --check, kids!

RubyMine

  • Open Settings (Ctrl-Alt-S)
  • Go to "Editor" → "General"
  • At the bottom, set "Strip trailing white spaces on Save" to "Modified Lines"

Sublime Text 2

  • Open the "Preferences" menu
  • Choose "File Settings – Default" (it will open Base File.sublime-settings for you)
  • Set "trim_trailing_white_space_on_save": true

Vim

  • Open up your ~/.vimrc file

  • Add this:

    autocmd BufWritePre * :%s/\s\+$//e
    

If that is too invasive for you, try only highlighting trailing spaces like suggested in the Vim wiki Show archive.org snapshot (also put this into your ~/.vimrc):

" Show trailing whitepace and spaces before a tab:
:highlight ExtraWhitespace ctermbg=red guibg=red
:autocmd Syntax * syn match ExtraWhitespace /\s\+$\| \+\ze\t/

TextMate

  • The Text bundle offers a command Remove Trailing Spaces in Document / Selection, which you can call before saving. This is not aware of git (i.e., which lines YOU have edited).
  • In the bundle editor, assign it a shortcut like Cmd + Alt + Backspace.
  • Update: Since 9-29-2012, TextMate2 has a callback will-save. In the above command, set 'Semantic class' to callback.document.will-save, and it will be called before saving the document.

Git (manually)

Git can fix whitespace in patches which you can make use of: git diff --cached --no-color > stage.diff && git apply --index -R stage.diff && git apply --index --whitespace=fix stage.diff && rm -f stage.diff. Store this as an alias and run before committing.

Git (automatically before commit)

You can tell git to react on trailing whitespace in a pre-commit hook. By default it will cancel a commit that contains trailing whitespace (and disallow non-ascii filenames), but you can modify it to automatically fix the whitespace, see below. (Note that this might lead to unexpected behaviour e.g. in Markdown documents.)

The global git hooks Show archive.org snapshot live in $PREFIX/share/git-core/templates/hooks (where $PREFIX is probably /usr/local or /usr). Rename the pre-commit.sample file to pre-commit to activate it. Afterwards, you'll need to re-initialize already cloned repositories with git init, which will essentially copy all hooks from the templates directory to that repository's .git/hooks. (You can always bypass the pre-commit hook by committing with the --no-verify option.)

In order to have git fix whitespace on lines you edited before each commit, append the following code to the pre-commit hook template (but before existing whitespace checks like exec git diff-index --check --cached $against --):

# A git hook script to find and fix trailing whitespace in your commits. Bypass
# it with the --no-verify option to git-commit.

# detect platform
platform="win"
uname_result=`uname`
if [[ "$uname_result" == "Linux" ]]; then
  platform="linux"
elif [[ "$uname_result" == "Darwin" ]]; then
  platform="mac"
fi

# change IFS to ignore filename's space in |for|
IFS="
"

# remove trailing whitespace in modified lines
for line in `git diff --check --cached | sed '/^[+-]/d'` ; do
  # get file name
  if [[ "$platform" == "mac" ]]; then
    file="`echo $line | sed -E 's/:[0-9]+: .*//'`"
    line_number="`echo $line | sed -E 's/.*:([0-9]+).*/\1/'`"
  else
    file="`echo $line | sed -r 's/:[0-9]+: .*//'`"
    line_number="`echo $line | sed -r 's/.*:([0-9]+).*/\1/'`"
  fi

  # since $file in working directory isn't always equal to $file in index,
  # we backup it; thereby we can add our whitespace fixes without accidently
  # adding unstaged changes
  backup_file="${file}.working_directory_backup"
  cat "$file" > "$backup_file"
  git checkout -- "$file" # discard unstaged changes in working directory

  # remove trailing whitespace in $file (modified lines only)
  if [[ "$platform" == "win" ]]; then
    # in windows, `sed -i` adds ready-only attribute to $file (I don't kown why), so we use temp file instead
    sed "${line_number}s/[[:space:]]*$//" "$file" > "${file}.bak"
    mv -f "${file}.bak" "$file"
  elif [[ "$platform" == "mac" ]]; then
    sed -i "" "${line_number}s/[[:space:]]*$//" "$file"
  else
    sed -i "${line_number}s/[[:space:]]*$//" "$file"
  fi
  git add "$file" # to index, so our whitespace changes will be committed

  # restore unstaged changes in $file from its working directory backup, fixing
  # whitespace that we fixed above
  sed "${line_number}s/[[:space:]]*$//" "$backup_file" > "$file"
  rm "$backup_file"
  
  [[ "$platform" == "mac" ]] || e_option="-e" # mac does not understand -e
  echo $e_option "Removed trailing whitespace in \033[31m$file\033[0m:$line_number"
done

echo

# credits:
# https://github.com/philz/snippets/blob/master/pre-commit-remove-trailing-whitespace.sh
# https://github.com/imoldman/config/blob/master/pre-commit.git.sh

# If there still are whitespace errors, print the offending file names and fail.
exec git diff-index --check --cached $against --

# Now we can commit
exit
Arne Hartherz
Last edit
Arne Hartherz
License
Source code in this card is licensed under the MIT License.
Posted by Arne Hartherz to makandra dev (2012-09-21 12:58)