Question: We use the auto-format tool [uncrustify](http://uncrustify.sourceforge.net/) on our git repositories, they run in a [git clean filter](https://git-scm.com/book/en/v2/Customizing-Git-Git-Attributes#filters_b).

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?

Answer: 
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` and `pop` invoke `git 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 applicable *`name`* (driver name in `.gitattributes`) and *`type`* (`clean` or `smudge`).

---

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 given *`paths`* get updated in the work-tree, from the copies already present in the index: this requires smudging. When using `git checkout *tree-ish* -- *paths*`, the given *`paths`* get copied from the given *`tree-ish`* into the index and then copied to the work-tree: this also requires smudging.

Or, when using `git checkout *`commit`*` or `git checkout branch`, the index entries that are different between the previous `HEAD` 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. Setting `merge.renormalize` in your configuration has the same effect, unless you override this with `git merge -X no-renormalize`. While `git merge-recursive` is lower level than `git merge`, I expect it does pretty similar things for the two commits that aren't represented by existing work-tree contents.
EDIT: I got a little over-enthusiastic. The answer below solves the filter running on every prompt, but not the filter introducing (actually not even real) changes to local files, thus preventing `checkout`.

---

The `__git_ps1` function provided in git's `contrib/completion/git-prompt.sh` runs `git diff`, which in turn runs the relevant clean filters.

Although I'm not sure about all the steps involved in the undesired behavior, it seems that the changes created by the clean filter (probably triggered by the prompt) hindered `checkout` and `stash pop`, in order to protect from possible loss of uncommitted work.

A solution is to disable clean filters in the `git diff` operations of `git-prompt.sh`, using the trick from @ElpieKay. In [this version of git-prompt.sh](https://github.com/git/git/blob/6d04ce75c4dd4bf0aeda7383c4d791daa049c98a/contrib/completion/git-prompt.sh), it's on row 508 and 509.

```
- git diff --no-ext-diff --quiet || w="*"
- git diff --no-ext-diff --cached --quiet || i="+"
+ git diff --no-ext-diff --quiet -c filter.*.clean=""  || w="*"
+ git diff --no-ext-diff --cached --quiet  -c filter.*.clean="" || i="+"

```