Skip to content

Instantly share code, notes, and snippets.

@vaishnavmhetre
Last active April 14, 2025 08:13
Show Gist options
  • Save vaishnavmhetre/dad7246f2dfceffe2c2f1d8c5ff68e6c to your computer and use it in GitHub Desktop.
Save vaishnavmhetre/dad7246f2dfceffe2c2f1d8c5ff68e6c to your computer and use it in GitHub Desktop.
Git Branches cleanup
# ------------------------------------------------------------------------------
# git_list_untracked
#
# Lists local Git branches that are tracking a remote branch which no longer
# exists (i.e., the remote was deleted or the branch was removed from the remote).
#
# - First runs `git fetch --prune` to clean up stale remote references.
# - Then checks all local branches with an upstream and verifies if the remote
# branch still exists.
# - Filters out "main" and "master" from the results to avoid accidental deletion.
#
# Usage:
# git_list_untracked
# ------------------------------------------------------------------------------
git_list_untracked() {
git fetch --prune
git for-each-ref --format='%(refname:short) %(upstream:short)' refs/heads/ |
while read -r local_branch upstream; do
if [[ -n "$upstream" ]] && ! git show-ref --verify --quiet "refs/remotes/$upstream"; then
echo "$local_branch"
fi
done | grep -vE '^(main|master)$'
}
# ------------------------------------------------------------------------------
# git_remove_untracked [--dry-run]
#
# Deletes local branches that no longer track a valid remote branch.
#
# - By default, deletes branches listed by `git_list_untracked`.
# - Use `--dry-run` to only list the branches that *would* be deleted,
# without actually deleting them.
#
# Skips deletion if no such branches are found.
#
# Usage:
# git_remove_untracked # actually deletes untracked branches
# git_remove_untracked --dry-run # previews deletions only
# ------------------------------------------------------------------------------
git_remove_untracked() {
local dry_run=false
if [[ "$1" == "--dry-run" ]]; then
dry_run=true
fi
local branches
branches=$(git_list_untracked)
if [[ -z "$branches" ]]; then
echo "βœ… No untracked local branches to delete."
return 0
fi
echo "🧹 Untracked branches:"
echo "$branches"
if $dry_run; then
echo "πŸ’‘ Dry run mode. No branches will be deleted."
else
echo "$branches" | xargs -r git branch -D
echo "βœ… Deleted untracked branches."
fi
}
# ------------------------------------------------------------------------------
# git_hard_sync [repo_path]
#
# Safely hard-resets the current branch in the given Git repository (or current
# directory) to match its upstream (remote-tracking) branch.
#
# - Checks if the given path is a Git repository.
# - Detects the current branch and its upstream.
# - Asks for confirmation before discarding local changes via `git reset --hard`.
#
# Useful for syncing a feature branch after someone rebased and force-pushed it.
#
# Usage:
# git_hard_sync # operates in current directory
# git_hard_sync /path/to/repo # operates in the specified repo
# ------------------------------------------------------------------------------
git_hard_sync() {
local repo_path="${1:-.}"
if [ ! -d "$repo_path/.git" ]; then
echo "❌ '$repo_path' is not a valid Git repository."
return 1
fi
(
cd "$repo_path" || exit 1
local branch
branch=$(git rev-parse --abbrev-ref HEAD)
local upstream
upstream=$(git rev-parse --abbrev-ref @{u} 2>/dev/null)
if [ -z "$upstream" ]; then
echo "❌ No upstream branch set for '$branch'."
return 1
fi
echo "πŸ“ In repo: $repo_path"
echo "πŸ” You're on branch '$branch'."
echo "⚠️ This will HARD RESET to match '$upstream'."
read -p "Are you sure? This will discard local changes. (y/N): " confirm
if [[ "$confirm" =~ ^[Yy]$ ]]; then
git fetch && git reset --hard "$upstream"
echo "βœ… Branch '$branch' has been reset to '$upstream'."
else
echo "🚫 Aborted."
fi
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment