Posted on

A Dev Suppoort tool for GitHub

Every now and then, one may wish to have had a simple script to check out or
update all the github repos you have, at once, using a single command. 

This can be for the reason of backups, or simply, check out new ones that you don’t have etc,
or, keeping a local up-to-date copy of everything. 

Well, I wrote a similar little script some time back for BitBucket.
(https://emberlabs.tech/2023/05/08/easily-mirror-a-bitbucket-repo/)

This should work just fine on pretty much any Linux or Mac install (or similar with a bash). 

Nuf of the talk! Show me the code!! =D

#!/bin/bash
# GH Mass checkout. 
# V 1.0 - 2025-11-23 Spruce
# Prerequisites: curl and jq
# Place your GH PAT in ~/.gitpat (contents / read-only needed)
# Relies on SSH for cloning/pull, add your public key to GH. 

ORG="[Your ORG name here]"
PAT="[Your GH PAT]"
CDIR="$(pwd)"

if [ "${PAT}" == "" ] 
then
    if [ -e ~/.gitpat ] 
    then 
        PAT="$(grep github ~/.gitpat | head -1)"
    else
        echo "No PAT available."
		echo "Create a PAT (Profile -> Settings -> Developer settings -> PAT"
		echo "Select fine-grained,  account/org, and all repos, then select contents with read-only."
        exit 1
    fi
fi

function GetRepoLists {
    echo ""
    echo -n "Updating the repolists : "  
    rm -f repolist.*
    for page in $(seq 1 20) ; do
        echo -n "${page} "
        curl -s \
            -H "Accept: application/vnd.github+json" \
            -H "X-GitHub-Api-Version: 2022-11-28" \
            -H "Authorization: Bearer ${PAT}" \
            "https://api.github.com/orgs/${ORG}/repos?per_page=100&page=${page}" \
            | jq -r '.[].ssh_url' > repolist.${page}
        if [ ! -s "repolist.${page}" ]
        then
            rm -f "repolist.${page}"
            break
        fi
    done
    echo ""

    cat repolist.* > repolist
    rm -f repolist.*
}


function ClonePull {
    mkdir -p ${ORG}

    while IFS= read -r URL; do
        repo="${URL##*/}"
        repobase="${repo%.git}"
        if [ -e "${ORG}/${repobase}" ]
        then
            echo "Updating ${ORG}/${repobase}" 
            cd ${ORG}/${repobase}
            git pull
            cd ${CDIR}
        else
            echo "Cloning  ${URL}"
            cd ${ORG} 
            git clone ${URL}
        fi
    done < "./repolist"
}

function GitExec {
	GITCMD="$1"
	cd ${ORG}
	for repo in *
	do
		echo "Executing ${GITCMD} in ${ORG}/${repo}" 
		cd ${CDIR}/${ORG}/${repo}
		git ${GITCMD}
		cd ${CDIR}
    done 
}

# --- Actions -------------------------------------------------------

case "$1" in
    full)
        GetRepoLists
        ClonePull
        ;;
    pull)
        GitExec "pull"
        ;;
    fetch)
        GitExec "fetch"
        ;;
    *)
        echo "Usage:"
        echo " "
	echo "       full      Update existing and clone new repos."
        echo "       fetch     Execute a fetch on all existing repos."
	echo "       pull      Execute a pull on all existing repos."
    ;; 
esac

Njoy!!