1

I have a series of git commits that, due to different editor defaults, ended up with huge whitespace diffs around every line that I ever touched. This makes git merges significantly harder, and violate the coding standards of the project I want to eventually upstream the changes to.

It's too many to fix manually, so I wanted to use unexpand.

However, I cannot just get a list of all the changed files in every commit and run unexpand on them, as some contain embedded tabs and I also cannot make whitespace modifications to lines I do not modify.

But, I also cannot run unexpand on the new files I add in the commits, as that would disrupt git history (long story).

So, what command/script should I use to run unexpand on all modified lines (but not touch added files) on a series of git commits?

Fred Nhara
  • 33
  • 4
  • 1
    This is the same problem as https://stackoverflow.com/questions/10413922/convert-spaces-to-tabs-in-lines-i-changed-in-a-commit, isn't it? – mkrieger1 Sep 20 '22 at 23:49
  • Similar, although that would affect files I added. – Fred Nhara Sep 21 '22 at 00:16
  • How many commits are we talking about ? up to 3-4 commits ? or more than 10 ? – LeGEC Sep 23 '22 at 08:17
  • _"as that would disrupt git history"_ - that's what rebasing is for. – CodeCaster Sep 23 '22 at 08:32
  • "that's what rebasing is for" It would disrupt the git history of the files I am adding, as I want to add them back in the same state they were deleted from the repo in as to simplify git blame. I modify them in later commits. – Zopolis4 Sep 27 '22 at 10:29

2 Answers2

1

git diff has a set of options to ignore whitespaces under some condition.

git format-patch can generate a list of patches, taking into account such options, and tuned to be usable by git am.

So you can try something along the lines of :

git switch -c wip <base_commit>
git format-patch -o ../mypatches --ignore-space-change HEAD..mybranch
git am ../mypatches/*

The difficulty will come from applying patches where the spacing does not match the content of your files on disk; if the number of commits to replay is small, this may still be manageable.

LeGEC
  • 46,477
  • 5
  • 57
  • 104
  • 1
    Whût? I thought I recommended before (in the [comments of that other answer of yours](https://stackoverflow.com/a/73133943/6309)) to *not* use `git checkout`!? So, `git switch -c wip ` – VonC Sep 23 '22 at 09:28
  • :D caught by the git squad ! – LeGEC Sep 23 '22 at 11:03
  • This immediately fails when applying patches: https://pastebin.com/ZMhVV4xz – Zopolis4 Sep 28 '22 at 07:57
1

Solved by modifying the script from Convert spaces to tabs in lines I changed in a commit.

#!/bin/bash -e
#
# Rewrite the last commit to remove any trailing whitespace
# in the new version of changed lines.
# Then replace space-based indentation with TAB based indentation
# based on TABS at every eight position
#
[[ -z $TRACE ]] || set -x
trap "rm -f $tmpf" 0
tmpf1=$TMP/$$.1.diff
tmpf2=$TMP/$$.2.diff
git show --binary --diff-filter=a >$tmpf1
perl -p -e 's/^(\+.*?)[ \t]+$/$1/; while(m/^(\+\t*)( {1,7}\t| {8})(.*)/) { $_=$1."\t".$3."\n"; }' <$tmpf1 >$tmpf2
if ! cmp -s $tmpf1 $tmpf2
then
    git apply --binary --index -R --whitespace=nowarn $tmpf1
    git apply --binary --index $tmpf2
    GIT_EDITOR=true git commit --amend
else
    echo "No changes"
fi

I modified the git show call to include --diff-filter=a, as inspired by the docs. Locally, I modified it to include --diff-filter=ad, as that seemed safer to me.

Fred Nhara
  • 33
  • 4