About a year ago I wrote a post called My Blog Migration Journey: From Gatsby to Astro. In it, past me declared victory: new framework, clean theme, āit just works.ā Past me was having a great time. Past me also, and I say this with love, had no idea what heād actually done.
This is the post where I clean up after that guy. š§¹
The Confession
When I āmigratedā to Astro last July, I didnāt fork the AstroPaper theme. I downloaded it. Copied the files into a fresh repo, typed āInitial commit,ā and moved on with my life. Later, feeling responsible, I added the original theme as a git remote called upstream so I could pull in updates someday.
Hereās the thing about that remote: it was a bookmark, not a lifeline. My repo and the themeās repo shared exactly zero commits of history. Run git merge-base between them and git just shrugs at you. Every āupdateā would have been an archaeology project, so naturally I did what any reasonable person does with an archaeology project. I didnāt do it.
Meanwhile, quietly, over twelve months:
- The theme moved on 861 commits without me, including a full version 6 rewrite
- Astro went from version 5 to 7
- Node 20, the version this site builds on, hit end-of-life and stopped getting security patches
- My laptop and my server ended up running different dependency trees for the same blog, because I never committed a lockfile and each machine resolved its own idea of ācurrentā (this one genuinely embarrassed me)
And my 118 commits of ācustomizationsā? When I finally audited them, most were ghosts. A coverImage field Iād dutifully added to 29 posts that nothing, anywhere, ever rendered. A āproxy-proofā theme toggle protecting against a reverse proxy I retired in August 2025. A bug fix the theme author had already shipped upstream. Out of six customizations, exactly two turned out to be real: a Contact link in the nav, and the comments widget.
I had built a museum of solutions to problems that no longer existed, and I couldnāt take updates because my fork wasnāt a fork. You know how it is.
The Do-Over š“
The fix wasnāt āupgrade the theme.ā The fix was to start over correctly: make a real GitHub fork of AstroPaper 6, with actual shared history, and port my content onto it. That sounds like a lost weekend. It took an evening, and honestly a pretty fun one, because I did the whole thing as a conversation with Claude Code.
I had Claude work in checkpoints, each one a place where I could look at a local preview and say ākeep goingā or ānopeā:
- Scaffold the fork, stock theme, dummy content
- Identity: my config, my hero text, my socials
- Content: all 31 posts and their images, moved verbatim
- Feature parity: Contact nav, comments, favicon
- Audit: diff the new site against production, mechanically
- Cutover: repoint the server, keep the old site on disk as a parachute
The audit step is the one Iād evangelize. Instead of trusting anyoneās notes about what got ported, Claude diffed the actual live site against the actual new build: every URL in the sitemap, the meta tags on every page type, the RSS feed item by item, tag pages, archives. All 31 post URLs came out identical, which means every old link and search result still works. The diff also caught that the new theme generates tag URLs differently (five tags moved), which became five redirect rules instead of five mystery 404s.
And for the record, the human still earned his keep: the AI ported my homepage down to the text and missed my face. I opened prod and the preview side by side and spotted the missing headshot in about five seconds. It had extracted the hero text with the HTML stripped out, and my photo went with it. A good reminder, for humans and robots alike: verify against the source, not your own checklist. š
Whatās Actually Better Now
Updates are one command. This is the whole ballgame. The theme author ships a release, GitHub emails me, and syncing is:
git fetch upstream
git merge upstream/main
That merge was impossible before. Not hard. Impossible. (Yes, --allow-unrelated-histories exists. No, hand-resolving a wall of conflicts against 861 commits of divergence is not a merge. Itās a punishment.)
My delta is now just six small commits. Config, hero, content, a nav link, a comments component, a deploy script. When upstream changes something, the surface area for conflicts is tiny and I understand every line of it. The old repoās 118 commits have been distilled down to the part that was actually mine.
The comments widget lost its framework. The old setup hauled in all of React to run one Giscus comments box (my 2025 fix for theme switching). Turns out the React wrapper was just a convenience around a postMessage API anyone can call. Itās now about seventy lines of vanilla JavaScript, and every existing comment survived because theyāre keyed to URL paths that didnāt change.
Version 6 itself is nice. Click-to-zoom lightbox on post images, callout boxes for asides, one typed config file instead of settings scattered across two. Nothing life-changing. The life-changing part is that when version 7 arrives, Iāll actually get it.
Lessons, Round Two š
Last yearās post had a āLessons Learnedā section too. Those lessons were fine. These are the ones I apparently needed a year to earn:
-
A fork is a relationship, not a download. If you copy a themeās files instead of forking its repo, youāve adopted a codebase, alone, forever. GitHubās Fork button costs one click and pays for itself the first time upstream fixes something.
-
Audit your customizations occasionally. Most of mine were dead code wearing a āload-bearingā costume. Every one you delete makes the next upgrade easier.
-
Verify against reality, not your notes. The side-by-side diff against production caught things that three rounds of ālooks good to meā didnāt. Your memory of what you built is not a spec.
-
The AI makes the boring discipline cheap. I would never have hand-diffed 136 URLs and every pageās meta tags on a Friday night. Claude Code did it in minutes, tiered the findings by severity, and turned them into redirect rules. The value wasnāt magic. It was that the tedious, correct process stopped being tedious.
The blog youāre reading is the result. Same posts, same URLs, same comments, new bones. And for the first time since I left Gatsby, ākeep the blog currentā is a habit instead of a someday project.
Share with me: If youāve got a āforkā thatās secretly an orphan, or a pile of customizations youāve been putting off auditing, Iād be curious how it got that way. Comments are open. š¬