
How to Version Control Your Presentations With Git
I put a .pptx in a git repo once, years ago, because the alternative was emailing “final_v3_REAL_final.pptx” around a team. Git took the file happily. It just could not do anything with it.
git log showed me who committed and when. git diff showed me nothing useful, a wall of binary noise, because a .pptx is a zip file full of XML and images, and two versions that look identical on screen can differ in a thousand bytes of internal bookkeeping. Review was impossible. Nobody could look at a pull request and say “the pricing slide changed, the rest didn’t” without opening both files side by side and squinting.
Why binary decks break git
Git is built around line-based diffs of text. A .pptx, a .key, a .pdf export - none of that is text, so git falls back to “binary files differ” and stores a full new blob every time, no matter how small the actual change was. Your repo grows by a few hundred KB per save, and your diff view is useless for review.
The options, roughly in order of how much I trust them
Store the binary, diff nothing. This is what most teams actually do, by default, because nobody set anything else up. It works exactly as well as it sounds.
Export-and-diff scripts. Pull text out of the deck on commit (a pre-commit hook that runs pptx2md or similar) and diff that alongside the binary. Better than nothing, but you are now maintaining a script whose whole job is working around the wrong file format, and it drifts out of date the first time someone changes the export tool.
Plain text formats. Reveal.js slides in Markdown, Marp, Slaide. The deck source is text from the start, so there is nothing to export and nothing to reconstruct. This is the option I actually use.
What a real diff looks like
Here is a commit from a deck I was editing last week, a customer proposal that needed the pricing slide updated:
# Pricing
-Starter: $29/mo, up to 5 seats
-Team: $99/mo, up to 25 seats
+Starter: $29/mo, up to 5 seats
+Team: $79/mo, up to 25 seats
+Enterprise: custom, unlimited seats
Two lines changed, one line added. Anyone reviewing this pull request sees exactly that and nothing else, no image bytes, no XML noise. If I had done this in PowerPoint, the honest review comment would have been “looks fine I guess” from someone who opened the file, glanced at slide 6, and closed it again.
Why this matters beyond diffing
A text deck reviews like code because it is code, in the sense that matters: line-addressable, greppable, mergeable. Two people can edit different slides in the same file and git will merge the change correctly most of the time, the same as it would for a config file. Try that with two people in the same .pptx and you get a lock file, a Slack message asking who has it open, and a merge that means “throw one version away.”
It also means the deck can be generated. A weekly report deck built from a script, a customer deck built from a template plus data - none of that is possible when the source format requires a GUI to write.
Where I landed
I write decks as .slaide files now - Markdown for the words, a small YAML block for the theme - and render them with the CLI:
slaide render deck.slaide --out deck.pdf
slaide render deck.slaide --out deck.pptx
The .pptx export is a real editable file, not a screenshot dump, so when someone asks for “the PowerPoint” I have one to send. The deck itself lives in git the whole time, reviews in a pull request like everything else I write, and the diff tells the truth about what changed. That last part is the whole point. A tool that tracks changes and then cannot show you the change has not actually given you version control, it has given you a backup folder with extra steps.