Created
September 28, 2020 19:28
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /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