stayz3ro.dev

Renaming ten repositories without breaking anything

Ten repositories moved to short names in one evening. The HA DNS lab became dns, the managed network lab became netlab, the VPS lab became vps-lab, the CSS DOOM experiment became css-doom, and several others got the same treatment. Five of them are public. The other five are private, and they stay unnamed here for a reason that shows up later.

Short names are easy to pick and annoying to apply. A repository name is a URL, a git remote, a Pages path, a README link, a local directory, and a line in a few tool configs. Any one of those left pointing at the old name is a broken link or a failed clone. The work was less about the renames and more about the sweep that follows them.

What GitHub redirects, and what it does not

GitHub redirects renamed repository URLs and git remotes. git pull on an old remote keeps working, and a browser on the old repository URL lands on the new one. That covers the obvious cases, and it makes a rename feel safer than it is.

Pages project URLs do not redirect. A project site lives at stayz3ro.github.io/<repository>/, and that path does not follow the rename. After the CSS DOOM repository became css-doom, the old path /css-doom-static-lab/ returned 404 while /css-doom/ served the site. The redirect covers the repository, not the published path built from its name.

That is the first lesson: redirects are per-object. Git has them. Pages does not, and neither does anything else that encodes the repository name in a URL.

The build that the rename exposed

The Pages problem was worse than the path. That site was still set to “Deploy from a branch”, the legacy mode that serves files straight from main. The real site is a Vite build. The rename triggered a legacy rebuild that published raw source instead of the build output, so the site’s JavaScript and CSS 404’d.

The fix shipped as a pull request: change the build --base to the new path, switch the Pages source from the branch to GitHub Actions so the workflow’s build is what gets served, merge, then check that the built JavaScript and CSS return 200.

The --base value is the part that is easy to miss. A project site built for /old-name/ keeps emitting /old-name/ asset URLs no matter how many times it rebuilds. The rename only made the mismatch visible; the build setting had been carrying the repository name the whole time.

One sweep pull request per repository

The mechanical cleanup was a pull request per repository for README links and titles. Every change was a rename: old name out, new name in, nothing else. To prove that, each diff was verified by undoing the name swap on every changed line. If reversing old and new reproduced the original text exactly, the line was a pure rename and not a stray edit riding along. Rename-only diffs should be provable, not asserted.

Local work took longer than the repository edits:

  • Clone remotes were updated to the new URLs.
  • Local folders were renamed to match, which meant chasing everything that pointed at the old paths: shell functions, tool configuration, editor project history.
  • Git worktrees needed git worktree repair. A worktree keeps a pointer back to its main checkout, and renaming the checkout directory breaks that pointer until it is rewritten.

The folder rename finds the most forgotten references, because the old path was text in places that never appear in a repository. A shell function that cds into the old directory is not part of any diff.

The slip

The first sweep’s commit message listed every renamed repository, including the private ones. That message landed on public pull request branches. A final review caught it.

The fix was to recreate the pull requests with clean messages and close the superseded ones. The files in those pull requests were fine; the messages were not. The rule that came out of it: no private repository names in any text attached to a public repository, including commit messages. File contents were already covered by habit. Commit messages were not, and they publish just as widely.

There is a second, smaller honesty point in that episode. Replacing a pull request after its messages have been visible is not the same as never having published them. The corrected branches are the right end state, but the earlier text was public and stays a disclosure.

What I would check next time

  • Redirects cover git URLs and remotes. They do not cover Pages project paths, package registries, or anything else that encodes the repository name.
  • A project-site build usually hardcodes its base path. Renaming the repository without updating --base produces a site that builds cleanly and serves broken assets.
  • Rename-only diffs can be proven by reversing the swap on each changed line.
  • Local folder renames touch shell functions, tool configs, editor history, and git worktrees.
  • Scan the commit messages, not just the files.

The renames themselves took one evening. The sweep is what made them stick.