Skip to content

Instantly share code, notes, and snippets.

@igstan
Last active May 30, 2024 17:35
Show Gist options
  • Save igstan/0a89b8bb1a6df0754647cdd87d8221b6 to your computer and use it in GitHub Desktop.
Save igstan/0a89b8bb1a6df0754647cdd87d8221b6 to your computer and use it in GitHub Desktop.
Clone all your GitHub gists, public or private.
#!/usr/bin/env bash
# Clones all gists (public or private) into directory `gists/` (auto-created
# and configurable if desired). The cloned gists are placed into directory
# names formed from the name of the first file found in the gist concatenated
# to the gist ID. For example, this gist will be cloned into:
#
# gists/clone-gists.sh-0a89b8bb1a6df0754647cdd87d8221b6
#
# USAGE:
#
# 1. Get a token with gist reading permissions from here:
# https://github.com/settings/tokens?type=beta
#
# 2. Export your token in an env var called `GITHUB_GISTS_TOKEN`:
#
# $ export GITHUB_GISTS_TOKEN=<YOUR_TOKEN>
#
# 3. Execute script with default destination directory:
#
# $ ./clone-gists.sh
#
# Or with a custom destination directory:
#
# $ DST_DIR=my_gists ./clone-gists.sh
#
# SYNCING:
#
# On subsequent executions, the script will skip already cloned gists by
# default, but you can override that. This will effectively issue `git pull`
# commands inside the already cloned gists:
#
# $ SYNC=1 ./clone-gists.sh
#
# SSH CLONING
#
# By default, the script uses HTTP cloning, mostly because it's faster, but if
# you want it to use SSH, you can ask it to do that too:
#
# $ USE_SSH=1 ./clone-gists.sh
#
shopt -so errexit
shopt -so nounset
shopt -so pipefail
shopt -s lastpipe
log() {
printf '%s' "$@"
printf '\n'
} >&2
declare -r token="${GITHUB_GISTS_TOKEN:?missing; create one at https://github.com/settings/tokens?type=beta}"
# Where should we put the gists? In "gists/" by default.
declare -r dst_dir=${DST_DIR:-gists}
# Should we update in case they're already cloned? Not by default.
declare -ri sync=${SYNC:-0}
# Should we clone using SSH? Not by default.
declare -ri use_ssh=${USE_SSH:-0}
# What external commands are we using?
declare -ra dependencies=(curl git jq)
gists() {
declare -r page=${1:-1}
declare -r url="https://api.github.com/gists?per_page=25&page=$page"
log "Fetching URL: $url"
curl -sSLH "Authorization: Bearer $token" "$url"
}
clone() {
declare -ri page=${1:-1}
if (( page > 1 )); then
read -r count
if [[ "$count" == 0 ]]; then return; fi
while IFS=, read -r id url key; do
dst="$dst_dir/$key-$id"
if [[ -d "$dst" ]]; then
if (( sync )); then
log "Gist already cloned; updating: $dst"
git -C "$dst" pull
else
log "Skipping already cloned gist: $dst"
fi
else
log "Cloning gist: $url → $dst"
if (( use_ssh )); then
git clone "git@gist.github.com:$id.git" "$dst"
else
git clone "$url" "$dst"
fi
fi
done
fi
gists "$page" \
| jq -r 'length, (.[] | [.id, .git_pull_url, (.files | to_entries[0].key)] | join(","))' \
| clone $(( page + 1 ))
}
main() {
for cmd in "${dependencies[@]}"; do
if ! command -v "$cmd" &> /dev/null; then
log "error: $cmd command is missing"
exit 1
fi
done
log "Cloning gists into: $dst_dir/"
mkdir -p "$dst_dir"
clone
}
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment