Skip to content

Instantly share code, notes, and snippets.

@9999years
Created September 28, 2020 19:28
Show Gist options
  • Save 9999years/8328257d9942ceeb8f68ed6f9516b22f to your computer and use it in GitHub Desktop.
Save 9999years/8328257d9942ceeb8f68ed6f9516b22f to your computer and use it in GitHub Desktop.
Rename the default branch on all your GitHub repos. Warning: this script deletes the old default branch, which makes GitHub *automatically close* open PRs to that branch.
#! /usr/bin/env bash
set -e
oldBranch="master"
newBranch="main"
# {{{ Colors, logging boilerplate
readonly PROG_NAME="$0"
function RESET { echo -e "\e[0m"; }
function BOLD { echo -e "\e[1m"; }
function RESET_BOLD { echo -e "\e[21m"; }
function DIM { echo -e "\e[2m"; }
function RESET_DIM { echo -e "\e[22m"; }
function UNDERLINED { echo -e "\e[4m"; }
function RESET_UNDERLINED { echo -e "\e[24m"; }
function BRRED { echo -e "\e[31m"; }
function RED { echo -e "\e[91m"; }
function BRGREEN { echo -e "\e[32m"; }
function GREEN { echo -e "\e[92m"; }
function BRYELLOW { echo -e "\e[33m"; }
function YELLOW { echo -e "\e[93m"; }
function BRBLUE { echo -e "\e[34m"; }
function BLUE { echo -e "\e[94m"; }
function BRPURPLE { echo -e "\e[35m"; }
function PURPLE { echo -e "\e[95m"; }
function BRCYAN { echo -e "\e[36m"; }
function CYAN { echo -e "\e[96m"; }
function BRGRAY { echo -e "\e[37m"; }
function GRAY { echo -e "\e[97m"; }
function RESET_FG { echo -e "\e[39m"; }
function now { date +%FT%T; }
# _log COLORS LABEL [MESSAGE [...]]
function _log {
color="$1"
shift
level="$1"
shift
echo -n "$color$level $PROG_NAME ${color}[$(now)]:" "$@"
RESET
}
# }}}
function dbg { _log "$(GRAY)" "[debug]" "$@"; }
function info { _log "$(BRGREEN)" "[info] " "$@"; }
function warn { _log "$(BRYELLOW)" "[warn] " "$@"; }
function error { _log "$(BRRED)" "[error]" "$@"; }
function fatal { _log "$(BOLD)$(BRRED)" "[FATAL]" "$@"; exit 1; }
function cmd { _log "$(CYAN)" "[run] " "\$ $(BOLD)$(UNDERLINED)$*"; }
function rename {
repo="$1"
clone_url="https://github.com/$repo.git"
oldRef=$(git ls-remote "$clone_url" "refs/heads/$oldBranch")
if [[ -z "$oldRef" ]]; then
refs=$(git ls-remote "$clone_url")
if [[ -z "$refs" ]]; then
warn "$repo: no branches/refs found; probably empty"
else
headRef=$(echo "$refs" | grep -E $'\t''HEAD$' | cut -f1)
defaultBranch=$(echo "$refs" \
| grep -E "^$headRef"$'\t' \
| cut -f2 \
| grep -vE '^HEAD$' \
| sed 's|^refs/heads/||')
if [[ "$defaultBranch" = "$newBranch" ]]; then
info "$repo: no $oldBranch branch: default branch is already $defaultBranch"
else
warn "$repo: no $oldBranch branch: default branch is currently $defaultBranch"
fi
fi
return
fi
newRef=$(git ls-remote "$clone_url" "refs/heads/$newBranch")
tmp=$(mktemp -d)
cmd "git clone $clone_url $tmp"
git clone -q "$clone_url" "$tmp"
pushd "$tmp" >/dev/null || return
if [[ -z "$newRef" ]]; then
# no $newBranch branch; create
info "$repo: creating $newBranch branch"
cmd "git branch -m $oldBranch $newBranch"
git branch -m "$oldBranch" "$newBranch"
cmd "git push -u origin $newBranch"
git push -q -u origin "$newBranch" || return
fi
git switch -q "$newBranch"
info "$repo: setting default branch to $newBranch"
hub api --obey-ratelimit -XPATCH "repos/$repo" --field "default_branch=$newBranch" >/dev/null
info "$repo: removing $oldBranch branch"
cmd "git push origin --delete $oldBranch"
git push -q origin --delete "$oldBranch"
cmd "git remote set-head origin -a"
git remote set-head origin -a
popd >/dev/null || return
info "$repo: deleting tmpdir"
rm -rf "$tmp"
}
if ! hub --version >/dev/null; then
fatal "hub not found; see $(UNDERLINED)https://github.com/github/hub"
fi
if ! jq --version >/dev/null; then
fatal "jq not found; see $(UNDERLINED)https://stedolan.github.io/jq/"
fi
info "Listing user repositories; this requires a GitHub API call so it'll list about 50 repos/second"
repos=$(hub api \
--method GET \
--paginate \
--obey-ratelimit \
user/repos \
--field 'type=owner' \
| jq --raw-output \
--arg branch "$newBranch" \
'.[]
| select(.fork or .archived or .default_branch == $branch | not)
| .full_name')
reposCount=$(echo "$repos" | wc -l)
dbg "Found $reposCount repos: $repos"
i=0 # repo counter just for progress
while IFS="" read -r repo
do
(( i += 1 ))
info "$i / $reposCount"
rename "$repo"
done < <(echo "$repos")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment