Version Control Practices for Research Code
Tying a backtest result to a commit hash and a data version is what makes quant research reproducible months later.
Version control for quant research code needs two things a typical software project does not: a way to tie a specific backtest result back to the exact code and data version that produced it, and a branching discipline that keeps a shared research library stable while individual researchers experiment freely on their own strategies. Git handles the code side directly, but the data side, and the discipline around how a shared library changes, both need conventions layered on top of git that a general software engineering course does not usually cover.
A backtest result that cannot be traced back to the exact code that produced it is close to worthless months later, when a researcher wants to know whether a subsequent change to a shared library improved or degraded a strategy's historical performance. The practical fix is mechanical: every backtest run should record the git commit hash of the code that ran, alongside the parameters and the date range, either in the output file itself or in a run log that is checked alongside the results.
This becomes essential once more than one person edits a shared research library, since a strategy's reported Sharpe ratio is only meaningful next to the specific version of the signal calculation, the risk model and the transaction cost assumptions that were active at the time the number was produced, and any of those three can change independently over time.
Git is not built to store large binary datasets efficiently, and committing gigabytes of Parquet files directly into a git repository slows every clone and every checkout for everyone on the team. The practical answer is to version the data separately, either through a tool built for large file versioning or, more commonly in research infrastructure, by treating each partitioned date range as immutable once written and referencing it by a path and a write timestamp rather than trying to fit it inside git's own history.
What does need to live in git is the schema and the validation logic that produced the data, since that is what determines whether a given dataset can be trusted, and reproducing an old result requires being able to check out the exact validation code that was active when a dataset passed its checks, even if the dataset itself lives outside the repository.