6 · Pre-commit & standards¶
Your patch must pass QGIS's own quality gates before it leaves your
machine. The devshell carries everything upstream's
.pre-commit-config.yaml needs, at the same pinned versions as QGIS CI —
so "works locally" means "works in CI".
What upstream checks¶
| Hook | Purpose |
|---|---|
clang-format (v21) |
C++ formatting per upstream .clang-format |
ruff check + format |
Python lint/format per upstream .ruff.toml |
spell_check |
QGIS's own dictionary-based spell checker |
banned_keywords, class_names, code_fixup |
QGIS coding conventions |
doxygen_test |
API documentation completeness |
shellcheck |
Shell script hygiene |
prepare_sip |
Regenerates SIP bindings from headers (runs last) |
Run them the comfortable way¶
From Neovim: <leader>pp checks your changed files; <leader>pP
checks the full branch diff against origin/master. Findings are
parsed into the quickfix list — fix, ]q, repeat, until the list closes
with a success notice.
From a terminal, identically:
The safety net¶
Bootstrap ran pre-commit install, so a plain git commit runs the same
hooks again. Never bypass them — --no-verify is how broken patches reach
reviewers. Two more allies:
<leader>plruns clang-tidy on the current file (upstream.clang-tidyconfig) for deeper static analysis than formatting hooks.qgis-dev doctorconfirms the hooks are actually installed.
Keep the diff boring
QGIS reviewers care that your diff contains only your change. Format-on-save over unrelated code creates noise — this environment deliberately formats only what the hooks require.
Format-on-save: only the lines you touched¶
Saving a C/C++ file inside the checkout runs clang-format on just the
lines you changed (versus HEAD), using the exact clang-format version
QGIS pins (v21.1.8) — not the editor's LSP formatter. Two problems this
solves:
- Version match. The QGIS-pinned toolchain nixpkgs ships clang-format
19; QGIS CI enforces 21. Formatting with the wrong version rewrites lines
QGIS already formatted, so what you save no longer matches CI. The
devshell therefore sources clang-format/clang-tidy at v21 (a separate
pinned input) and points
qgis-devstraight at them. - Minimal diffs. Only your touched line ranges are reformatted, so a save never churns code you didn't write. nix-vim's whole-file format-on-save is disabled for these buffers so the two don't fight.
| Action | Key | Scope |
|---|---|---|
| On save (automatic) | — | touched lines only |
| Format the whole file | <leader>pf |
entire file (manual) |
| Naming check | <leader>pn |
identifier naming for the file |
Turn the save behaviour off per session with :lua vim.g.qgis_format_on_save
= false, or from any terminal use qgis-dev fmt [--all] <file>.
Variable naming¶
QGIS's .clang-tidy defines the identifier rules (members camelBack,
static members s-prefixed, enums CamelCase, constants UPPER_CASE, …).
<leader>pn runs qgis-dev naming and surfaces violations as diagnostics
on the offending lines. Naming is reported, not auto-renamed — renaming
a symbol safely means touching every use of it, which is your call to make,
not a silent save-time rewrite. (Enable naming checks on every save with
:lua vim.g.qgis_naming_on_save = true if you want them nagging live —
it's a full-file clang-tidy pass, so it runs asynchronously.)
Continue to 7 · Your first patch.