Inércia Sensorial

23 de September de 2013

Replace tabs by space on git history

Filed under: Perils of Software Development — Tags: — inerte @ 21:04

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

7 Comments »

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

    Comment by Worried scripter — 02 de December de 2013 @ 22:27

  2. Hi Worried,

    Yes, you’re wrong. This code rewrites git history, not files in path.

    Comment by Julio Nobrega Netto — 03 de December de 2013 @ 00:05

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

    Comment by Worried scripter — 03 de December de 2013 @ 01:34

  4. Rephrase, what is the pipe for it seems redundant?

    Comment by Worried scripter — 03 de December de 2013 @ 03:47

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

    Comment by Julio Nobrega Netto — 03 de December de 2013 @ 14:30

  6. 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?

    Comment by Worried scripter — 03 de December de 2013 @ 21:40

  7. Бонусы от онлайн казино

    Comment by MichaelLeT — 08 de August de 2020 @ 09:57

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress