---
title: 'Useful Commands for Bitcoin Core Development'
description: 'This blog is subject to change, and may become out of date LSP First time build, so clangd can find a compile_commands.json: `bash cmake -B build -DCM...'
canonical: 'https://rustaceanrob.com/posts/useful-bitcoin-core-commands'
created: 2026-07-23T00:00:00.000Z
tags: ['tips']
author: '@rustaceanrob'
rights: 'All rights reserved.'
---

_This blog is subject to change, and may become out of date_

# LSP

First time build, so `clangd` can find a `compile_commands.json`:

```bash
cmake -B build -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
```

# Build

Prebuild:

```bash
cmake -B build
```

Build:

```bash
cmake --build build -j $(nproc)
```

Clear cache:

```bash
ccache -C
```

## Tests

Unit tests:

```bash
ctest --test-dir build
# or, in parallel with output on failure
ctest --test-dir build --parallel 8 --output-on-failure
# or
build/bin/test_bitcoin
# or, with full logging
build/bin/test_bitcoin --log_level=all
```

Run a single unit test:

```bash
build/bin/test_bitcoin --log_level=all --run_test=getarg_tests
```

Full regression test suite:

```bash
build/test/functional/test_runner.py
```

Run a single functional test:

```bash
build/test/functional/feature_rbf.py
```

Configure `test_kernel`:

```bash
cmake -B build -DBUILD_KERNEL_LIB=ON -DBUILD_KERNEL_TEST=ON
```

Build it:

```bash
cmake --build build -j$(nproc) --target test_kernel
```

Run it:

```bash
ctest --test-dir build -R test_kernel -V
```

# Git

Worktree checkout, from `master`:

```bash
git worktree add ../network
```

Cherry-pick a merge commit:

```bash
git cherry-pick -Xours -m 1 -x 00af5620f01dbd1d2e696487303fad0382b67591
```

Run a build and test suite on every commit in a range, useful for bisecting where something broke:

```bash
git rebase -i --exec "cmake --build build && ctest --test-dir build" "$(git merge-base master HEAD)"
```

Configure a fuzz build with GCC and sanitizers:

```bash
cmake -B build_fuzz_gcc \
  -DCMAKE_C_COMPILER=gcc \
  -DCMAKE_CXX_COMPILER=g++ \
  -DBUILD_FOR_FUZZING=ON \
  -DSANITIZERS=address,undefined
```

Combine a normal build, test, fuzz build, and lint into a single rebase exec:

```bash
git rebase -i --exec "cmake --build build -j 16 && ctest --test-dir build && cmake -B build_fuzz -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DBUILD_FOR_FUZZING=ON && cmake --build build_fuzz -j 16 && ./ci/lint.py" HEAD~8
```

Review what changed between the current branch and a previous version of it (e.g. after a rebase), using `range-diff`:

```bash
PREV=e586844902 N=17 && git range-diff `git merge-base --all HEAD $PREV`...$PREV HEAD~$N...HEAD
```

# IWYU

Restart Docker:

```bash
sudo systemctl restart docker
```

Run the native IWYU CI task locally:

```bash
env -i HOME="$HOME" PATH="$PATH" USER="$USER" MAKEJOBS="-j1" FILE_ENV="./ci/test/00_setup_env_native_iwyu.sh" ./ci/test_run_all.sh
```

# CI

Run the native fuzz-with-valgrind CI task locally:

```bash
env -i HOME="$HOME" PATH="$PATH" USER="$USER" MAKEJOBS="-j16" FILE_ENV="./ci/test/00_setup_env_native_fuzz_with_valgrind.sh" ./ci/test_run_all.sh
```

# Debug

To debug a test, build a debug binary:

```bash
cmake -B build_debug -DCMAKE_BUILD_TYPE=DEBUG && cmake --build build_debug -j $(nproc)
```

Then run it under `gdb`:

```bash
gdb --args build_debug/bin/test_bitcoin -t blockfilter_tests
```

Handy reference: [gdb cheat sheet](https://darkdust.net/files/GDB%20Cheat%20Sheet.pdf).

# Bench

Benchmark the merge-base against the current branch, then walk through each commit on the branch running the same benchmark, checking out the current branch again at the end:

```bash
BASE=$(git merge-base master HEAD) && \
  git checkout --detach --quiet "$BASE" && \
  cmake --build build --target bench_bitcoin >/dev/null && \
  build/bin/bench_bitcoin -filter='.*MemPool.*' && \
  git checkout --quiet - && \
  git rebase -i --exec "cmake --build build && build/bin/bench_bitcoin -filter='.*MemPool.*'" "$BASE"
```

A simpler before/after comparison between the merge-base and the tip of the current branch:

```bash
BRANCH=$(git symbolic-ref --short HEAD) && \
  git checkout --detach --quiet "$(git merge-base master HEAD)" && \
  cmake --build build --target bench_bitcoin && \
  build/bin/bench_bitcoin -filter='.*MemPool.*' && \
  git checkout --quiet "$BRANCH" && \
  cmake --build build --target bench_bitcoin && \
  build/bin/bench_bitcoin -filter='.*MemPool.*'
```
