Git for the Middle Office
Version control is usually sold to analysts as a tidiness habit. It is better understood as the cheapest audit trail an investment operation can buy — and the precondition for automating anything.
Ask a middle office to prove which version of a pricing query produced last quarter's numbers and you usually get one of two answers. Either somebody opens a network drive and starts reading filenames, or somebody says it hasn't changed — which is a belief, not a record.
That gap is not a discipline problem. It is a tooling problem with a forty-year-old solution that most investment operations have never installed.
What Git actually is
Git is version control. Think of it as Track Changes, except it works on any kind of file, it keeps every version permanently, and it never asks you to name anything _v3_FINAL_really_final. It runs locally: you install a program, point it at a folder, and it watches that folder.
GitLab is a hosted service that keeps a copy of those folders in the cloud, along with a web interface, access control, and — the part that matters later — a way to run jobs. GitHub and Azure DevOps do the same thing. The choice between them is less important than the decision to use one at all.
Two words carry most of the meaning. A repository is a tracked folder. A commit is a snapshot of every file in it at one moment, with a message you write describing what changed. A commit is a photograph with a caption. The repository is the album.
Setup, once
This takes about fifteen minutes and you never do it again.
Install Git. On Windows, download it from git-scm.com/downloads/win and accept every default. On a Mac, open Terminal and type git --version; if it isn't installed, macOS offers to install the Xcode command line tools for you.
Tell Git who you are. Every commit is stamped with a name and email, so set them once:
git config --global user.name "Derek Barnes"
git config --global user.email "you@example.com"
Create an SSH key so you aren't typing a password on every push:
ssh-keygen -t ed25519 -C "you@example.com"
Accept the default file location. Then copy the public key and paste it into GitLab under your avatar in the upper right → Edit profile → Access → SSH keys → Add new key.
# Git Bash on Windows, or macOS Terminal
cat ~/.ssh/id_ed25519.pub
# Windows Command Prompt
type %USERPROFILE%\.ssh\id_ed25519.pub
On the passphrase. Key generation offers you a passphrase and it is tempting to skip it. On a personal machine with a personal repository, fine. On a work laptop holding a key that reaches firm scripts, set one — the key is a credential, and an unprotected private key file is a credential sitting unencrypted on a laptop that travels. Your operating system's key agent will remember it after the first unlock, so the friction is close to zero.
The daily rhythm
Create the project on GitLab first, then bring a copy down to your machine:
git clone git@gitlab.com:your-username/sql-scripts.git
cd sql-scripts
From then on, everything you do is three commands. Save your work into that folder, then:
git add . # stage what changed
git commit -m "describe what changed" # take the snapshot
git push # send it to GitLab
That is the whole loop. git status shows you what Git has noticed, and git diff shows the actual line-by-line changes — though note that once you have run git add, plain git diff comes back empty, because the changes are staged. git diff --staged shows those.
git log --oneline gives you the history:
a3f2b1c Added cap rate analysis grid
9e1d4a7 Fixed BSM Greeks calculation
2c8f3e0 Initial SQL scripts
And to see a file as it was at any point, the web interface is easier than the command line: open the file in GitLab and click History.
Two things the tutorials skip
Both of them matter more in financial services than they do anywhere else.
1. Decide what must never be committed
git add . stages everything in the folder. That is convenient and it is exactly how connection strings, API keys, and extracts of client positions end up permanently recorded in a repository — permanently, because deleting a file in a later commit does not remove it from the history. Write a .gitignore file before your first commit, listing what Git should ignore:
*.env
config.local.*
credentials.*
data/
*.xlsx.lnk
Keep credentials in environment variables or a secrets manager and keep production data out of the repository entirely. The repository holds the logic, not the numbers.
2. Undo is not always undo
The command for discarding uncommitted changes to a file is genuinely destructive:
git restore filename.sql # modern form
git checkout -- filename.sql # older form, same effect
There is no recovering from it, because the change was never recorded. Anything you have committed, by contrast, is essentially impossible to lose. That asymmetry is the argument for committing often and in small pieces rather than saving up a week of work.
Commit messages are the audit trail
This is where the tooling becomes governance.
A commit message is a one-line changelog entry written at the moment you still remember why. "Updated stuff" is a wasted field. "Fixed BSM dividend yield handling for quarterly expiries" is a record that answers a question somebody will ask eleven months from now, when the person who made the change has moved on.
Every control framework asks some version of the same question: what changed, when, who approved it, and can you show me. For analytical logic, a repository answers all four for free — provided the messages are written like they will be read.
Excel, and the limits of this
Git shines on text: .sql, .py, .md, .txt, .csv. For those it can show you exactly which lines moved.
Workbooks are a different case. Git will track an .xlsx and keep every version of it, so you get history and backup, but it cannot show you a line-by-line comparison, because the file is binary. That is still a substantial improvement on a network drive full of near-identical filenames — and the workaround is to write a more detailed commit message than you otherwise would, since the message is doing the work the diff can't.
The deeper point is that a model whose logic lives inside a binary workbook is hard to audit no matter what you store it in. Version control makes the situation legible. It does not fix it.
Where this goes next
Everything above is version control, and version control on its own is a filing cabinet with a memory. The reason to build the habit now is what it makes possible afterwards.
Once analytical code lives in a repository, the platform hosting it can run that code for you. In GitLab this is CI/CD: a file in the repository named .gitlab-ci.yml defines jobs, and those jobs execute on a schedule, or when a change is merged, or when you press a button. GitHub calls its equivalent Actions. The mechanics differ; the idea does not.
That is the direction I am taking my own work. A month-end return calculation that runs on the first business day without anybody remembering to run it. A reconciliation that fires when the custodian file lands and emails the breaks. A pricing job that reruns when the query behind it changes, so the output is never quietly stale.
The operational appeal is obvious — fewer manual steps, fewer missed ones. The governance appeal is the one worth naming, and it is the same argument as the commit message. When a report is produced by a job running out of a repository, the exact code that produced it is identified by a commit, and the run is logged. You are no longer reconstructing what happened. You are reading it.
That is a long way from installing Git and typing three commands. But it is the same road, and this is the first mile of it.
Scarborough Road works with insurers and asset managers on derivatives governance, hedging operations, and the investment data infrastructure that demonstrates the governance was followed.
General commentary on operational tooling practice. Not legal or investment advice. Commands and interface paths reflect current documentation at the time of writing and may change; confirm against your own environment and your firm's policies on credential handling and approved software before adopting any of this.
Reference — GitLab Docs, "Use SSH keys to communicate with GitLab"