Skip to content

Instantly share code, notes, and snippets.

@ForestJay
Forked from kevinwright/git_cleanup
Last active February 28, 2024 03:21
Show Gist options
  • Save ForestJay/ef1a6b113e882f861d3b to your computer and use it in GitHub Desktop.
Save ForestJay/ef1a6b113e882f861d3b to your computer and use it in GitHub Desktop.
#!/bin/bash
# WARNING
# This expects your repository to be in ~/git . If your repository is elsewhere you will need to alter the script.
# SYNOPSIS
# git_cleanup [repo name] [-xl]
# DESCRIPTION
# This script allows people to delete (-x) the history of a directory OR destroy (-l) the history of a directory and just
# retain the latest version (useful for cutting down on space consumption).
# OPTIONS
# -x, --expunge <directory> Deletes the directory and its history.
# -l, --keeplatest <directory> Deletes the history but keeps the latest version.
if [ ! -d ~/git/ ]; then
echo "This script currently requires your repository to be in ~/git . Either change your path or your script!"
exit
fi
if [ $# -lt 2 ]; then
echo "format: git_cleanup <repo name> [-x/--expunge <directory 1> -l/--keeplatest <directory 2> ...]"
exit
fi
PROJ="$1"
shift
if [ ! -d ~/git/${PROJ}.git ]; then
echo "Your repository directory must end with .git !"
exit
fi
export EXPUNGE=()
export KEEPLATEST=()
while [[ $# > 1 ]]; do
key="$1"
shift
case $key in
-x|--expunge)
folder="$1"
EXPUNGE+=("$folder")
echo "expunging: $folder"
shift
;;
-l|-k|--keeplatest)
folder="$1"
KEEPLATEST+=("$folder")
echo "keeping latest: $folder"
shift
;;
*)
echo "unknown option $key"
echo "format: git_cleanup <repo name> [-x/--expunge <directory 1> -l/--keeplatest <directory 2> ...]"
exit
;;
esac
done
echo -------------------------------------------------------------------
echo setting up working repositories
cd ~/git
# folders used:
# X-shrinking: (non-bare) working repo where we rewrite git indexes to cut the unwanted folders
# X-stash: For retainlatest folders, keep a copy here during the expunging
# X-addback: a (non-bare) clone of the post-expunged shrinking repo, where we add back stashed folders
# X-shrink.git: The output
[ -d ${PROJ}-shrinking ] && rm -rf ${PROJ}-shrinking
[ -d ${PROJ}-stash ] && rm -rf ${PROJ}-stash
[ -d ${PROJ}-shrunk.git ] && rm -rf ${PROJ}-shrunk.git
mkdir ${PROJ}-stash
git clone --no-local ${PROJ}.git ${PROJ}-shrinking
cd ${PROJ}-shrinking
for folder in ${KEEPLATEST[@]}; do
echo "stashing the latest version of $folder"
rsync -az ~/git/${PROJ}-shrinking/$folder/ ~/git/${PROJ}-stash/$folder
done
echo -------------------------------------------------------------------
echo filtering...
BADFOLDERS=("${EXPUNGE[@]}" "${KEEPLATEST[@]}")
FILTERPARTS=$(for folder in ${BADFOLDERS[@]}; do echo "git rm -rf --cached --ignore-unmatch $folder"; done)
export FILTERCMD=${FILTERPARTS[0]}$(printf " \&\& %s" "${FILTERPARTS[@]:1}")
git filter-branch -f --index-filter '$FILTERCMD' --prune-empty --tag-name-filter cat -- --all
rm -Rf refs/original
rm -Rf refs/logs
git gc
echo -------------------------------------------------------------------
cd ~/git
git clone --no-local ${PROJ}-shrinking ${PROJ}-addback
cd ${PROJ}-addback
for folder in ${KEEPLATEST[@]}; do
echo "restoring from stashed copy of $folder"
rsync -az ~/git/${PROJ}-stash/$folder/ ~/git/${PROJ}-addback/$folder
git add . --all
git commit -a -m "re-adding latest version of $folder"
done
echo "Cloning to output repository"
cd ~/git
git clone --bare --no-local ${PROJ}-addback ${PROJ}-shrunk.git
read -p "delete working data (y/n)?"
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
rm -rf ${PROJ}-shrinking
rm -rf ${PROJ}-addback
rm -rf ${PROJ}-stash
fi
read -p "backup original and replace with shrunk repository (y/n)?"
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
mv ${PROJ}.git ${PROJ}-$(date -u +"%Y-%m-%dT%H:%M:%SZ").git
mv ${PROJ}-shrunk.git ${PROJ}.git
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment