Reputation: 41945
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?
Upvotes: 1
Views: 1378
Reputation: 41945
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, 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="+"
Upvotes: 0
Reputation: 487885
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
or commit
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.
2git 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.
Upvotes: 2