Skip to content

Instantly share code, notes, and snippets.

@AliSoftware

AliSoftware/git-groom

Last active Mar 26, 2021
Embed
What would you like to do?
Sync git working copies' trunk and develop branches and prune local and remote deleted/orphan branches
#!/bin/bash -euo pipefail
#
# Author: O.Halligon
# Jan 2021
#
# Help
if [ "${1:-}" == "-h" -o "${1:-}" == "--help" ]; then
BASENAME=${0##*/}
CMD="${BASENAME/-/ }"
cat <<HELP
usage: $CMD
This command does a little grooming on the working copy by:
- Updating the develop and trunk branches, to pull all their latest changes locally
- Prune all the branches that have been deleted on the remote,
to delete both the local and remote orphan branches from the working copy
- Switch back to the original branch you were working on
HELP
exit 1
fi
# Ensure git working copy is clean before starting
if [ -n "$(git status --porcelain)" ]; then
echo "You seem to have uncommited changes on your working copy. Please commit or stash them first and try again."
exit 2
fi
header() {
echo ""
echo -e "\033[34m### $1\033[0m"
echo ""
}
# Remember the branch we were on before starting the script, to switch back to it at the end.
CURRENT_BRANCH=$(git branch --show-current)
# Try to update every typically-long-living branches
for branch in trunk main master stable develop; do
# Only try to update the branches which actually exist
if (git branch -l --format "%(refname:short)" | grep -q "^${branch}$"); then
header "Update $branch"
git checkout "$branch"
git pull
fi
done
header "Prune deleted branches"
# Prune remote branches and tags that have since been deleted on the remote
git fetch --prune
git fetch --tags --prune
# Remove orphan/gone local branches too – listed as "* feature/branchname 123abc4 [gone] Commit Message"
git branch -v | sed -n 's/^. \([^ ]*\) *[0-9a-f]* \[gone\].*$/\1/p' | xargs git branch -d
header "Switch back to original branch ($CURRENT_BRANCH)"
# Restore original branch (authorize failure and stay on develop since it might have been deleted)
git checkout "$CURRENT_BRANCH" || true
# List remaining local branches for information
header "ℹ️ Local branches left after grooming"
git --no-pager branch -l
@AliSoftware

This comment has been minimized.

Copy link
Owner Author

@AliSoftware AliSoftware commented Jan 26, 2021

Why this script?

This script is especially useful if you work on a repository which moves way faster than you do, for example a repository on which you only intervene sporadically / from time to time, while the other contributors working on that repository are active and making a lot of changes.

In those cases, when you come back to work on the repository yourself, your working copy is very likely quite out of sync, potentially way behind both the develop and trunk/main/stable branches, and some branches that you previously might have fetched or even cloned might now be long gone and deleted. Using that script, git groom will put your working copy back to a state way closer to the current state on the remote, all in one go.

That's something that I need to do quite often as a Platform Engineer, as I have to contribute on our app's repositories from time to time to update tooling and libraries and such, but only sporadically, while the developers working on that app's codebase continuously land many new features every day.

Installation

Save this file in a directory that is in your $PATH, e.g. /usr/local/bin/git-groom, and chmod +x-it.

Because the script is named git-groom, git will now recognize the groom subcommand (git groom, without the dash, but instead used like any git subcommand) as if it was an official part of git itself.

If you prefer to use a different name for this subcommand (e.g. if you prefer it to be git sync or similar instead of git groom), just name the file accordingly (e.g. git-sync).

Notes

  • This is only the initial iteration of the script, so I might have missed some corner cases.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment