PaperCut Blog

Tech & DevCoding

Renaming the Git master branch

Renaming the Git <code>master</code> branch

TL;DR: We are renaming our Git master branches to main. This post explains why, shows how we are approaching this, and gives some suggestions that might be useful if you want to make similar changes.

Note that this blog post assumes you have already experience with Git, the world’s most popular version control tool.

Why are we doing this?

Inline with the global Black Lives Matter movement, various developer communities have been looking at behaviours and language to see how we can all be more inclusive. As part of this, the Git community has been doing some soul searching about using master as the default branch name in the git init command. To that end rel 2.28 of Git now provides support to reconfigure the default.

You will find it useful to review GitHub’s corresponding release blog post and some of the linked documents. In addition, this quote from Scott Hanseleman’s blog post is very relevant:

You might say, “I’m all for not using master in master-slave technical relationships, but this is clearly an instance of master-copy, not master-slave” but that may not be the case. Turns out the original usage of master in Git very likely came from another version control system (BitKeeper) that explicitly had a notion of slave branches.

PaperCut needs to: authentically live our anti-racist values; meet expecations in the broader community; and, most importantly, respect our diverse colleagues and partners. These goals need to be addressed with real change. As part of the process PaperCut is examining our use of technical terms and labels as a small part of that change, so renaming the master branch in as many of our repos as possible seems like an obvious thing to do.

On our GitHub repos (public and private) we are changing master branch to main over the next few weeks. GitHub will be automating this process later this year, but we didn’t want to wait. Repos on other systems will follow as well, but will take longer because of some of the issues listed below.

The following notes explain how we are doing this. They also provide some additional information if you want to do something similar.

Note that there are some risks when you rename branches like this.

For example:

  • Open pull requests may reference non existent branches
  • A local repo with multiple remotes can get confusing if only one of the remotes renames a branch
  • Build tools may try and check out or commit on non existent branches
  • API calls on services like GitHub may not work if they have hard coded branch names
  • Git Hook scripts may fail as well for the same reason
  • Developers (particularly on public projects) may get confused

Making the change on existing repositories

I have created a Bash script, adopted from information and examples in various sources (mainly here and here), and you are welcome to adapt it.

#!/bin/bash

# Run this script in a local repo to rename a branch and push the change to remote hosting service.

# Usage:  mv-branch [<old-branch> [<new-branch> [<remote>]]]


#  Default values

# old branch => master
# new branch => main
# remote     => origin

oldb="${1:-master}"
newb="${2:-main}"
remote="${3:-origin}"
 
git checkout $oldb
git pull || ( echo "pull failed, fix and run again" && exit 1 )

git branch -m $oldb $newb
git push -u $remote $newb

echo
echo "Please modify the default (or main) branch on your Git hosting server. Follow the appropriate links for more information"
echo
echo "    GitLab: https://docs.gitlab.com/ee/user/project/repository/branches/#default-branch"
echo "    BitBucket: https://community.atlassian.com/t5/Bitbucket-questions/How-to-change-MAIN-branch-in-BitBucket/qaq-p/977418 "
echo "    GitHub: https://docs.github.com/en/github/administering-a-repository/setting-the-default-branch"
echo
read -p "Press any key when the change is complete" x

git push $remote --delete $oldb

This should be run inside a local repository clone. It:

  1. Checks out the old branch
  2. Makes sure that all changes for the old branch are pulled down and merged locally (if this fails the process stops)
  3. Renames the old branch to the new branch (you can provide arguments to override the master and main defaults, as well as the default name of the remote origin)
  4. Changes are then pushed to the remote, which does not have to be hosted on GitHub.
  5. The user is then prompted to make changes on the hosting site for the default branch (Instructions here for BitBucket, GitLab, and GitHub)
  6. Finally the old branch is deleted on the origin host.

Because of this change your fellow contributors will need to run the following commands in their local repository clones — This script is adapted from Scott Hanleman’s post.

#!/bin/bash

# Run this script in a local repo to rename a branch (usually master) that has been renamed on a remote

# Usage:  update-branch-from-remote [<old-branch> [<new-branch> [<remote>]]]


#  Default values

# old branch => master
# new branch => main
# remote     => origin

oldb="${1:-master}"
newb="${2:-main}"
remote="${3:-origin}"

git checkout $oldb
git branch -m $oldb $newb
git fetch

git branch --unset-upstream
git branch -u $remote/$newb
git symbolic-ref refs/remotes/$remote/HEAD refs/remotes/$remote/$newb

Changing the default for new local repositories

As explained in the GitHub release blog post, if you upgrade to Git 2.28 or above then you can run the command git config --global init.defaultBranch main and all future git init commands will use main as default branch. However, if you can’t upgrade Git at the moment then there is a work around using the Git template directory (this information was adapted from this Stackoverflow reply).

For instance on my Debian Linux system:

cp -a /usr/share/git-core/templates/ ~/.config/git
printf "ref: refs/heads/main\n" > ~/.config/git/templates/HEAD 
git config --global init.templateDir ~/.config/git/templates

On Windows, using Powershell, the following will work assuming you have used the Git Windows installer defaults:

Copy-Item -recurse "C:\Program Files\Git\mingw64\share\git-core\templates" "$env:USERPROFILE\.config\git\templates"
Write-Output "ref: refs/heads/main" > "$env:USERPROFILE\.config\git\templates\HEAD"
git config --global init.templateDir "$env:USERPROFILE\.config\git\templates"

Please post below if you have any questions or comments.

Comments