- C++ 82.7%
- CMake 9.3%
- Nix 8%
| docs/assets | ||
| src | ||
| tests | ||
| .clang-format | ||
| .clang-tidy | ||
| .clangd | ||
| .gitignore | ||
| CMakeLists.txt | ||
| CMakePresets.json | ||
| flake.lock | ||
| flake.nix | ||
| keepassxc-core.nix | ||
| package.nix | ||
| README.md | ||
| treefmt.toml | ||
kdbx-merge
kdbx-merge reviews KeePassXC KDBX databases field by field and writes a new
database after explicit conflict resolution. Input databases are never
modified.
KeePassXC 2.7.12 is built once as the separate keepassxc-core Nix package.
The application links against that package instead of rebuilding KeePassXC
when application sources change.
Demo
Watch the interactive merge walkthrough
Play the interactive terminal cast on asciinema.
Development
Enter the reproducible development shell and configure the persistent local build directory:
nix develop
cmake --preset dev
cmake --build --preset dev
ctest --preset dev
The build/ directory is intentionally local and ignored. Ninja recompiles
only changed files.
Format C++ sources and verify formatting with the same toolchain used by CI:
nix fmt
cmake --build --preset dev --target kdbx-merge-format-check
The developer shell includes Clang, clangd, clang-format, clang-tidy, cppcheck, include-what-you-use, doctest, Valgrind, and Cachegrind.
Verification Profiles
Run AddressSanitizer and UndefinedBehaviorSanitizer tests:
nix develop .#asan
cmake --preset asan-ubsan
cmake --build --preset asan-ubsan
ctest --preset asan-ubsan
Run Valgrind Memcheck and Cachegrind:
nix develop
cmake --preset valgrind
cmake --build --preset valgrind
ctest --preset valgrind
cmake --build --preset valgrind --target kdbx-merge-cachegrind
cg_annotate build-valgrind/cachegrind.out
Run optional static analyzers in isolated build directories:
nix develop .#tidy
cmake --preset clang-tidy
cmake --build --preset clang-tidy
cmake --build --preset dev --target kdbx-merge-cppcheck
cmake --preset iwyu
cmake --build --preset iwyu
-Werror is available when a clean warning gate is desired:
cmake -S . -B build-werror -G Ninja \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_CXX_COMPILER=clang++ \
-DKDBX_MERGE_BUILD_TESTS=ON \
-DKDBX_MERGE_ENABLE_WERROR=ON
cmake --build build-werror
Neovim and clangd
Configure the dev preset once from inside nix develop. .clangd points at
the resulting build/compile_commands.json. The development shell exports
CLANGD_FLAGS with the Nix Clang compiler as --query-driver, so Neovim can
use the real clangd binary directly:
cmd = { "clangd" }
Start Neovim from the development shell so clangd and the wrapped compiler
are on PATH. The shell exports CLANGD_FLAGS, so the real clangd command
used by Neovim can query the Nix compiler directly.
Database Workflow
Close KeePassXC and pause Syncthing before reviewing or merging. Never use an input path as the output path.
Review the canonical database against each conflict copy:
./build/kdbx-merge diff \
/path/to/canonical.kdbx \
/path/to/conflict-copy.kdbx \
--same-credentials
The password is requested through /dev/tty; it is not accepted on the
command line. Protected values are masked unless --show-sensitive is used.
Write a new authoritative database after resolving each field:
./build/kdbx-merge merge \
--target /path/to/canonical.kdbx \
--source /path/to/conflict-copy-1.kdbx \
--source /path/to/conflict-copy-2.kdbx \
--output /path/to/merged-output.kdbx \
--same-credentials
Choose Finish later in the resolver to save an owner-only checkpoint beside
the output (for example, merged-output.kdbx.checkpoint). Continue with the
same command plus --resume; use --checkpoint PATH to place the sidecar
elsewhere. The checkpoint records only input paths, encrypted-file hashes, and
field choices—not passwords or field values—but those paths and field labels
are still sensitive metadata. It is removed after a successful save or an
explicit cancellation.
Inspect the resulting file in KeePassXC before making it canonical. The tool uses an atomic output write and reopens the output to verify it. Once the result is confirmed, close KeePassXC, replace the canonical file with the verified output, preserve the old file as a backup, and resume Syncthing.