Last active
July 15, 2023 08:54
-
-
Save larsxschneider/e431a2dcc325135bcda5cc459e6b6976 to your computer and use it in GitHub Desktop.
Clone a repository with Git LFS files and leverage a local cache.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# | |
# Clone a repository with Git LFS files and leverage a local cache. | |
# | |
# Usage: | |
# | |
# Clone and checkout any branch: | |
# $ clone.sh <repo-url> <cache-dir> <working-copy-dir> <branch-name> | |
# | |
# Clone and checkout a PR head: | |
# $ clone.sh <repo-url> <cache-dir> <working-copy-dir> pull/<pr-id>/head | |
# | |
# Clone and checkout a PR merge: | |
# $ clone.sh <repo-url> <cache-dir> <working-copy-dir> pull/<pr-id>/merge | |
# | |
GIT_REPO_URL=$1 | |
GIT_OBJECT_CACHE_DIR=$2 | |
WORKING_COPY_DIR=$3 | |
REF=$4 | |
# Abort the script if a single command fails. | |
set -e | |
# Check if $DEBUG variable is defined (e.g. with "export DEBUG=1") | |
# If it is defined, then print all commands executed by this script | |
# and all internal commands executed by Git. | |
if [[ -n "$DEBUG" ]]; then | |
set -x | |
export GIT_TRACE=1 | |
fi | |
# Helper function that retries a command if it failed. | |
# This is useful for Git commands that perform network requests as | |
# network requests can always fail. | |
function execute_with_retry { | |
COMMAND=$1 | |
RETRIES=7 # longest continuous wait should be 64s (2**6) | |
COUNT=1 # first try after 4s, if needed | |
RET=1 # make command overwrite this | |
while [ $COUNT -lt $RETRIES ]; do | |
set +e | |
$COMMAND | |
RET=$? | |
set -e | |
if [ $RET -eq 0 ]; then | |
break | |
fi | |
COUNT=$((COUNT+1)) | |
DELAY=$((2**COUNT)) | |
sleep $DELAY | |
done | |
if [ $RET -gt 0 ]; then | |
echo "'$COMMAND' failed with exit code '$RET'" | |
exit $RET | |
fi | |
} | |
# Create cache if it does not exist yet | |
if [ -z "$(ls -A "$GIT_OBJECT_CACHE_DIR" 2>/dev/null)" ]; then | |
printf "\n## Initializing repo cache...\n" | |
execute_with_retry "git clone --bare $GIT_REPO_URL $GIT_OBJECT_CACHE_DIR" | |
fi | |
# Update the cache | |
printf "\n## Fetching latest changes into repo cache...\n" | |
pushd "$GIT_OBJECT_CACHE_DIR" >/dev/null | |
CACHE_URL=$(git remote get-url origin) | |
if [ $CACHE_URL != $GIT_REPO_URL ]; then | |
printf "\nERROR: Repo cache ($CACHE_URL) does not match request repo ($GIT_REPO_URL)!\n" | |
exit 1 | |
fi | |
execute_with_retry "git fetch origin $REF:$REF" | |
execute_with_retry "git lfs fetch origin $REF" | |
popd | |
# Create a fresh clone and leverage the cache | |
printf "\n## Setup working copy...\n" | |
rm -rf "$WORKING_COPY_DIR" | |
mkdir -p "$WORKING_COPY_DIR" | |
pushd "$WORKING_COPY_DIR" >/dev/null | |
git init . | |
mkdir -p .git/objects/info/ | |
echo "${GIT_OBJECT_CACHE_DIR}/objects" > .git/objects/info/alternates | |
git remote add origin "$GIT_REPO_URL" | |
execute_with_retry "git fetch origin $REF:local-ci-branch/$REF" | |
execute_with_retry "git checkout -f local-ci-branch/$REF" | |
popd | |
printf "\n## DONE!\n" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment