git remove trailing whitespace in new files before commit

22,256

Solution 1

To manually clean up whitespace from your last 3 commits, you can do this:

git rebase --whitespace=fix HEAD~3

When I work on a topic branch, I track the upstream branch (usually by creating it like this)

git checkout -b topic -t

Which allows me to drop the last argument from git rebase. So once I'm done & ready to merge, I can clean the whole topic branch quickly with:

git ws # aliased to rebase --whitespace=fix

Note that, unlike the HEAD~3 example, this will actually rebase your changes upon the upstream branch if it's changed! (But that's also what I want, in my workflow.)

Solution 2

I like Luke's answer, except for the limitation that you need to either manually specify the base commit, or use a rebase-style workflow, where your history is linearized. I propose a modification that doesn't need an extra argument and doesn't change the topology of your commit graph. As a shell command:

git rebase --whitespace=fix --onto $(git merge-base HEAD @{u})

Or as a ~/.gitconfig alias:

ws = "!git rebase --whitespace=fix --onto $(git merge-base HEAD @{u})"

I prefer this because sometimes I want to rebase my changes, but if I think think there might be a merge conflict I prefer to merge, so that both my original change and the conflict resolution will be recorded in the history. That way I can later second-guess the conflict resolution and redo it if necessary.

Given that I don't always rebase, I prefer not to mix whitespace-fixing with rebasing; hence this modification to Luke's answer.

In addition, I enable the default pre-commit hook which aborts on whitespace errors:

cp .git/hooks/pre-commit.sample .git/hooks/pre-commit

This gives the following workflow, which I like because it's manual enough that I know what's going on but automated enough not to get in the way:

  1. hack hack hack, introduce whitespace error
  2. attempt to commit
  3. commit fails with whitespace error due to pre-commit hook
  4. git commit --no-verify to commit anyway
  5. git ws use the alias to fix

Note on the usage of --onto: It's not necessary here, but I find it easier to reason about how the rebase works this way. In Luke's version, HEAD~3 is the <upstream> in the man page, while in my version <upstream> keeps its default value of the real upstream of the branch. You wind up with the same result either way though.

Solution 3

Simple fix

The command you quoted

(export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .) && git checkout . && git reset

works if you first add the files you want to fix with git add -N <files you want to fix>. The add -N essentially tells Git to pretend you'd previously committed empty versions of the files.

Error you got

I don't understand why you get fatal: Empty patch. Aborted. error with add -Ae, but it looks like a bug, since doing plain git add -A . && git diff --cached shows that the patch should not actually be empty.

Better whitespace fixer

I recently updated my answer that you linked to with a better Git alias for fixing whitespace. Here's a rewrite of that alias using Luke's rebase trick and a less redundant control flow:

fixws =!"\
  if (! git diff-index --quiet --cached HEAD); then \
    \
    git diff-files --quiet `git rev-parse --show-toplevel` ; \
    export NEED_TO_STASH=$? ; \
    \
    git commit -m FIXWS_SAVE_INDEX && \
    if [ 1 = $NEED_TO_STASH ] ; then git stash save FIXWS_SAVE_TREE; fi && \
    git rebase --whitespace=fix HEAD~ && \
    git reset --soft HEAD~ && \
    if [ 1 = $NEED_TO_STASH ] ; then git stash pop; fi ; \
  fi"

This fixes whitespace in the index, while preserving the index, and leaving the tree untouched. With this alias, you can fix unversioned files in the repo with

git add --all :/ && git fixws && git reset

But, it also handles the more common case of fixing up whitespace in a commit you're working on. It's complicated because it works even when the index or tree are clean.

Share:
22,256
loop
Author by

loop

Updated on March 06, 2020

Comments

  • loop
    loop about 4 years

    I know removing trailing whitespace can be done with a pre-commit hook. I am interested in doing it manually. I read the question here:
    Make git automatically remove trailing whitespace before committing - Stack Overflow
    The answer closest to what I want is the "automatic version" from ntc2:

    (export VISUAL=: && git -c apply.whitespace=fix add -ue .) && git checkout . && git reset
    


    That command works well except it seems to be only for changes on files that are already in the repo, not new files. I have a bunch of files that are new, meaning they aren't yet in the repo. I want to remove whitespace from those files so I tried add -A instead of -u but that didn't make a difference.