Make Git automatically remove trailing white space before committing
Asked Answered
D

17

242

I'm using Git with my team and would like to remove white space changes from my diffs, logs, merges, etc. I'm assuming that the easiest way to do this would be for Git to automatically remove trailing white space (and other white space errors) from all commits as they are applied.

I have tried to add the following to the ~/.gitconfig file, but it doesn't do anything when I commit. Maybe it's designed for something different. What's the solution?

[core]
    whitespace = trailing-space,space-before-tab
[apply]
    whitespace = fix

I'm using Ruby in case anyone has any Ruby specific ideas. Automatic code formatting before committing would be the next step, but that's a hard problem and is not really causing a big problem.

Dort answered 26/2, 2009 at 18:52 Comment(3)
If the core.whitespace directive doesn't fix your issues, you can also change the pre-commit hook (.git/hooks/pre-commit) to find and fix them for you. See this post for a detailed description.Selfsupport
I got frustrated with similar whitespace errors and partial solutions, and wrote a flexible and fairly feature-complete utility which can fix or simply report whitespace errors that bedevil version control systems: Whitespace Total Fixer on Github (apologies if this is too self-promotional)Snaggy
It seems like an independent tool that continually monitors the folder for changed files and modifies them would be easier.Undetermined
C
124

Those settings (core.whitespace and apply.whitespace) are not there to remove trailing whitespace but to:

  • core.whitespace: detect them, and raise errors
  • apply.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:

  • temporarily: git commit --no-verify .
  • permanently: 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
Corrigendum answered 26/2, 2009 at 19:19 Comment(10)
Turns out git can be convinced to fix whitespace in your working copy via apply.whitespace, by tricking git into treating your working copy changes as a patch. See my answer below.Tavey
> "you don't want to remove trailing whitespace in .md (markdown) files" - Why is that? What is the purpose of trailing whitespace in markdown files? I noticed some .editorconfig files have a specific rule for that.Radius
@Radius depending on the type of markdown, a trailing double space indicate <br>: github.com/FriendsOfPHP/PHP-CS-Fixer/issues/…Corrigendum
Setting core.whitespace to trailing-space with git config does not raise error when committing in git 2.5.0.Barbican
You can have two spaces at end of line in markdown and not have it as trailing whitespace by adding "\" before \n. Mind thought that not all tools that say they handle Markdown support all of Markdown so YMMV.Sain
What I'm wondering a bit is why there ain't a filter for the configured whitespace rules in git. git config --global filter.space-removal-at-eol.clean 'sed -e "s/ \+$//"' is what I have with .gitattributes *.md filter=space-removal-at-eol as I was getting tired to fix all those little things after writing markdown. Now discovering the whitespace configuration more and more, wondering if this approach is useful/scales in general.Sain
@Sain Nice use of a content filter driver there. I have included your comment in the answer for more visibility. That approach (content filter driver) means it is registered in the code base versioned by Git, but still need a git config to be active. It is more specific (limited to md files) then a whitespace config.Corrigendum
@VonC: Yes, and if git would ship with a built-in whitespace filter that is based on the project configuration, then (having the git version, granted) it would be available OOTB. I wonder if this is worth to bring forward.Sain
@Sain You can mention it on public-inbox.org/git, and see what counter-arguments are put forward.Corrigendum
Does whitespace = fix get applied during cherry-pick? (it seems to, but confirmation would be nice).Shanteshantee
T
50

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.


Robust solutions

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).

Fix the index but not the tree

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://mcmap.net/q/119233/-git-remove-trailing-whitespace-in-new-files-before-commit
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.

Fix the index and the tree

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

Simple but not robust solutions

These versions are easier to copy and paste, but they don't do the right thing if their side conditions are not met.

Fix the sub-tree rooted at the current directory (but resets the index if it's not empty)

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

Fix and preserve the index (but fails if the tree is dirty or the index is empty)

git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset --soft HEAD~

Fix the tree and the index (but resets the index if it's not empty)

git add -u :/ && git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset HEAD~

Explanation of the export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue . trick

Before 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:

  1. 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.

  2. 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).

  3. Remove the whitespace errors from your working copy:

    git checkout .
    
  4. 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.

Tavey answered 13/3, 2013 at 23:30 Comment(11)
I just tested it in Windows: this works just fine in a DOS command prompt: set VISUAL= && git add -ue . && git checkout . Note the '.' used with git add: that is because of git1.8.3Corrigendum
@Corrigendum Won't that unset VISUAL permanently, which may e.g. cause a subsequent use of git commit to use the wrong editor? I wrap the VISUAL= part in a subshell in my unix version above to avoid this, but I don't know if DOS has subshells.Tavey
You are right, I suspect I would have to wrap that command line in a .bat file.Corrigendum
Thanks for the great hack! FYI, if you have core.editor set then exporting VISUAL has no effect because the config setting takes precedence per man git-var. To override this you need to export GIT_EDITOR=: instead.Labdanum
@NickFelt Thanks! I've updated the answer to use GIT_EDITOR=: instead as you suggest.Tavey
@ntc: I tried your first command (git fixws) and it does touch the working tree here, and if it tries to fix lines where the working tree has changes over the index, I am asked to merge... this is git 1.8.4.4.Jamiejamieson
FYI, I think the fixws script could use another tweak - it seems like some recent version of git (I'm on 2.4.3.573.g4eafbef) made it an error to git stash pop onto a dirty index. This makes git fixws fail when attempting to run it with both a dirty index and tree. To fix it, you can just move the git stash pop line above the git reset --soft HEAD~ line. That seems like the correct sequence anyway.Labdanum
Also, I tweaked my version of fixws to fail fast if you're already in an interactive rebase since otherwise it will die at the git rebase --whitespace=fix line and leave you in a weird state. I borrowed from this question and just added an extra case before the if: fixws = !"\ if test -d $(git rev-parse --git-dir)/rebase-merge ; then \ echo 'In rebase - cannot fixws' ; \ elif (! git diff-files --quiet .) && \ (! git diff-index --quiet --cached HEAD) ; then \ ...Labdanum
Thanks @NickFelt! I incorporated your first suggestion into the answer, and put your second suggestion in my actual config. I'm not going to add your second suggestion to the answer here though, since I don't think that corner case is worth the extra complication here.Tavey
fyi: I adapted this into a pre-commit hookFraga
@ntc2: fixws does not work if no previous commits have been made. Is there an easy fix for handling that condition? The workaround of committing something and rebasing is not difficult, of course, but it would be nice to make fixws even more robust.Bateau
A
30

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
Arnhem answered 18/8, 2010 at 20:44 Comment(4)
The second sed invocation (sed -r 's/:[0-9]+:.*//') could be substituted with cut -f1 -d:. This should work the same on both Linux and BSD based platforms.Glassware
@IhorKaharlichenko: actually, using cut is not as safe as the second sed: cut will fail in the (highly unlikely) case of filenames that contain ":". You could use awk 'NF>2{NF-=2}1' to be safeGiza
BTW, If you're on Windows (msysgit) and use core.autocrlf=true, you may want to add dos2unix -D "$FILE" inside the for loop, after sed. Otherwise, it will change all CRLFs to LFs by issuing only sed.Doreendorelia
Doing git add inside a commit hook seems pretty evil to me. What if you are doing partial staging/committing of a file? You don't want the complete file to be committed behind your back, do you?Bryozoan
T
20

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 rerunning git init is to pick up newly added templates.

Throw answered 4/1, 2011 at 18:31 Comment(2)
Isn't this hook modifying the working file and overwriting the index with the modified working file? If you were to 'git add -p' to construct your index, this commit hook would blow that away.Lucknow
Yeah, you're probably right. Someone may have to rewrite this script to use git hash-object -w and git update-index to (re)insert the munged file directly into the index. Someone very brave.Throw
S
18

Using Git attributes, and filters setup with Git configuration

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.

Tell your Git to look for a global attributes file

First, tell your global configuration to use a global attributes file:

git config --global core.attributesfile ~/.gitattributes_global

Create global filters

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

Add the sed scripting magic

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

Tell Git which file types to apply your newly created filter to

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

Discussion of the filter

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.

Shipowner answered 11/2, 2015 at 4:7 Comment(2)
Thanks @VonC! I also want to take this opportunity to point out that the git attributes can be configured in a per-repisitory basis in the .git folder rather than globally, which might make more sense.Shipowner
sed -e 's/[ ]*$//' -- You can just use \s for both spaces and tabs, so sed -e 's/\s*$//' will do the job.Enswathe
K
14

I'd rather leave this task to your favorite editor.

Just set a command to remove trailing spaces when saving.

Kulun answered 26/2, 2009 at 21:34 Comment(6)
In vim you can do this with: autocmd BufWritePre .cpp,.c,*.h :%/\s\+$//eBradstreet
Sorry, I upvoted the above comment before testing it. There is a missing "s" after the percent sign, and it will move the cursor around if whitespace is found, and it will remove the last search pattern. See vim.wikia.com/wiki/Remove_unwanted_spaces for better alternatives.Murphey
In emacs it's M-x delete-trailing-whitespace.Starwort
Better still, for emacs, set a hook to delete trailing whitespace before saving by adding (add-hook 'before-save-hook 'delete-trailing-whitespace) to your .emacs file. Emacs whitespace tricksAdowa
I use (add-hook 'before-save-hook 'whitespace-cleanup) which also converts tabs to spaces.Cloudscape
This is by far the safest and most robust solution. I have wasted hours fixing unexpected problems caused by seemingly innocent pre-commit hooks.Waltner
P
10

I wrote this pre-commit hook, which only removes the trailing white space from the lines which you've changed/added, since the previous suggestions tend to create unreadable commits if the target files have too much 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

IFS='
'

files=$(git diff-index --check --cached $against -- | sed '/^[+-]/d' | perl -pe 's/:[0-9]+:.*//' | uniq)
for file in $files ; do
    diff=$(git diff --cached $file)
    if test "$(git config diff.noprefix)" = "true"; then
        prefix=0
    else
        prefix=1
    fi
    echo "$diff" | patch -R -p$prefix
    diff=$(echo "$diff" | perl -pe 's/[ \t]+$// if m{^\+}')
    out=$(echo "$diff" | patch -p$prefix -f -s -t -o -)
    if [ $? -eq 0 ]; then
        echo "$diff" | patch -p$prefix -f -t -s
    fi
    git add $file
done
Pointenoire answered 14/10, 2013 at 7:33 Comment(2)
Interesting. +1. See my other answer for computing the empty tree.Corrigendum
Good idea, this is exactly what I would want. However, be careful when using this! For me on OSX and git version 2.3.5 it blows away any add but uncommitted changes i have staged. I would still be interested in a working solution for this though.Evalynevan
M
9

Please try my pre-commit hooks. It can auto detect trailing white space and remove it.

It can work under Git Bash (Windows), Mac OS X and Linux!


Snapshot:

$ git commit -am "test"
auto remove trailing whitespace in foobar/main.m!
auto remove trailing whitespace in foobar/AppDelegate.m!
[master 80c11fe] test
1 file changed, 2 insertions(+), 2 deletions(-)
Misbeliever answered 28/3, 2014 at 4:44 Comment(4)
Interesting. +1. I have referenced your hook in my own answerCorrigendum
@Corrigendum Thanks for your affirmation! To the '.md', I only found git commit -no-verify, any sugesstions?Misbeliever
I would rather make the hook able to detect .md file and not remove the whitespaces, rather than asking the end user to add a --no-verify option on the git commit.Corrigendum
Fails if committing a file/directory that starts with a + or -Drexler
T
7

Here is an Ubuntu and Mac OS X compatible version:

#!/bin/sh
#

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

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]+:.*//' > /dev/null 2>&1 || sed -E 's/:[0-9]+:.*//') | uniq` ; do
  # Fix them!
  (sed -i 's/[[:space:]]*$//' "$FILE" > /dev/null 2>&1 || sed -i '' -E 's/[[:space:]]*$//' "$FILE")
  git add "$FILE"
done

# Now we can commit
exit
Training answered 7/6, 2011 at 8:44 Comment(4)
Looks like the only difference between yours and mine is that you check that sed will actually replace something before rewriting the file... I'm not sure that matters since git doesn't commit changes that don't actually change anything. I suppose it's marginally safer, but also marginally slower, and I prefer the clarity of not repeating the regexes twice on one line. De gustibus non disputandum est!Throw
no the difference is that the version is using the ubuntu syntax first and (if that fails) afterwards the osx one.Training
i editted sdepold's post, it should be able to also allow whitespaces in filenames now.Morelos
I think we could use this git rev-list --max-parents=0 HEAD to get init commitTammietammuz
R
6

I was thinking about this today. This is all I ended up doing for a Java project:

egrep -rl ' $' --include *.java *  | xargs sed -i 's/\s\+$//g'
Riviera answered 20/9, 2012 at 7:54 Comment(0)
U
4

For Sublime Text users.

Set the following properly in your Setting-User configuration.

"trim_trailing_white_space_on_save": true
Unchancy answered 19/6, 2014 at 13:37 Comment(3)
Is it a way to set this by file type? I have *.md (markdown) files that rely on " " (trailing double-spaces) for marking a simple <br />, and that setting seem to apply to all files, including the ones I don't want to remove the trailing spaces.Corrigendum
@Corrigendum There is hierarchy on how configuration is applied more details here, #16983828 hope it helpsUnchancy
This isn't related to gitUndetermined
C
3

This doesn't remove white space automatically before a commit, but it is pretty easy to effect. I put the following Perl script in a file named git-wsf (Git white space fix) in a directory in $PATH, so I can:

git wsf | sh

And it removes all white space only from lines of files that Git reports as a diff.

#! /bin/sh
git diff --check | perl -x $0
exit

#! /usr/bin/perl

use strict;

my %stuff;
while (<>) {
    if (/trailing whitespace./) {
        my ($file,$line) = split(/:/);
        push @{$stuff{$file}},$line;
    }
}

while (my ($file, $line) = each %stuff) {
    printf "ex %s <<EOT\n", $file;
    for (@$line) {
        printf '%ds/ *$//'."\n", $_;
    }
    print "wq\nEOT\n";
}
Cheat answered 21/10, 2017 at 3:10 Comment(0)
M
2

The for loop for files uses the $IFS shell variable. In the given script, filenames with a character in them that also is in the $IFS-variable will be seen as two different files in the for loop.

This script fixes it: multiline-mode modifier as given in the sed manual doesn't seem to work by default on my Ubuntu box, so I sought for a different implementation and found this with an iterating label, essentially it will only start substitution on the last line of the file if I've understood it correctly.

#!/bin/sh
#

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

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

SAVEIFS="$IFS"
# only use new-line character as separator, introduces EOL-bug?
IFS='
'
# Find files with trailing white space
for FILE in $(
    git diff-index --check --cached $against -- \
    | sed '/^[+-]/d' \
    | ( sed -r 's/:[0-9]+:.*//' || sed -E 's/:[0-9]+:.*//' ) \
    | uniq \
)
do
# replace whitespace-characters with nothing
# if first execution of sed-command fails, try second one (Mac OS X version)
    (
        sed -i ':a;N;$!ba;s/\n\+$//' "$FILE" > /dev/null 2>&1 \
        || \
        sed -i '' -E ':a;N;$!ba;s/\n\+$//' "$FILE" \
    ) \
    && \
# (re-)add files that have been altered to Git commit-tree
#   when change was a [:space:]-character @EOL|EOF git-history becomes weird...
    git add "$FILE"
done
# restore $IFS
IFS="$SAVEIFS"

# Exit script with the exit-code of git's check for white space characters
exec git diff-index --check --cached $against --

1 sed-substitution pattern: How can I replace a newline (\n) using sed?

Morelos answered 26/2, 2009 at 18:52 Comment(1)
The footnote does not seem to be referenced. What is the intent?Duly
J
0

Python Script for the same result.

import subprocess                                                                 
                                                                              
def get_trailing_lines():                                                         
                                                                              
    result = subprocess.run([                                                     
                            'git',                                            
                            'diff',                                           
                            '--check'                                         
                        ], capture_output=True)                               
                                                                              
    return result.stdout.decode().split('\n')                                     
                                                                              
                                                                              
def modify_line(file_path, l_num):                                                
                                                                              
    f_lines = open(file_path).readlines()                                         
    f_lines[l_num] = f_lines[l_num].rstrip()+'\n'\                                
                     if '\n' in f_lines[l_num] else f_lines[l_num].rstrip()    
                                                                              
    with open(file_path, "w") as w_fp:                                            
        w_fp.writelines(f_lines)                                                  
                                                                              
                                                                              
if __name__ == '__main__':                                                        
                                                                              
    l = get_trailing_lines()                                                      
    for m, d in zip(l[::2], l[1::2]):                                             
        f_path, l_no, *_ = m.split(":")                                           
        modify_line(f_path, int(l_no)-1)                                          
Journal answered 1/11, 2021 at 10:1 Comment(0)
B
-1

This probably won't directly solve your problem, but you might want to set those via git-config in your actual project space, which edits file ./.git/config as opposed to file ~/.gitconfig. It is nice to keep the settings consistent among all project members.

git config core.whitespace "trailing-space,space-before-tab"
git config apply.whitespace "trailing-space,space-before-tab"
Briefcase answered 26/2, 2009 at 19:12 Comment(1)
afaik, settings inside .git are not shared with anyone else; they're specific to your local repoThrow
A
-2

Open the file in Vim. To replace tabs with white spaces, type the following on the Vim command line:

:%s#\t#    #gc

To get rid of other trailing white spaces

:%s#\s##gc

This pretty much did it for me. It's tedious if you have a lot of files to edit. But I found it easier than pre-commit hooks and working with multiple text editors.

Arhna answered 25/7, 2014 at 22:20 Comment(1)
If it gets to tedious - and if you have a backup of what you are about to edit - then I often just use sed to change tabs to spaces: sed -i 's|\t| |g' filenames (spaces in the replace position). Note that you can use find to get your filenames. If you have not thought of how to get that backup, I usually just commit everything and then 'undo' the commit with a soft reset back to where I am; sometimes I add everything to the tree but don't commit, and sometimes I use the stash/apply (not pop!). If I feel anxious, I rsync my entire tree to a safe location before meddling...Vidda
S
-2

To delete trailing white space at the end of lines in a file portably, use ed:

test -s file &&
   printf '%s\n' H ',g/[[:space:]]*$/s///' 'wq' | ed -s file
Statuary answered 2/12, 2014 at 13:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.