Created
May 31, 2025 22:26
-
-
Save tailot/849d5c9109c2c8eace80f21738d31143 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
#!/bin/bash | |
# USAGE: | |
# ./cleangit.sh | |
# | |
# DESCRIPTION: | |
# cleangit.sh is an interactive script for cleaning and maintaining a Git repository. | |
# It runs a series of Git commands to optimize the repository, remove obsolete branches, | |
# and untracked files. | |
# | |
# PREREQUISITES: | |
# 1. The script must be executable: | |
# chmod +x cleangit.sh | |
# 2. The script MUST be run from the root directory of the Git repository you intend to clean. | |
# | |
# OPERATION: | |
# The script will guide the user through the following steps, asking for confirmation before | |
# performing potentially destructive operations: | |
# | |
# 1. Repository integrity check (git fsck). | |
# 2. Garbage Collection (git gc --prune=now --aggressive) to optimize space. | |
# 3. Pruning of obsolete remote-tracking branches (git remote prune <remote_name>). | |
# You will be asked for the remote name (default: 'origin'). | |
# 4. Optional removal of local branches that have already been merged into the current branch (HEAD), | |
# excluding common protected branches (master, main, develop, etc.). | |
# 5. Optional and destructive removal of untracked files (git clean -fdx). | |
# An option to perform a dry-run (git clean -fdxn) will be offered first. | |
# | |
# WARNINGS: | |
# - Ensure you have committed or stashed all important changes before running the script. | |
# - The removal of untracked files (Step 5) is a destructive operation, and | |
# files will be permanently deleted. Proceed with caution. | |
print_header() { | |
echo "" | |
echo "---------------------------------------------------------------------" | |
echo " $1" | |
echo "---------------------------------------------------------------------" | |
} | |
run_command() { | |
local cmd_string="$1" | |
echo "-> Executing: ${cmd_string}" | |
eval "${cmd_string}" | |
local status=$? | |
if [ $status -ne 0 ]; then | |
echo "WARNING: The previous command '${cmd_string}' finished with an error status: $status." | |
fi | |
return $status | |
} | |
if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then | |
echo "ERROR: This script must be run from the main directory of a Git repository." | |
exit 1 | |
fi | |
echo "Starting Git repository cleanup in: $(pwd)" | |
echo "Make sure you have committed or stashed all important changes before proceeding." | |
read -p "Do you want to continue? (y/N): " confirm_start | |
if [[ ! "$confirm_start" =~ ^[Yy]$ ]]; then | |
echo "Operation cancelled by the user." | |
exit 0 | |
fi | |
print_header "Step 1: Repository Integrity Check (git fsck)" | |
run_command "git fsck --full" | |
echo "If 'git fsck' reports 'dangling objects', these are usually not a problem and will be handled by 'git gc'." | |
echo "More serious problems may require manual intervention." | |
print_header "Step 2: Garbage Collection (git gc)" | |
echo "This process may take some time, especially for large repositories." | |
run_command "git gc --prune=now --aggressive" | |
echo "'git gc' completed." | |
print_header "Step 3: Pruning Obsolete Remote-Tracking Branches (git remote prune)" | |
default_remote="origin" | |
read -p "For which remote do you want to run 'prune' (e.g., 'origin', 'upstream'. Default: ${default_remote}): " remote_name | |
remote_name="${remote_name:-${default_remote}}" | |
if git remote | grep -q "^${remote_name}$"; then | |
echo "You can run 'git remote prune ${remote_name} --dry-run' to see what would be pruned." | |
read -p "Do you want to prune obsolete remote-tracking branches for '${remote_name}'? (y/N): " confirm_prune_remote | |
if [[ "$confirm_prune_remote" =~ ^[Yy]$ ]]; then | |
run_command "git remote prune ${remote_name}" | |
echo "Pruning for '${remote_name}' completed." | |
else | |
echo "Pruning for '${remote_name}' skipped." | |
fi | |
else | |
echo "WARNING: The remote '${remote_name}' was not found. Skipping this step." | |
fi | |
print_header "Step 4: Removing Merged Local Branches (Optional)" | |
echo "This command will attempt to remove local branches that have been fully merged" | |
echo "into the current branch (HEAD). Common protected branches (e.g., master, main, develop) will be ignored." | |
current_branch_name=$(git rev-parse --abbrev-ref HEAD) | |
echo "Current branch: $current_branch_name" | |
merged_branches_to_consider=$(git branch --merged | grep -v "^\*" | sed 's/^[ *]*//' | grep -vE "^(master|main|develop|release/.*|hotfix/.*|${current_branch_name})$") | |
if [ -z "$merged_branches_to_consider" ]; then | |
echo "No merged local branches (other than protected/current) to remove." | |
else | |
echo "The following merged local branches are candidates for removal:" | |
echo "$merged_branches_to_consider" | sed 's/^/ - /' | |
read -p "Do you want to remove these branches? (y/N): " confirm_delete_merged | |
if [[ "$confirm_delete_merged" =~ ^[Yy]$ ]]; then | |
echo "$merged_branches_to_consider" | xargs -r git branch -d | |
echo "Selected merged local branches removed." | |
else | |
echo "Removal of merged local branches skipped." | |
fi | |
fi | |
print_header "Step 5: Removing Untracked Files (git clean) - DESTRUCTIVE OPERATION (Optional)" | |
echo "WARNING: This operation will PERMANENTLY remove untracked files from your working directory." | |
echo "This includes files, directories (-d), and files normally ignored by .gitignore (-x)." | |
echo "" | |
echo "It is STRONGLY RECOMMENDED to first run 'git clean -fdxn' (dry-run) to see which files would be removed." | |
read -p "Do you want to run a dry-run ('git clean -fdxn') now? (y/N): " confirm_dry_run_clean | |
if [[ "$confirm_dry_run_clean" =~ ^[Yy]$ ]]; then | |
run_command "git clean -fdxn" | |
fi | |
read -p "Are you SURE you want to proceed with the permanent removal of untracked files ('git clean -fdx')? (y/N): " confirm_clean | |
if [[ "$confirm_clean" =~ ^[Yy]$ ]]; then | |
echo "Running 'git clean -fdx'..." | |
run_command "git clean -fdx" | |
echo "Untracked files removed." | |
else | |
echo "Cleaning of untracked files skipped." | |
fi | |
print_header "Cleanup Completed" | |
echo "The repository has been processed." | |
echo "Check the output for any messages or warnings." | |
echo "It might be a good idea to check the repository status with 'git status' and 'git log'." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment