-
We are using clang-format.
-
We use the current stable release, with an eye to good new options coming from the next release. As of writing we're using release 10, the configuration options are documented here.
-
As mentioned in the style guide, the format style is based on Google C++ style guide, but mixed in with Postgres formatting rules (break before braces, 4-space tabbing, etc)
-
We should use an explicit, complete (locked down) specification for the .clang-format file.
-
But our intent is better expressed as well organized, commented yaml. We use a simple script to generate the complete config file from the intent file. For example, on my Linux laptop, I run:
CLANG_FORMAT=clang-format-10 src/tools/fmt gen
If the correct version of
clang-format
is installed asclang-format
(as is the case in macOS), you can omit the environment variable override. -
To check for formatting conformance, one can run
src/tools/fmt chk
It will succeed quietly (with return code 0) or point out the first few places that need to be formatted.
-
To wholesale format all of ORCA and GPOPT
src/tools/fmt fmt
On my laptop this takes about 2.5 seconds.
-
Of course, when you're writing code, 2.5 seconds is an eternity. Here's a non-exhaustive list of editor / IDE plugins that provide an integrated formatting experience. The in-editor formatting typically takes around 50ms. Depending on your plugin / editor, the formatting either happens automatically as you type, on save, or when you invoke it explicitly.
- LLVM's official Emacs integration provides the
clang-format-region
macro.
- Vim integration as documented by the official LLVM project
- A community VIM plugin that looks promising and claims to be better than the official VIM integration
- Clion detects
.clang-format
automatically and switches to using it for the built-in "Reformat Code" and "Reformat File...".
- Similar to CLion, Visual Studio Code has it built in.
- LLVM's official Emacs integration provides the
- It's usually desirable to skip past formatting commits when doing a
git blame
. Fortunately, git blame has two options that are extremely helpful:-w
ignore whitespace--ignore-rev
/--ignore-revs-file
accepts commits to skip while annotating
When combined, -w --ignore-revs-file
produces a perfectly clean annotation, unencumbered by a noisy history. This also gives us a peace of mind in changing our formats more frequently without worrying about hindering the git blame
experience, rather than "do it once, set it in stone, and forget about it".
ORCA is actively developed, that means when the "big bang" formatting change is merged, there will inevitably be a number of patches that were started well before the formatting change, and these patches will now need to conform to the new format. The following steps are used to convert in-flight branches to the new format.
-
Fetch the inflight PR. Let's say its greenplum-db/gpdb#20042
git fetch origin refs/pull/20042/head git checkout -b 20042-backup FETCH_HEAD
-
Duplicate the PR to a working branch. We'll reformat this branch:
git checkout -b 20042-fmt
-
Rebase the working branch to just before the big bang. Normally, you'd do it like (but don't do this yet):
git rebase 'origin/master^{/Format ORCA and GPOPT}~'
Here
'origin/master^{/Format ORCA and GPOPT}'
is a Git notation that denotes the most recent commit from branch `origin/master' that contains the phrase "Format ORCA and GPOPT". The trailing tilde character is Git shorthand for "first parent". -
But! We want to insert a precursor commit that will eventually disappear:
git rebase --interactive 'origin/master^{/Format ORCA and GPOPT}~2'
When we edit the "rebase todo" in an editor, make sure to insert the following action between the first two "pick" action items:
--- /tmp/todo 2020-11-12 16:48:07.251333950 -0800 +++ /tmp/todo2 2020-11-12 16:48:07.291333698 -0800 @@ -1,7 +1,8 @@ pick 87fd0149caf8f052 Penultimate commit on master +exec git checkout origin/master -- src/tools/fmt src/include/gpopt/.clang-format src/backend/gpopt/.clang-format src/backend/gporca/.clang-format; git commit -m 'this commit will disappear' pick 93235faf306f4ecb 1st commit from PR pick 2b7ad8b9fd1f222c 2nd commit from PR pick 5bc7ac02c1c78b8b Last commit from PR # Rebase f96bb1e290ef188e..5bc7ac02c1c78b8b onto c6ab7beee96e8bc7 (2 commands) #
What happens here is that we inserted a placeholder commit that gets us the format script and format configuration while rebasing.
This commit will disappear in the final history (read on)
-
Use
git filter-branch
to rewrite the branch historygit filter-branch --force --tree-filter 'CLANG_FORMAT=clang-format-10 src/tools/fmt fmt; CLANG_FORMAT=clang-format-10 src/tools/fmt fmt' origin/master..
Now we have reformatted every commit in this branch that's not in master (modulo the big bang commit). As a bonus, our placeholder commit should now be identical to the tip of master (the big bang formatting commit).
-
Now that we have reformatted the history, rebase on top of master
git rebase origin/master
Git should be smart enough to drop our placeholder commit, and now the history is all properly formatted.