So, I prefer spaces, and when I press tab, it should instead write 4 spaces. I forgot to set this option on Sublime Text and did some commits with tabs. The following git command will rewrite the repo history and replace tabs by 4 spaces.
git filter-branch --tree-filter 'git diff-tree --name-only --diff-filter=AM -r --no-commit-id $GIT_COMMIT | find . -exec perl -pi -e "s/\t/ /g" {} \;' HEAD
Comments
6 responses to “Replace tabs by space on git history”
This code looks total wrong to me (Don’t use it!). The pipe seems to do nothing and even if it did the perl script is told to processes all files by find so it’s pointless (and it will modify tabs in .git!!!) Please tell me if I’m missing something??
Hi Worried,
Yes, you’re wrong. This code rewrites git history, not files in path.
Sorry! Please feel free to delete my FUD. Could you explain why pearl gets a piped list of just some of the files and also every file with the find command? I ran the red highlighted code and perl deleted everything (it just did what find told it to), but the git diff-tree output seemed to do nothing? I don’t understand what perl is doing or how the scripts environment changes in a tree-filter.
Rephrase, what is the pipe for it seems redundant?
Sure, so here’s what the command does:
“git filter-branch” rewrites git revision history. If you run only this command you’ll see it going through every changeset to rewrite it. But since you did not told what to do, it does nothing.
This is the manual entry for –tree-filter:
“This is the filter for rewriting the tree and its contents. The argument is evaluated in shell with the working directory set to the root of the checked out tree. The new tree is then used as-is”
So what comes right after inside the quotes will be evaluated on shell. We feed “git diff-tree” with $GIT_COMMIT, that’s the changeset from “git filter-branch”
Run only this command:
$ git diff-tree –name-only –diff-filter=AM -r –no-commit-id HEAD
It gets the file names, with their complete paths, from your last commit (actually from the HEAD, which is also probably your last commit).
And then, the output of “git diff-tree” is piped into “find”, which executes perl to replace t with ” ” (four spaces).
In other words, every changeset is passed to diff-tree, which uses find/perl to replace the tabs. But it does on the git changeset, not on the current files.
You’re not supposed to run only the red part of the command 🙂 It’s an argument for “git filter-branch”, so it executes on changesets.
Thanks for your reply.
I did get wrong at the start that –tree-filter doesn’t actually checkout another .git folder when it makes the temporary working tree but other than that I have read the man and have run the diff-tree thing on HEAD / understand the basics.
So, if `git diff-tree –name-only –diff-filter=AM -r –no-commit-id HEAD` outputs file1 file2 then why does:
printf ‘%sn’ file1 file2 | perl -pi -e “s/t/ /g” file3 # only change file 3?
It seems that the perl script is not using standard input at all and the only thing that matters is the find loop and the git diff-tree pipe is NON functional?