Version Control for Circuits
Quantum programs are software, and software changes. As an algorithm evolves — a tweaked ansatz, a re-routed circuit, a deeper error-correction distance — you need the same engineering hygiene that classical teams take for granted: a record of what changed, when, why, and the ability to reproduce any past result. Version control is the backbone of that hygiene, but circuits have quirks that make naive versioning misleading.
Version the source, not the artefact
The first rule is to version the highest-level description you can, and regenerate everything below it. A circuit exists at several levels — generator code, IR (OpenQASM/QIR), transpiled circuit, and measurement results — and only the top is the true source:
- Commit the generator code and any fixed parameters (ansatz depth, angles, seeds).
- Treat as derived the transpiled circuit and results — they are outputs of the source plus a compiler version plus a backend, and should be reproducible from those inputs.
Checking in a transpiled circuit as if it were source is a classic mistake: it bit-rots the moment the compiler updates, and it hides the parameters that actually generated it.
Why text IR is git-friendly
OpenQASM's text format is what makes circuits play nicely with line-based version control. A QASM file diffs cleanly:
h q[0];
- cx q[0], q[1];
+ cx q[0], q[1];
+ rz(0.7853981634) q[1];
measure q -> c;
Each gate is a line, so a reviewer sees exactly which operations were added, removed, or re-parameterised. Binary or pickled circuit objects, by contrast, produce opaque diffs and merge conflicts no human can resolve. This legibility is a concrete engineering reason to keep an OpenQASM export alongside generator code, even when the generator is the source of truth.
Semantic versus textual diffs
A subtlety unique to quantum (and reversible) code: two textually-different circuits can be the same unitary, and two textually-similar ones can differ. and mean a refactor that cancels or merges gates produces a huge textual diff for zero behavioural change. The right way to confirm "did this change the behaviour?" is not to read the diff but to run a unitary-equality check (the assertion discipline from earlier in this module) between the old and new circuits on a small instance. Text diffs review intent; simulator diffs verify equivalence.
What belongs in a circuit repository
A well-organised quantum project commits:
- Generator code — the program that builds the circuit, parameterised and seeded.
- Pinned dependencies — exact framework, transpiler, and simulator versions.
- A canonical IR export (OpenQASM) for legible review and cross-tool portability.
- Tests — the statevector/unitary/distribution assertions that define correctness, so a regression is caught the moment a commit breaks them.
- Resource-estimate snapshots — committed gate counts, -counts, and qubit widths, so a pull request that quietly doubles the -count is visible in review.
Excluded — because they are derived and machine-specific — are transpiled circuits tied to one backend and raw result dumps, which belong in an experiment log, not the source tree.
The payoff
With this structure, any historical result is reproducible: check out the commit, install the pinned versions, re-run the generator with the recorded seed, and you get the same circuit, the same transpilation, and — for the deterministic parts — the same numbers. That reproducibility is not a nicety; it is what lets a team trust a six-month-old benchmark, bisect a regression to the commit that introduced it, and review a circuit change as confidently as any other code change. The next lesson makes the stochastic parts reproducible too, by pinning the random seed.
Sign in on the full site to ask questions and join the discussion.