Skip to content

Instantly share code, notes, and snippets.

@kepocnhh
Last active July 3, 2026 18:41
Show Gist options
  • Select an option

  • Save kepocnhh/db0562440170f2fc3496065610fcd052 to your computer and use it in GitHub Desktop.

Select an option

Save kepocnhh/db0562440170f2fc3496065610fcd052 to your computer and use it in GitHub Desktop.
gitbackups.sh
#!/usr/local/bin/bash
CURRENT_DIR="$(pwd)"
if [[ $? != 0 ]]; then
echo 'Get current dir error!'; exit 1; fi
CONFIG_FILE="${CURRENT_DIR}/reps.yml"
if [[ -L "${CONFIG_FILE}" ]]; then
echo "\"${CONFIG_FILE}\" is a symlink!" >&2; exit 1
elif [[ ! -e "${CONFIG_FILE}" ]]; then
echo "\"${CONFIG_FILE}\" does not exist!" >&2; exit 1
elif [[ ! -f "${CONFIG_FILE}" ]]; then
echo "\"${CONFIG_FILE}\" is not a file!" >&2; exit 1
elif [[ ! -s "${CONFIG_FILE}" ]]; then
echo "\"${CONFIG_FILE}\" is empty!" >&2; exit 1
fi
# github
GITHUBX_API='https://api.github.com'
GITHUBX_API_VERSION='2026-03-10'
GITHUBX_PER_PAGE=64
GITHUBX_DST="$(mktemp)"
OWNER_COUNT="$(yq -M -p=yml -o=yml '.github.owners | length' "${CONFIG_FILE}")"
OWNER_NUMBER=0
while IFS= read -r REP_OWNER; do
OWNER_NUMBER=$((OWNER_NUMBER+1))
REP_OWNER_DIR="${CURRENT_DIR}/${REP_OWNER}"
if [[ -L "${REP_OWNER_DIR}" ]]; then
echo "\"${REP_OWNER_DIR}\" is a symlink!" >&2; exit 1
elif [[ -e "${REP_OWNER_DIR}" ]]; then
if [[ ! -d "${REP_OWNER_DIR}" ]]; then
echo "\"${REP_OWNER_DIR}\" is not a dir!" >&2; exit 1; fi
else
mkdir "${REP_OWNER_DIR}"
if [[ $? != 0 || ! -d "${REP_OWNER_DIR}" ]]; then
echo "Make \"${REP_OWNER_DIR}\" dir error!"; exit 1; fi
fi
#
rm "${GITHUBX_DST}"
HTTP_CODE=$(curl -m 8 -w '%{http_code}' \
"${GITHUBX_API}/users/${REP_OWNER}/repos?per_page=${GITHUBX_PER_PAGE}&sort=pushed" \
--header 'Accept: application/vnd.github+json' \
--header "X-GitHub-Api-Version: ${GITHUBX_API_VERSION}" \
-o "${GITHUBX_DST}" 2>/dev/null)
if [[ $? -ne 0 || "${HTTP_CODE}" != '200' ]]; then
echo "Request ${REP_OWNER} error!" >&2; continue; fi
#
REP_COUNT="$(yq -M -p=json -o=yml 'length' "${GITHUBX_DST}")"
REP_NUMBER=0
while IFS= read -r REP_NAME; do
REP_NUMBER=$((REP_NUMBER+1))
printf "%03d / %03d ${REP_OWNER} %03d / %03d"$'\n' "${OWNER_NUMBER}" "${OWNER_COUNT}" "${REP_NUMBER}" "${REP_COUNT}"
if [[ ! -d "${REP_OWNER_DIR}/${REP_NAME}.git" ]]; then
echo "Git clone ${REP_OWNER}/${REP_NAME}..."
git clone --quiet --bare "https://github.com/${REP_OWNER}/${REP_NAME}.git" "${REP_OWNER_DIR}/${REP_NAME}.git"
if [[ $? != 0 ]]; then
echo "Git clone ${REP_OWNER}/${REP_NAME} error!"; continue; fi
fi
echo "Git fetch ${REP_OWNER}/${REP_NAME}..."
git -C "${REP_OWNER_DIR}/${REP_NAME}.git" fetch --quiet -p --tags
if [[ $? != 0 ]]; then
echo "Git fetch ${REP_OWNER}/${REP_NAME} error!"; continue; fi
done < <(yq -M -p=json -o=yml '.[].name' "${GITHUBX_DST}")
done < <(yq -M -p=yml -o=yml '.github.owners[]' "${CONFIG_FILE}")
OWNER_COUNT="$(yq -M -p=yml -o=yml '.github.reps | keys | length' "${CONFIG_FILE}")"
OWNER_NUMBER=0
while IFS= read -r REP_OWNER; do
OWNER_NUMBER=$((OWNER_NUMBER+1))
REP_OWNER_DIR="${CURRENT_DIR}/${REP_OWNER}"
if [[ -L "${REP_OWNER_DIR}" ]]; then
echo "\"${REP_OWNER_DIR}\" is a symlink!" >&2; exit 1
elif [[ -e "${REP_OWNER_DIR}" ]]; then
if [[ ! -d "${REP_OWNER_DIR}" ]]; then
echo "\"${REP_OWNER_DIR}\" is not a dir!" >&2; exit 1; fi
else
mkdir "${REP_OWNER_DIR}"
if [[ $? != 0 || ! -d "${REP_OWNER_DIR}" ]]; then
echo "Make \"${REP_OWNER_DIR}\" dir error!"; exit 1; fi
fi
REP_COUNT="$(yq -M -p=yml -o=yml ".github.reps.${REP_OWNER} | length" "${CONFIG_FILE}")"
REP_NUMBER=0
while IFS= read -r REP_NAME; do
REP_NUMBER=$((REP_NUMBER+1))
printf "%03d / %03d ${REP_OWNER} %03d / %03d"$'\n' "${OWNER_NUMBER}" "${OWNER_COUNT}" "${REP_NUMBER}" "${REP_COUNT}"
if [[ ! -d "${REP_OWNER_DIR}/${REP_NAME}.git" ]]; then
echo "Git clone ${REP_OWNER}/${REP_NAME}..."
git clone --quiet --bare "https://github.com/${REP_OWNER}/${REP_NAME}.git" "${REP_OWNER_DIR}/${REP_NAME}.git"
if [[ $? != 0 ]]; then
echo "Git clone ${REP_OWNER}/${REP_NAME} error!"; continue; fi
fi
echo "Git fetch ${REP_OWNER}/${REP_NAME}..."
git -C "${REP_OWNER_DIR}/${REP_NAME}.git" fetch --quiet -p --tags
if [[ $? != 0 ]]; then
echo "Git fetch ${REP_OWNER}/${REP_NAME} error!"; continue; fi
done < <(yq -M -p=yml -o=yml ".github.reps.${REP_OWNER}[]" "${CONFIG_FILE}")
done < <(yq -M -p=yml -o=yml '.github.reps | keys | .[]' "${CONFIG_FILE}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment