Type M-x delete-trailing-whitespace to delete all trailing whitespace. This command deletes all extra spaces at the end of each line in the buffer, and all empty lines at the end of the buffer; to ignore the latter, change the variable delete-trailing-lines to nil .
Some editors automatically remove trailing whitespace, some don't. This creates diff noise and can cause merge conflicts. You should coordinate with the people you're working with (colleagues, open-source crowd) what strategy everybody is using and make sure you all use the same strategy.
Python String strip() function will remove leading and trailing whitespaces. If you want to remove only leading or trailing spaces, use lstrip() or rstrip() function instead.
Those settings (core.whitespace
and apply.whitespace
) are not there to remove trailing whitespace but to:
core.whitespace
: detect them, and raise errorsapply.whitespace
: and strip them, but only during patch, not "always automatically"I believe the git hook pre-commit
would do a better job for that (includes removing trailing whitespace)
Note that at any given time you can choose to not run the pre-commit
hook:
git commit --no-verify .
cd .git/hooks/ ; chmod -x pre-commit
Warning: by default, a pre-commit
script (like this one), has not a "remove trailing" feature", but a "warning" feature like:
if (/\s$/) {
bad_line("trailing whitespace", $_);
}
You could however build a better pre-commit
hook, especially when you consider that:
Committing in Git with only some changes added to the staging area still results in an “atomic” revision that may never have existed as a working copy and may not work.
For instance, oldman proposes in another answer a pre-commit
hook which detects and remove whitespace.
Since that hook get the file name of each file, I would recommend to be careful for certain type of files: you don't want to remove trailing whitespace in .md
(markdown) files!
Another approach, suggested by hakre in the comments:
You can have two spaces at end of line in markdown and not have it as trailing whitespace by adding "
\
" before\n
.
Then a content filter driver:
git config --global filter.space-removal-at-eol.clean 'sed -e "s/ \+$//"'
# register in .gitattributes
*.md filter=space-removal-at-eol
You can trick Git into fixing the whitespace for you, by tricking Git into treating your changes as a patch. In contrast to the "pre-commit hook" solutions, these solutions add whitespace-fixing commands to Git.
Yes, these are hacks.
The following Git aliases are taken from
my ~/.gitconfig
.
By "robust" I mean that these aliases run without error, doing
the right thing, regardless of whether the tree or index are dirty. However, they don't work if an interactive git rebase -i
is already in progress; see my ~/.gitconfig
for additional checks if you care about this corner case, where the git add -e
trick described at the end should work.
If you want to run them directly in the shell, without creating a Git alias, just copy and paste everything between the double quotes (assuming your shell is Bash like).
The following fixws
Git alias fixes all whitespace errors in the index,
if any, but doesn't touch the tree:
# Logic:
#
# The 'git stash save' fails if the tree is clean (instead of
# creating an empty stash :P). So, we only 'stash' and 'pop' if
# the tree is dirty.
#
# The 'git rebase --whitespace=fix HEAD~' throws away the commit
# if it's empty, and adding '--keep-empty' prevents the whitespace
# from being fixed. So, we first check that the index is dirty.
#
# Also:
# - '(! git diff-index --quiet --cached HEAD)' is true (zero) if
# the index is dirty
# - '(! git diff-files --quiet .)' is true if the tree is dirty
#
# The 'rebase --whitespace=fix' trick is from here:
# https://stackoverflow.com/a/19156679/470844
fixws = !"\
if (! git diff-files --quiet .) && \
(! git diff-index --quiet --cached HEAD) ; then \
git commit -m FIXWS_SAVE_INDEX && \
git stash save FIXWS_SAVE_TREE && \
git rebase --whitespace=fix HEAD~ && \
git stash pop && \
git reset --soft HEAD~ ; \
elif (! git diff-index --quiet --cached HEAD) ; then \
git commit -m FIXWS_SAVE_INDEX && \
git rebase --whitespace=fix HEAD~ && \
git reset --soft HEAD~ ; \
fi"
The idea is to run git fixws
before git commit
if you have
whitespace errors in the index.
The following fixws-global-tree-and-index
Git alias fixes all whitespace
errors in the index and the tree, if any:
# The different cases are:
# - dirty tree and dirty index
# - dirty tree and clean index
# - clean tree and dirty index
#
# We have to consider separate cases because the 'git rebase
# --whitespace=fix' is not compatible with empty commits (adding
# '--keep-empty' makes Git not fix the whitespace :P).
fixws-global-tree-and-index = !"\
if (! git diff-files --quiet .) && \
(! git diff-index --quiet --cached HEAD) ; then \
git commit -m FIXWS_SAVE_INDEX && \
git add -u :/ && \
git commit -m FIXWS_SAVE_TREE && \
git rebase --whitespace=fix HEAD~2 && \
git reset HEAD~ && \
git reset --soft HEAD~ ; \
elif (! git diff-files --quiet .) ; then \
git add -u :/ && \
git commit -m FIXWS_SAVE_TREE && \
git rebase --whitespace=fix HEAD~ && \
git reset HEAD~ ; \
elif (! git diff-index --quiet --cached HEAD) ; then \
git commit -m FIXWS_SAVE_INDEX && \
git rebase --whitespace=fix HEAD~ && \
git reset --soft HEAD~ ; \
fi"
To also fix whitespace in unversioned files, do
git add --intent-to-add <unversioned files> && git fixws-global-tree-and-index
These versions are easier to copy and paste, but they don't do the right thing if their side conditions are not met.
Using git add -e
to "edit" the patches with the identity editor :
:
(export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .) && git checkout . && git reset
git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset --soft HEAD~
git add -u :/ && git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset HEAD~
export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .
trickBefore I learned about the git rebase --whitespace=fix
trick from this answer I was using the more complicated git add
trick everywhere.
If we did it manually:
Set apply.whitespace
to fix
(you only have to do this once):
git config apply.whitespace fix
This tells Git to fix whitespace in patches.
Convince Git to treat your changes as a patch:
git add -up .
Hit a+enterto select all changes for each file. You'll get a warning about Git fixing your whitespace errors.
(git -c color.ui=auto diff
at this point reveals that your non-indexed changes are exactly the whitespace errors).
Remove the whitespace errors from your working copy:
git checkout .
Bring back your changes (if you aren't ready to commit them):
git reset
The GIT_EDITOR=:
means to use :
as the editor, and as a command
:
is the identity.
I found a Git pre-commit hook that removes trailing white space.
#!/bin/sh
if git-rev-parse --verify HEAD >/dev/null 2>&1 ; then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# Find files with trailing whitespace
for FILE in `exec git diff-index --check --cached $against -- | sed '/^[+-]/d' | sed -r 's/:[0-9]+:.*//' | uniq` ; do
# Fix them!
sed -i 's/[[:space:]]*$//' "$FILE"
git add "$FILE"
done
exit
On macOS (or, likely, any BSD), the sed command parameters have to be slightly different. Try this:
#!/bin/sh
if git-rev-parse --verify HEAD >/dev/null 2>&1 ; then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# Find files with trailing whitespace
for FILE in `exec git diff-index --check --cached $against -- | sed '/^[+-]/d' | sed -E 's/:[0-9]+:.*//' | uniq` ; do
# Fix them!
sed -i '' -E 's/[[:space:]]*$//' "$FILE"
git add "$FILE"
done
Save this file as .git/hooks/pre-commit
-- or look for the one that's already there, and paste the bottom chunk somewhere inside it. And remember to chmod a+x
it too.
Or for global use (via Applying a git post-commit hook to all current and future repos) you can put it in $GIT_PREFIX/git-core/templates/hooks
(where GIT_PREFIX is /usr or /usr/local or /usr/share or /opt/local/share) and run git init
inside your existing repos.
According to git help init
:
Running
git init
in an existing repository is safe. It will not overwrite things that are already there. The primary reason for rerunninggit init
is to pick up newly added templates.
I'd rather leave this task to your favorite editor.
Just set a command to remove trailing spaces when saving.
OK, this is a new tack on solving this problem… My approach is to not use any hooks, but rather use filters and Git attributes. This allows you to set up, on each machine you develop on, a set of filters that will strip extra trailing white space and extra blank lines at the end of files before committing them.
Then set up a .gitattributes file that says which types of files the filter should be applied to. The filters have two phases, clean
which is applied when adding files to the index, and smudge
which is applied when adding them to the working directory.
First, tell your global configuration to use a global attributes file:
git config --global core.attributesfile ~/.gitattributes_global
Now, create the filter:
git config --global filter.fix-eol-eof.clean fixup-eol-eof %f
git config --global filter.fix-eol-eof.smudge cat
git config --global filter.fix-eol-eof.required true
Finally, put the fixup-eol-eof
script somewhere on your path, and make it executable. The script uses sed to do some on the fly editing (remove spaces and blanks at the end of lines, and extraneous blank lines at the end of the file)
fixup-eol-eof should look like this:
#!/bin/bash
sed -e 's/[ ]*$//' -e :a -e '/^\n*$/{$d;N;ba' -e '}' $1
My gist of this
Lastly, create or open file ~/.gitattributes_global in your favorite text editor and add lines like:
pattern attr1 [attr2 [attr3 […]]]
So if we want to fix the white space issue, for all of our C source files we would add a line that looks like this:
*.c filter=fix-eol-eof
The filter has two phases. The clean phase which is applied when things are added to the index or checked in, and the smudge phase when Git puts stuff into your working directory.
Here, our smudge is just running the contents through the cat
command which should leave them unchanged, with the exception of possibly adding a trailing newline character if there wasn’t one at the end of the file.
The clean command is the white space filtering which I cobbled together from notes at http://sed.sourceforge.net/sed1line.txt. It seems that it must be put into a shell script. I couldn’t figure out how to inject the sed command, including the sanitation of the extraneous extra lines at the end of the file directly into the git-config file. (You can get rid of trailing blanks, however, without the need of a separate sed script. Just set the filter.fix-eol-eof
to something like sed 's/[ \t]*$//' %f
where the \t
is an actual tab, by pressing Tab.)
The require = true
causes an error to be raised if something goes wrong, to keep you out of trouble.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With