Skip to content

Instantly share code, notes, and snippets.

@carpii
Created February 19, 2026 19:34
Show Gist options
  • Select an option

  • Save carpii/1174554aac4836795de4c75a064ad347 to your computer and use it in GitHub Desktop.

Select an option

Save carpii/1174554aac4836795de4c75a064ad347 to your computer and use it in GitHub Desktop.
bash script to clone all nested gitlab groups and repos from a parent group id
#!/usr/bin/env bash
set -euo pipefail
usage() {
echo "Usage: ${0##*/} -t <token> [-g <id>]"
echo
echo "Arguments:"
echo " -t <token> personal access token (required)"
echo " -g <id> groupID to clone (defaults to your membership projects)"
}
die() {
echo "$1" >&2
exit 1
}
require_cmd() {
command -v "$1" >/dev/null 2>&1 || die "Missing dependency: $1"
}
GITLAB_TOKEN=""
GROUPID=""
while getopts "ht:g:" opt; do
case "$opt" in
h)
usage
exit 0
;;
t)
GITLAB_TOKEN="${OPTARG}"
;;
g)
GROUPID="${OPTARG}"
;;
*)
usage >&2
exit 1
;;
esac
done
[[ -n "${GITLAB_TOKEN}" ]] || { usage >&2; exit 1; }
require_cmd curl
require_cmd jq
require_cmd git
PER_PAGE=100
PAGE=1
if [[ -n "${GROUPID}" ]]; then
API_PATH="/api/v4/groups/${GROUPID}/projects?include_subgroups=true"
else
API_PATH="/api/v4/projects?membership=true"
fi
while :; do
JSON="$(
curl -sS \
--header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
"https://gitlab.com${API_PATH}&per_page=${PER_PAGE}&page=${PAGE}"
)"
COUNT="$(echo "${JSON}" | jq 'length')"
[ "${COUNT}" -eq 0 ] && break
echo "${JSON}" |
jq -r '.[] | [.path_with_namespace, .ssh_url_to_repo] | @tsv' |
while IFS=$'\t' read -r path repo; do
dir="${path%/*}"
mkdir -p "${dir}"
if [[ -d "${path}/.git" ]]; then
echo "Skipping existing repo: ${path}"
continue
fi
git clone "${repo}" "${path}"
done
PAGE=$((PAGE + 1))
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment