Git: Run a command on all files in a repository

Occasionally it’s useful to run commands on all files in your repository, or those matching a pattern. This is possible by combining git ls-files and xargs.
For all files:
$ git ls-files -z | xargs -0r <command>
Or for files with a given suffix:
$ git ls-files -z -- '*.<suffix>' | xargs -0r <command>
A deconstructed example
For example, to get the line counts of all Python files:
$ git ls-files -z -- '*.py' | xargs -0r wc -l
...
255 example/urls.py
138 example/utils.py
3160 example/views.py
78123 total
Let’s take that apart.
You can take the line count of a file with wc and its -l flag:
$ wc -l example/models.py
7142 example/models.py
git ls-files -- '*.py' lists all files known to Git that end in .py, in the current folder:
$ git ls-files -- '*.py'
...
example/urls.py
example/utils.py
example/views.py
Adding -z uses null byte separator, which isn’t exactly human readable:
$ git ls-files -z -- '*.py'
...example/urls.pyexample/utils.pyexample/views.py
Terminals don’t typically render the null byte, so all the filenames are jammed together. But the null byte separators are vital to correctly pass filenames with spaces, newlines, and weirder characters to xargs.
xargs takes a list of files from its input, and runs the command you give it on them, in groups as required. Its -0 option makes it split on the null byte separator, rather than newlines. The -r option avoids running the command if there are no files to process.
So in the combination command, it receives the list of files from git ls-files, and runs wc -l on them in batches.
Running Fixer Tools
You can also use this technique to run “fixer” tools. For example to run my tool django-upgrade on all Python files in your repository:
$ git ls-files -z -- '*.py' | xargs -0r django-upgrade --target-version 4.0
...
Rewriting example/models.py
Rewriting example/urls.py
😸😸😸 Check out my new book on using GitHub effectively, Boost Your GitHub DX! 😸😸😸
One summary email a week, no spam, I pinky promise.
Related posts:
Tags: git