Skip to content

Instantly share code, notes, and snippets.

@ninenine
Created August 27, 2024 12:21
Show Gist options
  • Save ninenine/e5dece0059003e8ac846a80cb7d47aa7 to your computer and use it in GitHub Desktop.
Save ninenine/e5dece0059003e8ac846a80cb7d47aa7 to your computer and use it in GitHub Desktop.
Git Cleanup

Git Repository Cleanup Script

This Bash script is designed to clean up and optimize a Git repository by reducing its size and removing unnecessary files and objects. Below is a summary of its functionalities:

Usage

Usage: ./git-clean.sh [-f] [-b branch_name]
  -f: Force aggressive cleanup (use with caution)
  -b branch_name: Specify the branch to clean (default: current branch)

Features

1. Basic Cleanup

  • Fetch Latest Changes:
    The script fetches all branches and prunes any branches that no longer exist on the remote.

  • Switch Branch:
    It checks out the specified branch (or remains on the current branch if none is specified).

  • Garbage Collection:
    Performs Git's garbage collection in aggressive mode to remove unreachable objects and optimize the repository.

  • Reflog Cleanup:
    Expires all reflog entries immediately, removing old references.

  • File Cleanup:
    Removes untracked files and directories, excluding those ignored by .gitignore.

2. Aggressive Cleanup (Optional)

  • Forceful File Removal:
    Removes all untracked files, directories, and ignored files (use with caution).

  • Repository Repackaging:
    Repackages the repository with specified depth and window size for better compression.

  • Object Pruning:
    Removes all unreachable objects that are not part of any branch or tag.

  • History Rewriting:
    Aggressively rewrites the repository history by removing cached .log files (use with extreme caution as this is irreversible).

3. Optimization

  • Database Optimization:
    Optimizes the Git repository database for better performance.

4. Push Changes to Remote

  • Safe Force Push:
    Forcefully pushes changes to the remote repository using --force-with-lease to prevent overwriting others' work.

5. Size Reporting

  • Size Calculation:
    The script calculates and displays the initial and final sizes of the repository to show the impact of the cleanup.

6. Remote Cleanup Reminder

  • Post-Cleanup Reminder:
    The script reminds the user to possibly force push to the remote and ask their Git host to run garbage collection for further size reduction.

Important Notes

  • Aggressive Cleanup:
    The -f option enables aggressive cleanup, which includes irreversible actions like history rewriting and forceful file removal. Use this option with extreme caution.

  • Remote Size Reduction:
    To fully realize size reductions on the remote repository, you may need to force push the changes and request garbage collection from your Git host.

#!/bin/bash
# Function to display script usage
usage() {
echo "Usage: $0 [-f] [-b branch_name] [-d directory]"
echo " -f Force aggressive cleanup (use with caution)"
echo " -b branch_name Specify the branch to clean (default: current branch)"
echo " -d directory Specify the directory containing the git repository (default: current directory)"
exit 1
}
# Default values
force=false
branch=""
directory="."
# Parse command line options
while getopts "fb:d:" opt; do
case $opt in
f) force=true ;;
b) branch=$OPTARG ;;
d) directory=$OPTARG ;;
*) usage ;;
esac
done
# Ensure the specified directory exists
if [[ ! -d $directory ]]; then
echo "Error: Directory '$directory' does not exist."
exit 1
fi
# Change to the specified directory
cd "$directory" || { echo "Error: Cannot change to directory '$directory'"; exit 1; }
# Ensure we're in a git repository
if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
echo "Error: Not in a git repository"
exit 1
fi
# If no branch is specified, use the current branch
if [[ -z $branch ]]; then
branch=$(git rev-parse --abbrev-ref HEAD)
fi
# Store initial size
initial_size=$(du -sh . | cut -f1)
echo "Starting Git repository cleanup in directory: $directory"
echo "Initial repository size: $initial_size"
# Fetch the latest changes
git fetch --all --prune
# Switch to the specified branch
if ! git checkout $branch; then
echo "Error: Unable to checkout branch '$branch'"
exit 1
fi
# Run garbage collection
echo "Running garbage collection..."
git gc --aggressive --prune=now
# Remove old reflog entries
echo "Removing old reflog entries..."
git reflog expire --expire=now --all
# Clean up unnecessary files
echo "Cleaning up unnecessary files..."
git clean -fd
if $force; then
echo "Performing aggressive cleanup..."
# Remove all untracked files (use with caution!)
git clean -ffdx
# Repack the repository
git repack -a -d --depth=250 --window=250
# Remove old objects
git prune --expire now
# Aggressively remove old objects
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch **/*.log' \
--prune-empty --tag-name-filter cat -- --all
fi
# Optimize the repository
echo "Optimizing the repository..."
git reflog expire --expire-unreachable=now --all
git repack -A -d
git prune
git gc --aggressive --prune=now
# Push changes to remote (force push with lease for safety)
echo "Pushing changes to remote..."
git push --force-with-lease
# Calculate size reduction
final_size=$(du -sh . | cut -f1)
echo "Final repository size: $final_size"
echo "Cleanup complete!"
# Remind about remote cleanup
echo "Note: To reduce the size on the remote, you may need to force push and ask your Git host to run garbage collect
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment