Skip to content

Instantly share code, notes, and snippets.

@hyperupcall
Last active May 14, 2021 04:35
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hyperupcall/7edd9f31843d40b12c1db2ff40a283d9 to your computer and use it in GitHub Desktop.
Save hyperupcall/7edd9f31843d40b12c1db2ff40a283d9 to your computer and use it in GitHub Desktop.
Cross-platform shell script to change the 'master' branch to 'main' for the local and remote repository
#!/bin/sh -eu
# code licensed under BSD 2-Clause "Simplified" License
# see `change-master-branch-to-main.sh --help` for usage
# see twitter thread for more details: https://twitter.com/EdwinKofler/status/1272729160620752898
site="github.com"
oldDefaultBranch="master"
newDefaultBranch="main"
bin="gh" # or set to 'hub'
user="${1:-""}"
repo="${2:-""}"
# ------------------- helper functions ------------------- #
showHelp() {
echo "change-master-branch-to-main.sh"
echo
echo "Description:"
echo " Cross-platform shell script to change the 'master' branch to"
echo " 'main' for the local and remote repository. Should work with"
echo " providers besides Github, but I haven't tested that"
echo
echo "Usage:"
echo " change-master-branch-to-main.sh [username] [repo name]"
echo " Rename the 'master' branch to 'main' both for the local"
echo " and remote repository with the specified variables. It"
echo " also sets the default branch to 'main' if the previous"
echo " default was 'master'"
echo " change-master-branch-to-main.sh"
echo " Same as above, but intelligently guesses (and ask user for"
echo " confirmation) the github user and repo names"
echo
echo "Requirements:"
echo " 'jq' and 'gh' are optional dependencies and are only required"
echo " when trying to update the GitHub default branch"
echo
echo "Examples:"
echo " change-master-branch-to-main.sh eankeen deno-babel"
}
# get the GitHub username, if it wasn't already specified
askUser() {
# return if user is already set (passed as arg)
test ! -z "$user" && return
# get github username and strip quotes
url="$(git config --get remote.origin.url)"
# if url looks like git@github.com:user/repo
if [ "$(echo "$url" | cut -d'@' -f1)" = "git" ]; then
user="$(echo "$url" | sed -E "s/(.*:)(.*)(\/.*)/\2/g")"
else
user="$(echo "$url" | sed -E "s/(.*$site\/)(.*)(\/.*)/\2/g")"
fi
printInfo "github username (default: %s): " "$user"
read -r
# trim whitespace
REPLY="$(echo "$REPLY" | xargs)"
user="${REPLY:-$user}"
printInfo "input: $user\n\n"
}
# get the GitHub repository name, if it wasn't already specified
askRepo() {
# return if repo is already set (passed as arg)
test ! -z "$repo" && return
url="$(git config --get remote.origin.url)"
repo="$(basename -s .git "$url")"
printInfo "github repository name (default: %s): " "$repo"
read -r
# trim whitespace
REPLY="$(echo "$REPLY" | xargs)"
repo="${REPLY:-$repo}"
printInfo "input: $repo\n\n"
}
remoteMainExists() {
git show-branch "refs/remotes/origin/$newDefaultBranch" >/dev/null 2>&1
}
remoteMasterExists() {
git show-branch "refs/remotes/origin/$oldDefaultBranch" >/dev/null 2>&1
}
localMainExists() {
git rev-parse --verify --quiet "refs/heads/$newDefaultBranch" >/dev/null
}
localMasterExists() {
git rev-parse --verify --quiet "refs/heads/$oldDefaultBranch" >/dev/null
}
hasColor() {
test -t 1 && command -v tput >/dev/null && \
test -n "$(tput colors)" && test "$(tput colors)" -ge 8
}
hasBinAndJq() {
command -v jq >/dev/null && command -v "$bin" >/dev/null
}
printInfo() {
if hasColor; then
printf "\033[0;94m"
# shellcheck disable=SC2059
printf "$@"
printf "\033[0m"
else
# shellcheck disable=SC2059
printf "$@"
fi
}
# ------------------------- main ------------------------- #
test "${1:-""}" = "--help" && showHelp && exit
git fetch --all
git checkout "$oldDefaultBranch"
git push origin "$oldDefaultBranch"
# ensure 'main' is the default locally
if ! localMainExists; then
printInfo "renaming '$oldDefaultBranch' to '$newDefaultBranch' locally\n"
git checkout $oldDefaultBranch
git branch --move $oldDefaultBranch "$newDefaultBranch"
fi
# ensure 'main' is at remote
if ! remoteMainExists; then
printInfo "setting '$newDefaultBranch' as default upstream branch\n"
git checkout "$newDefaultBranch"
git push --set-upstream origin "$newDefaultBranch"
fi
# remove local 'master' branch
if localMasterExists; then
printInfo "renaming local $oldDefaultBranch branch\n"
git branch --delete $oldDefaultBranch
fi
# ensure github default branch is 'main'
if hasBinAndJq; then
askRepo
askUser
beforeNewbranch="$("$bin" api "repos/$user/$repo" -X GET | jq --raw-output ".default_branch")"
# sets new default branch
if test "$beforeNewbranch" = "$oldDefaultBranch"; then
"$bin" api "repos/$user/$repo" -X PATCH -F default_branch="$newDefaultBranch"
fi
afterNewbranch="$("$bin" api "repos/$user/$repo" -X GET | jq --raw-output ".default_branch")"
printInfo "default branch at $user/$repo was: '$beforeNewbranch'\n"
printInfo "default branch at $user/$repo is now: '$afterNewbranch'\n"
fi
# remove remote 'master' branch
if remoteMasterExists; then
printInfo "deleting remote $oldDefaultBranch branch\n"
# if this fails, it may be due to forgetting
# to reset the default branch to 'main' on github
git push origin --delete $oldDefaultBranch
test ! $? && printInfo "this probably errored since '$oldDefaultBranch' is still the 'default branch' on github" \
&& printInfo "if you install \`gh\` and \`jq\` this will be done for you"
fi
@hkatzdev
Copy link

This is really cool - would it be possible to add an option to change main to any name, in case people want trunk for instance?

@hyperupcall
Copy link
Author

@hkatzdev yah! since your comment i added a variable at the top for that ;)

@hkatzdev
Copy link

I don't know why but I kept getting ! [remote rejected] master (refusing to delete the current branch: refs/heads/master) error: failed to push some refs to 'https://github.com/hkatzdev/hackagotchi.git' when running the script. Every time I tried to clone with hub it wouldn't change the head ref, even though I ended up manually doing it in github. Maybe its a hub problem?

@hyperupcall
Copy link
Author

hyperupcall commented Jun 16, 2020

@hkatzdev can you please provide more output? like it should say default branch at hkatzdev/hackagotchi is now 'main' somewhere

i would recommend troubleshooting with hub api "repos/hkatzdev/hackagotchi" -X GET | jq and hub api "repos/hkatzdev/hackagotchi" -X PATCH -F default_branch="main". does that latter output anything? if not maybe there are some issues with authentication? you can also remove the >/dev/null from line 162 for more details

@kishoreesxi
Copy link

kishoreesxi commented Jan 31, 2021

@eankeen it so cool. will this same script work for GITLAB as well ?

@hyperupcall
Copy link
Author

hyperupcall commented Feb 1, 2021

@eankeen it so cool. will this same script work for GITLAB as well ?

Thank you! It should work, provided you set site=gitlab.com near the top - but it's not tested :) I don't think GitLab is fully supported. To get complete support, you'll have to modify the requests starting near line 150 that use the gh or hub utility (basically anything that executes the utility referred to by "$bin")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment