Cleaning up master → main without creating a mess you have to clean up later
- Shannon

- May 8
- 6 min read
At some point you look across your repos and realize you've got some sort of split personality problem. Half your projects are on main, the other half are still on master, and every time you touch a pipeline, clone a repo, or write documentation, you have to stop and remember which one you're dealing with. You know it's not broken, it's just inconsistent enough to be a persistent low-grade annoyance. I recently went through this myself and thought about adding this to my blog as a way to help any of you out if you have repos that still have "master".
Now, the instinct is to fix it all very quickly. Rename the branch, move on, and you're done. The reality is that the rename is the least interesting part of this effort. What matters is everything that quietly depends on that branch name, and that's what turns a quick cleanup into something that breaks builds and deployments in ways that aren't immediately obvious.
So instead of starting with the rename, start by figuring out what still thinks master exists. You may thank me later!
Start by figuring out what depends on master
Before you touch anything, take a few minutes to surface where master is actually being used. Over time it creeps into pipeline triggers, Terraform modules, scripts, and external systems that pull from your repo. Keep in mind, you're not trying to fix everything yet. You're trying to answer one question: what breaks if I remove master?
Do a quick sweep of the repo
The easiest place to start is the repo itself:
git grep -n "master"That command gives you every tracked file where master appears. From there you can scan for actual dependencies rather than comments or docs. If you want to be more targeted about catching real branch references, use this command:
git grep -nE "origin/master|refs/heads/master|ref=master|master"For a broader sweep that includes untracked files and skips common noise, use this command:
grep -RIn --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=.terraform "master" .I've found that usually catches a few things git grep misses.
Spend Some extra time on pipelines
If something is going to break after the switch, it's almost always here...your pipelines! Pipelines are explicit about branch names and they don't adapt unless you tell them to.
Look through your workflow and pipeline definitions (GitHub Actions, Azure DevOps, Jenkins, whatever you're running) for triggers and conditions tied to master:
yaml trigger
on:
push:
branches:
- masteryaml condition
if: github.ref == 'refs/heads/master'These unfortunately won't fix themselves. If your deployment pipeline is tied to master and you remove it, nothing runs. Your pipelines quietly stop doing what you expected.
Here's an example of a focused scan for GitHub Actions:
grep -RIn "master" .github/workflowsThat alone usually finds the majority of pipeline-level dependencies.
Don't forget GitHub settings
Some dependencies aren't in code at all. They're in repo settings, which makes them easy to overlook. Before switching anything, check the:
Default branch
Branch protection rules and required status checks
PR policies and rulesets
Environment and deployment restrictions
GitHub does a decent job helping with renames, but it's not aware of your intent (if only!). If protections are tied to master, you want to know that before making changes so you can confirm everything moves cleanly.
Think beyond GitHub
This is where things get missed. Anything outside GitHub that interacts with your repo could still be referencing master. Reviewing and identifying components such as Azure DevOps pipelines, Jenkins jobs, ArgoCD configurations, Terraform modules, or scripts that interact with or clone your repository will help you completely squash the issue before it's an issue.
Here's a common example in Terraform:
source = "git::https://github.com/yourorg/yourrepo.git?ref=master"That won't throw an obvious error right away. It'll just start behaving in ways that don't make sense once master is gone. I will mention this too: you don't need to audit every system in your environment, but you should think through what's pulling from your repos and whether it assumes master.
Use a script to speed this up
If you want something reusable, this gives you a solid first pass:
#!/usr/bin/env bash
echo "Searching tracked files for references to master..."
git grep -nE "origin/master|refs/heads/master|ref=master|master" || true
echo ""
echo "Checking GitHub Actions workflows..."
if [ -d ".github/workflows" ]; then
grep -RIn "master" .github/workflows || true
else
echo "No GitHub Actions workflows directory found."
fi
echo ""
echo "Checking common pipeline and IaC files..."
find . \( -name "*.yml" -o -name "*.yaml" -o -name "*.tf" -o -name "Jenkinsfile" -o -name "*.sh" \) \
-not -path "*/.git/*" \
-not -path "*/node_modules/*" \
-not -path "*/.terraform/*" \
-print0 | xargs -0 grep -In "master" 2>/dev/null || true
echo ""
echo "Done. Review anything referencing master before switching branches."Run it once, skim the output, and you'll have a clear picture of what needs attention before you touch anything. This script could save you hours upfront!
Once you understand the dependencies, the switch is straightforward
At this point you know what depends on master, or at least where to look if something behaves unexpectedly. That makes the actual switch uneventful (and remember, from past blogs, I like uneventful changes).
Rename the branch
You can do this directly in GitHub (simplest path) or locally if you want something scriptable:
git branch -m master main
git push -u origin mainNow both branches coexist briefly while you validate things.
Change the default branch
Go to Settings → Branches and flip the default branch to main. This is what actually changes how the repo behaves going forward. New pull requests, merges, and most integrations will start using main.
Give yourself a short validation window
Before deleting master, run a build, trigger a deployment, confirm nothing obvious is broken. Having both branches temporarily gives you a safety net without any real cost.
Remove master
Once you're confident everything is clean:
git push origin --delete masterUpdate local clones
Anyone who cloned the repo will still be on master locally. That doesn't fix itself, so share these commands with your team:
git branch -m master main
git fetch origin
git branch -u origin/main main
git remote set-head origin -aSkipping this step generates a lot of small, annoying issues.
Doing this at scale with the GitHub CLI
For a handful of repos, the manual approach is fine. For dozens or hundreds, it gets old fast. The key idea is to script against your repos rather than clicking through them while still respecting the same rule: don't flip anything until you know it's ready.
Get visibility before you change anything
Run this first. It doesn't modify anything. It just shows you the state of each repo.
ORG="YOUR_ORG"
gh repo list "$ORG" --limit 1000 --json nameWithOwner -q '.[].nameWithOwner' | while read -r REPO; do
DEFAULT_BRANCH=$(gh api "repos/$REPO" --jq '.default_branch')
gh api "repos/$REPO/branches/main" >/dev/null 2>&1 && MAIN_STATUS="yes" || MAIN_STATUS="no"
gh api "repos/$REPO/branches/master" >/dev/null 2>&1 && MASTER_STATUS="yes" || MASTER_STATUS="no"
echo "$REPO | default=$DEFAULT_BRANCH | has_main=$MAIN_STATUS | has_master=$MASTER_STATUS"
doneThis gives you a snapshot of which repos are ready, which still only have master, and which are already cleaned up.
Switch repos that already have main
Once you know which ones are ready, flip the default branch for those:
ORG="YOUR_ORG"
gh repo list "$ORG" --limit 1000 --json nameWithOwner -q '.[].nameWithOwner' | while read -r REPO; do
if gh api "repos/$REPO/branches/main" >/dev/null 2>&1; then
echo "Switching $REPO to main..."
gh repo edit "$REPO" --default-branch main
else
echo "Skipping $REPO (no main branch)"
fi
doneRename master to main via API
If you want to do everything from GitHub without cloning repos locally:
ORG="YOUR_ORG"
gh repo list "$ORG" --limit 1000 --json nameWithOwner -q '.[].nameWithOwner' | while read -r REPO; do
if gh api "repos/$REPO/branches/main" >/dev/null 2>&1; then
echo "$REPO already has main"
elif gh api "repos/$REPO/branches/master" >/dev/null 2>&1; then
echo "Renaming master to main for $REPO..."
gh api \
--method POST \
"repos/$REPO/branches/master/rename" \
-f new_name='main'
sleep 3
gh repo edit "$REPO" --default-branch main
else
echo "Skipping $REPO (no master or main)"
fi
doneThat's the closest thing to full automation without touching local clones.
The way to think about All of this
This isn't really a branch rename, rather it's a cleanup of accumulated assumptions and a little bit of that tribal knowledge. The branch name just happens to be the thing exposing everything like an eye sore. In all my discussions with customers, I've realized tribal knowledge is directly linked to technical debt. Let's clean that up and quickly.
If you spend a little time on dependencies first, the switch itself becomes boring. Skip that step and you'll still get there (probably), but you'll do it while troubleshooting things that quietly stopped working. My recommendation: do it once, do it cleanly, and you won't ever have to think about it again...at least in theory!




This post explains software cleanup and version control in a very practical way, especially how poor planning can create future technical problems. While studying software engineering concepts, I struggled with structuring workflows and wanted help with assignment to understand how clean system design works. It shows that careful planning in development prevents confusion and saves time in later stages of a project. nice post