Created
December 26, 2022 01:01
-
-
Save KenanBek/294d21b95a85cee9c54d0a17a8c90dcb to your computer and use it in GitHub Desktop.
Shell script to clone repositories at a specific branch, remove the `.git` folder, and have a clean, archived copy of the repository. Read more: https://kenanbek.medium.com/archive-git-repositories-with-shell-script-987d944af769
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
# parse the command-line arguments | |
while getopts ":nh" opt; do | |
case ${opt} in | |
h) | |
echo "Usage:" | |
echo " git-clone.sh [-n]" | |
echo "" | |
echo "Options:" | |
echo " -n Skip commit and push" | |
exit 0 | |
;; | |
n) | |
# set a flag to skip the commit_and_push function | |
no_push=1 | |
;; | |
\?) | |
echo "Invalid option: -$OPTARG" >&2 | |
exit 1 | |
;; | |
esac | |
done | |
# list of repositories with list of branches for each repository | |
repos=( | |
"git@github.com:KenanBek/dbui.git;main,dev" | |
"git@github.com:KenanBek/django-skeleton.git;master" | |
) | |
# define ANSI escape codes for color | |
COLOR_GREEN='\033[32m' | |
COLOR_RESET='\033[0m' | |
# extract rightmost text until the first "/" from the right and remove the rightmost ".git" | |
function extract_repo_name { | |
# input string | |
input=$1 | |
# extract rightmost text until the first "/" from the right | |
result="${input##*/}" | |
# remove the rightmost ".git" | |
result="${result%.git}" | |
# return the result | |
echo "$result" | |
} | |
# clone a repository by the given repository and branch | |
function clone_repo { | |
# repository url, name, and branch | |
repo_url=$1 | |
repo_name=$(extract_repo_name $repo_url) | |
branch_name=$2 | |
# construct the folder name | |
folder_name=$repo_name-$branch_name | |
# print the cloning message | |
echo "Cloning ${COLOR_GREEN}\"$repo_name\"${COLOR_RESET} at branch ${COLOR_GREEN}\"$branch_name\"${COLOR_RESET} into folder ${COLOR_GREEN}\"$folder_name\"${COLOR_RESET}" | |
# if the folder already exists, check the commit hash | |
if [ -d "$folder_name" ]; then | |
echo "Folder ${COLOR_GREEN}\"$folder_name\"${COLOR_RESET} already exists" | |
echo "Checking commit hash" | |
# get the commit hash from the file | |
commit_hash=$(cat $folder_name/commit-hash.txt) | |
# get the commit hash from the remote | |
remote_commit_hash=$(git ls-remote $repo_url $branch_name | cut -f 1) | |
# if the commit hashes are equal, skip the repository | |
if [ "$commit_hash" == "$remote_commit_hash" ]; then | |
echo "Commit hash ${COLOR_GREEN}\"$commit_hash\"${COLOR_RESET} is equal to remote commit hash ${COLOR_GREEN}\"$remote_commit_hash\"${COLOR_RESET}, skipping" | |
return | |
fi | |
# otherwise, remove the folder | |
echo "Commit hash ${COLOR_GREEN}\"$commit_hash\"${COLOR_RESET} is not equal to remote commit hash ${COLOR_GREEN}\"$remote_commit_hash\"${COLOR_RESET}, removing folder ${COLOR_GREEN}\"$folder_name\"${COLOR_RESET}" | |
rm -rf $folder_name | |
fi | |
# clone the repository at the branch into the folder | |
git clone -b $branch_name $repo_url $folder_name | |
# write commit hash to file | |
git ls-remote $repo_url $branch_name | cut -f 1 > $folder_name/commit-hash.txt | |
# remove the .git folder | |
rm -rf $folder_name/.git | |
} | |
# function to commit changes in the current folder and push them to the remote | |
function commit_and_push { | |
# commit the changes | |
git add . | |
git commit -m "Update at $(date)" | |
# push the changes | |
git push | |
} | |
# iterate over the list and clone each repository | |
for repo in "${repos[@]}" | |
do | |
# split the repository name and branch names | |
repo_url=$(echo $repo | cut -d ';' -f 1) | |
branch_names=$(echo $repo | cut -d ';' -f 2) | |
# iterate over the branch names and clone the repository for each branch | |
for branch_name in $(echo $branch_names | tr "," "\n") | |
do | |
clone_repo $repo_url $branch_name | |
echo "" | |
done | |
done | |
# iterate over all subfolders and verify .git folder is removed | |
for folder in ./* | |
do | |
# if the folder is not a directory, skip it | |
if [ ! -d "$folder" ]; then | |
continue | |
fi | |
# if the folder contains a .git folder, remove it | |
if [ -d "$folder/.git" ]; then | |
echo "Removing .git folder from ${COLOR_GREEN}\"$folder\"${COLOR_RESET}" | |
rm -rf $folder/.git | |
fi | |
done | |
# wait for all sub-processes to finish | |
wait | |
# commit and push the changes | |
# check the no_push flag before calling the commit_and_push function | |
if [ -z "$no_push" ]; then | |
# commit and push the changes | |
echo "Committing and pushing changes" | |
commit_and_push | |
else | |
# print the skipping message | |
echo "Skipping commit and push" | |
fi | |
echo "${COLOR_GREEN}Done${COLOR_RESET}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment