9

Situation: I've just cloned a git repo, and then I configure the smudge filter for the repo. There are .gitattributes files scattered around the repo that specify the filter that should be used on the files at checkout. But since I setup the filter after the checkout (clone), none of the files were processed.

How can I tell git to go through the repo, find all the .gitattributes files, and update (re-checkout, apply filter, whatever) all the files which have a smudge filter on them?

phemmer
  • 6,882
  • 3
  • 33
  • 31

2 Answers2

14

Simply re-checkout everything.

cd /path/to/your/repo
git stash save
rm .git/index
git checkout HEAD -- "$(git rev-parse --show-toplevel)"
git stash pop

The smudge filter will be applied at that new checkout.

Note, as seen in this answer, you need to remove the index in order to force the filter to run again.

Alexander Amelkin comments below:

I have created an alias 'reattr' to perform all those steps and now I am happy.

reattr = !sh -c "\"git stash save; rm .git/index; git checkout HEAD -- \\\"$(git rev-parse --show-toplevel)\\\"; git stash pop\""

(multi-line for readability)

reattr = !sh -c "\"git stash save; \
                   rm .git/index; \
                   git checkout HEAD -- \\\"$(git rev-parse --show-toplevel)\\\"; \
                   git stash pop\""
Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 2
    Doesn't work. Smudge not applied. I'm guessing git is intelligent enough to know the file wasn't modified, so it thinks it doesn't need to be checked out and ignores it. The only way I've been able to get git to re-checkout the file is to touch the file, and then check it out. But I want want to touch every file in the whole repo. – phemmer Feb 09 '14 at 01:41
  • @Patrick Strange, I have been doing that for months now successfully: https://github.com/VonC/compileEverything/blob/master/gitlab/install_or_update_gitlab.sh.tpl#L64-L68. Try a `git checkout HEAD -- /path/to/your/repo` – VonC Feb 09 '14 at 01:47
  • That does it, thanks. I'll add it to the script I use to set up the filter, but with a few tweaks: 1) add `git stash save` and `git stash pop` (if save did anything) before and after the checkout. This is just in case I was working on anything. 2) `git checkout HEAD -- "$(git rev-parse --show-toplevel)"` so I don't have to hard code the path. – phemmer Feb 09 '14 at 02:43
  • @Patrick Excellent. I hace edited the answer to reflect those additional steps. – VonC Feb 09 '14 at 02:44
  • Didn't check on filters, but this definitely does not work for me for 'ident' attribute. Nothing is re-checked-out, and the value if $Id$ remains the same inside the file unless I delete it and then do `git reset --hard` on it. – Alexander Amelkin Oct 17 '16 at 11:58
  • 1
    @AlexanderAmelkin I have edited the answer to include the "rm .git/index" step in order to force any filter or attribute directive to re-apply on checkout. – VonC Oct 17 '16 at 12:22
  • @VonC, thank you! Now it works! I have created an alias 'reattr' to perform all those steps and now I am happy. I guess you may want to include it into the answer: `reattr = !sh -c "true; echo Re-applying filters and other attributes; git stash save; rm .git/index; git checkout HEAD -- \"$(git rev-parse --show-toplevel)\"; git stash pop"`. I put that `true` as the first step of the alias because for the reason I do not know the very first command is never executed for any `!sh -c` alias. So that `true` is an ugly kludge. – Alexander Amelkin Oct 17 '16 at 16:54
  • 1
    @AlexanderAmelkin Thank you for this feedback. I have included your comment and alias in the answer for more visibility. – VonC Oct 18 '16 at 08:59
  • @VonC, thank you. By the way, I found out why the first command was ignored. It was due to insufficient escaping of double quotes. The proper syntax thus is: `reattr = !sh -c "\"git stash save; rm .git/index; git checkout HEAD -- \\\"$(git rev-parse --show-toplevel)\\\"; git stash pop\""` – Alexander Amelkin Oct 18 '16 at 09:33
2

You can remove the Git index and let Git rescan it to aware the changes. Then you can checkout all the files which have a smudge filter on them.

# remove Git index
rm .git/index

# rescan index
git reset HEAD -- .

# checkout all the files which have a smudge filter on them
git ls-files --modified | grep -v .gitattributes | awk '{print "git checkout HEAD -- \""$1"\""}' | bash

Note: Save your uncommitted changes before the re-checkout, otherwise, all your modifications on those smudge-filter-applied files will be overridden.

Tony YUEN
  • 492
  • 4
  • 4