After a month of building with AI agents, I'm sad to announce the retirement of my version control strategy, which ran final_final in production, final_final_really in staging, probably_latest on the days I felt brave, and please_dont_sync_yet for anything that actually mattered.
Jokes aside, after creating many, many, many folders, my laptop and GitHub, where I back up my work, had drifted apart. In my case, 23 projects existed only on my laptop with no backup anywhere, and most of the others still sat on GitHub under names I'd already changed on my laptop, so for some of them it was no longer clear which version was the latest.
Building with AI makes this happen faster than it used to, because an agent can start a new project folder in a minute, and nothing in that process reminds you to back it up or to name it properly. So I wrote a Python script that keeps the two in line, and its first full run went through about 120 repos. Here is what I would tell anyone in the same situation.
Decide Which Side Is the Original
Before writing any code, decide which copy wins when the two disagree. For me it's the laptop, because that's where I reorganise folders and where the work actually happens, and GitHub is the copy that follows it.
That one decision settles most cases on its own. A project missing on GitHub gets a new private repo, and a repo with an old name gets renamed to match its folder. The one exception is a file that exists only on GitHub, which the script brings down to the laptop rather than ignoring, because an automated job in the cloud may have written it and may still need it.
Give Everything the Same Name in Both Places
Most of my confusion came from names. A folder called 01_Torke on my laptop was still called torke on GitHub, so two names pointed at one project and I had to remember which went with which. The script now names each repo exactly like its folder.
The rule stops at code projects that a live website or app points at, since renaming them would break whatever depends on them. One small site published through GitHub Pages keeps its old name for exactly that reason, because its web address is built from the repo name.
Write the Rules Down as Code
Every decision the script makes is a rule written in a file, so it does the same thing every time and I can read exactly why a repo was renamed or skipped. No step asks an AI model to judge anything, even though an AI agent helped me write the script.
Two decisions stay with me, because they can't be written as a rule: choosing which folder is the real home when two folders hold the same project, and settling a conflict where both sides made real edits. The AI coding agent I built it with is also blocked from uploading a hundred repos in one command, so the big manual uploads are started by me, which is the right call for anything that reaches outside my laptop.
Check What Your Tools Tell You
The first version reported 20 new repos as created when they had never been created. The GitHub command-line tool prints its "Not Found" message as normal output, and my script read any output as proof that the repo existed.
It now trusts only the exit code, the signal a command gives when it finishes, and there is a test for that case. If you automate anything against an outside service, check the result on the other side rather than trusting the success message.
Never Overwrite Anything
When the same file changed on both sides, the script stops, keeps both versions, and puts my laptop's version on a separate branch named with the date, so the conflict waits for me to decide. This came up on the first run with my skills library, where GitHub still held older versions with the old folder paths while the laptop held the renumbered ones.
The script also runs as a dry run by default, so it shows everything it would change before it touches anything, and only acts when I add --apply.
Decide What Never Leaves Your Laptop
A private repo is still a copy of your files on someone else's server, and it can be shared or leaked later. So before anything is uploaded, a filter goes through every file.
Whole folders that belong to my private life stay out entirely. In everything else, any file that looks like a password or an API key, contains a bank account or card number, holds personal data, or is a database stays on the laptop. Each check has a test with a look-alike that must not be caught, because the first scan mistook ordinary text that happened to start with "sk-" for a secret key.
Let It Run on Its Own, Carefully
My Mac runs the script every Tuesday and Friday. The scheduled run is narrower than a manual one on purpose: it only uploads changes, it never renames or creates repos, and it skips any project I edited in the last two hours, so a half-finished change never lands on GitHub. Every run ends with a notification that says either that it's done or that it needs me.
Where It Stops
It doesn't delete repos, because it was never given permission to, and it doesn't clean up files that were already on GitHub before the filter existed. For those there is a separate audit that lists them, and removing one is a decision I make file by file. It also scans only five folders deep, so a project buried further down stays invisible to it.
What I'd Keep From This
The mess came from speed. When an agent can start a project in a minute, the boring parts, meaning the name, the backup and the check for secrets, have to happen without me remembering them. The same holds for anything you produce quickly with AI, whether it's landing pages, campaign assets or documents, so it's worth deciding early where the original lives and how it gets named.
If you're shipping a lot with AI right now and this sounds familiar, hit me up and I can share the script with you.
Top comments (0)