We use the auto-format tool uncrustify on our git repositories, they run in a git clean filter.
The problem is that users sometimes turn off their filters (don't ask). This leads to some bad formatting in some commits. Checking out these commits, while having the clean filter active, shows the bad formatting as diffs.
The filter is applied on git diff
and others, and now users can't checkout another commit (warning about losing changes), so they turn off their filter, and create more problems since it's easy to forget to turn it on again.
One solution is to apply the auto-format on the server repository, I'm looking into it.
I like seeing the auto-formatting on git diff
, so I see what I'm going to commit.
The question is: can we prevent running the clean filter on given operations, such as checkout
, stash pop
, and such?
Any better suggestion?
First, a note:
git checkout
should not run the clean filter at all, because it only does an index → work-tree copy.1 This runs the smudge filter instead. Only index ← work-tree copy operations use the clean filter.Since
git stash save
/git stash push
does an index ← work-tree operation, it will use the clean filter.Stash's
apply
andpop
invokegit merge-recursive
, which is more complicated. While some merging happens in the index, this sometimes needs to do smudging and/or cleaning,2 so you will see some cases of clean filter invocation here too.As ElpieKay suggested in the comment, a quick and dirty, but easy, way to disable a filter is to temporarily override its driver's configuration on the command line, with the front-end's
-c
option:git -c filter.name.type=noop
for each applicablename
(driver name in.gitattributes
) andtype
(clean
orsmudge
).1This is true whether
git checkout
is doing a branch-switch (git switch
operation in Git 2.23 or later) or a file-restore (git restore
operation in Git 2.23 or later). In either case, checkout updates index copies of some file(s) if/as appropriate, then updates the work-tree copy from each updated or selected index copy.That is, when using
git checkout -- paths
, the givenpaths
get updated in the work-tree, from the copies already present in the index: this requires smudging. When usinggit checkout tree-ish -- paths
, the givenpaths
get copied from the giventree-ish
into the index and then copied to the work-tree: this also requires smudging.Or, when using
git checkout
orcommit
git checkout branch
, the index entries that are different between the previousHEAD
and the newly selected one are updated in the index, then copied to the work-tree, which requires smudging.2
git merge -X renormalize
always runs both, doing a smudge first and then a clean, before merging, for every file in every commit, using the.gitattributes
from the work-tree. Settingmerge.renormalize
in your configuration has the same effect, unless you override this withgit merge -X no-renormalize
. Whilegit merge-recursive
is lower level thangit merge
, I expect it does pretty similar things for the two commits that aren't represented by existing work-tree contents.