|
| 1 | +#!/usr/bin/env bash |
| 2 | +# shallow-reclone-gl.sh |
| 3 | +# |
| 4 | +# Replaces a GitLab repository's full history with a shallow clone from its |
| 5 | +# upstream source. Reduces storage by ~95% for large repos (e.g. Chromium). |
| 6 | +# |
| 7 | +# Strategy: |
| 8 | +# 1. Shallow-clone upstream (--depth=50 --no-tags per branch) |
| 9 | +# 2. Fetch tags shallowly (--depth=1) |
| 10 | +# 3. Force-push all refs to the GitLab mirror |
| 11 | +# 4. Run GitLab housekeeping API to trigger GC immediately |
| 12 | +# |
| 13 | +# Required env vars: |
| 14 | +# GITLAB_TOKEN — GitLab PAT with write access to the target project |
| 15 | +# UPSTREAM_URL — source to clone from (GitHub URL with token embedded) |
| 16 | +# GITLAB_URL — GitLab project URL (with token embedded) |
| 17 | +# GITLAB_PROJECT_ID — numeric project ID (for housekeeping API call) |
| 18 | +# |
| 19 | +# Optional: |
| 20 | +# DEPTH — shallow depth (default: 50) |
| 21 | +# GL_API — GitLab API base (default: https://gitlab.com/api/v4) |
| 22 | + |
| 23 | +set -euo pipefail |
| 24 | + |
| 25 | +DEPTH="${DEPTH:-50}" |
| 26 | +GL_API="${GL_API:-https://gitlab.com/api/v4}" |
| 27 | + |
| 28 | +info() { echo "[shallow-reclone] $*"; } |
| 29 | +warn() { echo "[shallow-reclone] WARN: $*" >&2; } |
| 30 | + |
| 31 | +info "Upstream: ${UPSTREAM_URL//*@/***@}" |
| 32 | +info "GitLab: ${GITLAB_URL//*@/***@}" |
| 33 | +info "Depth: ${DEPTH}" |
| 34 | + |
| 35 | +work_dir=$(mktemp -d) |
| 36 | +trap 'rm -rf "$work_dir"' EXIT |
| 37 | + |
| 38 | +# 1. Shallow-clone all branches from upstream |
| 39 | +info "Cloning upstream (depth=${DEPTH})..." |
| 40 | +if ! git clone --bare --depth="${DEPTH}" --no-tags \ |
| 41 | + "${UPSTREAM_URL}" "${work_dir}" 2>&1; then |
| 42 | + warn "Clone failed — aborting" |
| 43 | + exit 1 |
| 44 | +fi |
| 45 | + |
| 46 | +# 2. Fetch tags shallowly |
| 47 | +info "Fetching tags (depth=1)..." |
| 48 | +git -C "${work_dir}" fetch --depth=1 --tags origin 2>/dev/null || true |
| 49 | + |
| 50 | +# 3. Force-push all refs to GitLab |
| 51 | +info "Force-pushing to GitLab..." |
| 52 | +git -C "${work_dir}" push --force "${GITLAB_URL}" \ |
| 53 | + '+refs/heads/*:refs/heads/*' 2>&1 || true |
| 54 | +git -C "${work_dir}" push --force "${GITLAB_URL}" \ |
| 55 | + '+refs/tags/*:refs/tags/*' 2>&1 || true |
| 56 | + |
| 57 | +info "Push complete." |
| 58 | + |
| 59 | +# 4. Trigger GitLab housekeeping to reclaim storage immediately |
| 60 | +if [[ -n "${GITLAB_PROJECT_ID:-}" ]]; then |
| 61 | + info "Triggering GitLab housekeeping for project ${GITLAB_PROJECT_ID}..." |
| 62 | + HTTP=$(curl -sf -o /dev/null -w "%{http_code}" \ |
| 63 | + -X POST -H "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \ |
| 64 | + "${GL_API}/projects/${GITLAB_PROJECT_ID}/housekeeping" || true) |
| 65 | + info "Housekeeping response: ${HTTP}" |
| 66 | +fi |
| 67 | + |
| 68 | +info "Done." |
0 commit comments