GitHub - ylongw/firmware-bisect: Automated git bisect for firmware projects — find the exact commit that broke your build, flash-free. · GitHub
Skip to content

About

Automated git bisect for firmware projects — find the exact commit that broke your build, flash-free.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

firmware-bisect 🔍

Automated git bisect for firmware projects — find the exact commit that broke your firmware, hands-free.

Instead of manually checking out → building → flashing → reading logs for each commit, this tool automates the entire loop:

git bisect → build → flash → capture logs → pass/fail → repeat

20 commits? ~5 rounds × 1 min each = done in 5 minutes, unattended.

Why?

Finding firmware regressions is painful:

  1. Checkout a commit
  2. Build (~30s)
  3. Flash the board (~10s)
  4. Connect debugger/serial, wait for output
  5. Read logs, decide pass or fail
  6. Repeat 5-10 times

firmware-bisect does all of this automatically. You provide the known good/bad commits and tell it how to build, flash, and check results. It does the rest.

Quick Start

# Clone
git clone https://github.com/ylongw/firmware-bisect.git

# Run (all config via CLI)
cd your-firmware-repo
python path/to/fw_bisect.py \
  --good v1.0 --bad HEAD \
  --build "make -j8" \
  --flash "JLinkExe -CommandFile flash.jlink" \
  --capture "JLinkRTTLogger -device STM32 -if SWD -speed 4000 -RTTChannel 0 {log_file}" \
  --capture-duration 10 \
  --pass-pattern "TEST OK"

# Or with a config file
python path/to/fw_bisect.py --good v1.0 --bad HEAD -c bisect.yaml

Output

🔍 Bisecting 20 commits (est. 5 rounds)

[1/5] a1b2c3d BUILD ✅ FLASH ✅ VERDICT: ✅ PASS → bisect good (45.2s)
[2/5] e4f5g6h BUILD ✅ FLASH ✅ VERDICT: ❌ FAIL → bisect bad (43.1s)
[3/5] i7j8k9l BUILD ✅ FLASH ✅ VERDICT: ✅ PASS → bisect good (44.8s)
[4/5] m0n1o2p BUILD ✅ FLASH ✅ VERDICT: ❌ FAIL → bisect bad (42.3s)
[5/5] q3r4s5t BUILD ✅ FLASH ✅ VERDICT: ❌ FAIL → bisect bad (43.7s)

──────────────────────────────────────────────────────────────
🎯 First bad commit: q3r4s5t
   Author:  dev@example.com
   Date:    2026-02-25
   Message: "refactor: cleanup frame handling"

📋 Changed files:
   src/nfc/frame.c (+12 -8)
   src/nfc/t4t.c (+3 -1)

📊 Summary: 5 rounds, 2 good, 3 bad, 0 skipped
⏱️  Total time: 219s (3.7min)
──────────────────────────────────────────────────────────────

Config File

Create a bisect.yaml (or .json) in your project for reuse:

build:
  cmd: "cmake --build .build --target firmware"
  artifact: ".build/firmware.hex"

flash:
  cmd: "JLinkExe -device STM32H747XI_M7 -if SWD -speed 4000 -autoconnect 1 -CommandFile flash.jlink"
  delay: 1.5

capture:
  cmd: "JLinkRTTLogger -device STM32H747XI_M7 -if SWD -speed 4000 -RTTChannel 0 {log_file}"
  duration: 10

verdict:
  pass_pattern: "ALL TESTS PASSED|VERIFY OK"
  fail_pattern: "HardFault|ASSERT FAILED|FAIL"

skip_on_build_fail: true

See examples/ for STM32, ESP32, nRF52, and RP2040 configurations.

How It Works

You: "Something broke between v1.0 and HEAD"
                    │
          firmware-bisect starts
                    │
         git bisect start HEAD v1.0
                    │
    ┌───── loop (log₂ N rounds) ─────┐
    │                                 │
    │  1. Build firmware              │
    │  2. Flash to board              │
    │  3. Capture logs (RTT/UART)     │
    │  4. Check pass/fail pattern     │
    │  5. git bisect good/bad         │
    │                                 │
    └─────────────────────────────────┘
                    │
         🎯 "commit abc123 is the first bad commit"
                    │
         📋 shows diff + changed files

Supported Platforms

Build Flash Log Capture
STM32 CMake, Make J-Link, OpenOCD, ST-Link RTT, SWO, UART
nRF52/53 west (Zephyr), Make J-Link, OpenOCD, nrfjprog RTT, UART
ESP32 idf.py, PlatformIO esptool UART
RP2040 CMake picotool, OpenOCD UART, SWD
RISC-V Make, CMake OpenOCD, probe-rs UART, semihosting
Any Any command Any command Any command

The tool doesn't care what you use — it just runs the commands you give it.

Agent-Friendly

This tool is designed to be called by AI coding agents (Claude, Codex, Gemini, etc.):

  • Structured output: --json flag for machine-readable results
  • SKILL.md: Agent-readable documentation at the repo root
  • Zero dependencies: No pip install needed (PyYAML optional)
  • Deterministic: Same inputs → same behavior
  • Clear exit codes: 0 = found bad commit, 1 = error, 130 = interrupted
# Example: agent calls fw_bisect and reads JSON output
result = run("python fw_bisect.py --good v1.0 --bad HEAD -c bisect.yaml --json")
bad_commit = json.loads(result)[-1]  # last failing commit
diff = run(f"git diff {bad_commit['commit']}~1..{bad_commit['commit']}")
# Agent analyzes the diff to find root cause

CLI Reference

usage: fw_bisect [-h] [--good GOOD] [--bad BAD] [--repo REPO]
                 [--config CONFIG] [--build BUILD] [--artifact ARTIFACT]
                 [--flash FLASH] [--capture CAPTURE]
                 [--capture-duration DURATION] [--pass-pattern PATTERN]
                 [--fail-pattern PATTERN] [--log-dir DIR]
                 [--skip-on-build-fail] [--dry-run] [--json] [--version]
Flag Description
--good Known good commit
--bad Known bad commit
--repo Git repo path (default: cwd)
--config / -c YAML or JSON config file
--build Build command
--artifact Build artifact path ({artifact} in flash/capture cmds)
--flash Flash command
--capture Log capture command
--capture-duration Seconds to capture (default: 10)
--pass-pattern Regex for PASS verdict
--fail-pattern Regex for FAIL verdict (checked first)
--log-dir Where to save logs (default: .bisect-logs/)
--skip-on-build-fail git bisect skip instead of bad on build failure
--dry-run Simulate without hardware
--json Output JSON results

FAQ

Q: What if some commits don't compile? Use --skip-on-build-fail. The tool will git bisect skip for those commits instead of marking them as bad.

Q: Do I need PyYAML? Only for YAML config files. JSON config works with zero dependencies. Or just pass everything via CLI flags.

Q: Can I use this without a physical board? Yes — use --dry-run to test the bisect flow, or skip the flash and capture steps and just bisect on build success/failure.

Q: What if the capture process doesn't exit cleanly? The tool sends SIGTERM to the capture process group after the duration expires, then waits 5s before force-killing.

License

MIT

About

Automated git bisect for firmware projects — find the exact commit that broke your build, flash-free.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages