How do you automatically format your Swift code every time you commit it to your Git repository?
Swift Format
There are several Swift formatting tools. Xcode 16 shipped with swift-format included in the toolchain:
$ xcrun --find swift-format
/Applications/Xcode.app/Contents/Developer/Toolchains/
XcodeDefault.xctoolchain/usr/bin/swift-format
To run the formatter:
$ swift format MyFile.swift
Note: This runs the swift-format bundled with the active Xcode development directory (beta or release).
Configuring swift-format
The Xcode settings let you configure various formatting options including indentation but I prefer to use an external configuration file for swift-format.
By default, swift-format looks for a configuration file named .swift-format in the same directory as the files you are formatting. If there isn’t one it looks in each successive parent directory. If it doesn’t find a configuration file it uses a default configuration. You can dump the default configuration to get started:
$ swift format dump-configuration > swift-format
Modify the configuration file to meet your own code style:
{
"fileScopedDeclarationPrivacy" : {
"accessLevel" : "private"
},
"indentConditionalCompilationBlocks" : true,
"indentSwitchCaseLabels" : false,
"indentation" : {
...
I keep my default configuration file in my base Developer directory:
$ mv swift-format ~\Developer\.swift-format
When needed, I can override the defaults by placing a modified configuration file in the project-specific root directory.
Note: Don’t forget to prefix the configuration file with a .
Git Commit Hooks
Git Hooks are a way to run custom scripts when different Git actions occur. A pre-commit hook runs when you commit changes to a repository. Here’s the pre-commit script I’m using to run swift-format:
#!/bin/bash
GIT=/usr/bin/git
GREP=/usr/bin/grep
SWIFT=/usr/bin/swift
# Staged (cached) added/copied/modified/renamed files
FILES=$($GIT diff --cached --name-only --diff-filter=ACMR | $GREP '\.swift$')
# Exit early if no staged files
if [ -z "$FILES" ]; then
exit 0
fi
$SWIFT format --in-place --parallel $FILES
$GIT add $FILES
Notes:
- The git diff command returns the names of any staged (cached) swift files (A)dded, (C)hanged, (M)oved, or (R)enamed compared to
HEAD. - I run the swift format command on the staged files in one go, modifying the files in-place.
- Since formatting the files can change them I need to add the modified files back to the staging area.
- Exiting the script with a non-zero value cancels the commit.
Installing the Git pre-commit script
Git stores hook scripts in the hooks subdirectory of the Git directory in the project root. To install my pre-commit script I need to copy it to the hooks folder and make it executable:
$ cp pre-commit ~/Developer/Repositories/MyProject/.git/hooks
$ chmod +x ~/Developer/Repositories/MyProject/.git/hooks/pre-commit
Note:
- This is a client-side hook so I have to install it each time I create or clone a new repository.
Bypass the pre-commit script with the --no-verify flag:
$ git commit --no-verify