From the Git side: the filter-branch
command1 works in principle by:
- extracting each commit, one at a time, into a temporary directory;
- running your filter(s) in that temporary directory on that extracted commit; and then
- building a new replacement commit from the results left behind in the directory.
The replacement commits get strung together, one at a time, in the usual way, and when all commits have been filtered, Git updates the various branch and other such references (--all
) as needed, with --tag-name-filter
deciding the new tag names (for you case this is all correct).
The --tree-filter
method, which is by far the slowest filter, uses this approach without any optimizations. Other filters exist to (a) go faster if you don't plan to touch most of the files and/or (b) make changes to things like the commit messages or other metadata, instead of or in addition to the snapshots. There's probably no point in trying to use a more optimal filter as you really do need to get all the files out in order to reformat them. So the thing to take away here is that each clang-format run will be run in a private, temporary directory that contains no Git repository. The $PWD
of that command will be this private directory.
To make things go faster, it's a good idea to consider using the -d
option to put that private directory in a memory or SSD or otherwise fast-access file system. For instance, if /tmp
is an in-memory file system, mkdir /tmp/foo; git filter-branch -d /tmp/foo ...
may run much faster than the one without the -d /tmp/foo
directive. The default -d
is a subdirectory that Git makes within the .git
directory; if that's on a slow, but highly reliable, file system, your filter-branch operation will go very slowly.
From the clang-format side: use any -style=
options you like. As numerous commenters noted, trailing whitespace stripping is the default (and apparently there are no options to control this at all now).
Note that it would be fine to add a .clang-format
file to the temporary directory. If you leave it there, it will be added to each replacement commit. If you remove it again after adding it, the lack of a .clang-format
file (because you removed it) will be what is in each commit. If you do nothing, there will or won't be a .clang-format
file based on whether there was one in the commit being filtered.
If you decide that, after all, you would like to use a .clang-format
file and add it to each commit, note that you will have to copy the file from outside the temporary directory, to the temporary directory, before each run of clang-format
, because Git itself clears out the temporary directory between each commit. Note further that you will not know where the temporary directory is,2 so to copy a known file, use a full path: cp /tmp/new-clang-format-file .clang-format && clang-format -style=file
, for instance.
1git filter-branch
is nominally outdated now, but its replacement, filter-repo
, isn't included with Git, so there's a bit of a dilemma here. You can install filter-repo separately, or for this kind of one-time job, you can just live with filter-branch.
2Even with the -d
option, Git makes various sub-directories of the directory you specify (it drops a bunch of temporary files in various places for its own purposes).