Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to apply Git clean filter on working tree file?

Tags:

git

filter

I want to let Git run all configured filters on my working tree file and print the resulting output (i.e. the same content which would be written to the Index). Is there a Git command to do that? For example, I'm looking for something like:

$ git the-command-i-am-looking-for < huge-lfs-file
version https://git-lfs.github.com/spec/v1
oid sha256:60ab6bad73e833318d3ad4a186c7ea77e0cf26c1419474dd6786db1c53a366c6
size 1050624
like image 719
mstrap Avatar asked Dec 19 '25 22:12

mstrap


1 Answers

There is no Git command to do it.

To do it manually, you would have to identify which filter is to be applied to the file, and then run that filter. If the filter is an old style driver, running it is pretty easy. If it's a new style driver, running it is more difficult. Finding it is potentially a bit tricky, but in practice easy.

Everything is documented in the gitattributes manual page. The filter to be applied is the one specified by the "best matching" filter=name. The "best match" is the last one taken, and matches are applied in order, starting from the top level .gitattributes file and working down the work-tree to the nearest .gitattributes file in whatever subdirectory a file lives in. For instance, if the project itself has:

.gitattributes
dir/.gitattributes
dir/sub/.gitattributes
dir/sub/subsub/.gitattributes

and the file itself is named dir/sub/name.ext, we look in .gitattributes for any pattern matching name.ext and take its definitions:

$ cat .gitattributes
* driver=d1
*.ext driver=d2
name.* driver=d3

Since name.ext matches *, the first line applies. Since name.ext matches *.ext, the second line also applies. Since name.ext matches name.*, the third line also applies, so the best match so far is d3.

Then we look in dir/.gitattributes:

$ cat dir/.gitattributes
*.ext driver=d4
*.dat driver=d5

This *.ext also matches, so the best match so far is now d4.

Now we look in dir/sub/.gitattributes:

$ cat dir/sub/.gitattributes
* driver=d6

This * matches, so the best match so far is d6.

There is a dir/sub/subsub/.gitattributes, but we don't look there because the file is in dir/sub, not dir/sub/subsub. So the driver to apply to dir/sub/name.ext is d6.

Now we merely have to locate the actual driver for d6, which we do by running git config --get:

git config --get filter.d6.clean

Whatever comes out of this is the clean filter we should apply to dir/sub/name.ext. (Let's say that's either run-d6 %f or just run-d6.) Now, however, we must check whether there is a filter.d6.process setting:

git config --get filter.d6.process

If there is no such setting (which git config indicates by exiting with a nonzero status), we have an old style driver filter, which is easy to run: it just reads its standard input and writes its standard output, and perhaps takes the file's path name as an argument. If the invocation line was run-d6 %f we just run:

git clean dir/sub/name.ext < dir/sub/name.ext > /tmp/cleaned

for instance.

If there is a filter.d6.process, though, invoking it to clean dir/sub/name.ext is considerably trickier. See the documentation for details. Unfortunately, modern Git-LFS uses long running filter processes (in fact I believe Git-LFS is the reason these exist at all), but I suspect there is some backwards compatibility method to invoke it one file at a time since long-running filter processes are still relatively new.

(Note that in practice, people don't build complicated .gitattributes tree structures. For Git-LFS in particular there's just one .gitattributes at the top level that runs everything through the long-running process.)

like image 147
torek Avatar answered Dec 22 '25 13:12

torek



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!