Last active
December 7, 2021 15:46
-
-
Save AliSoftware/be7fd7de9468adaf4e47b615bbecfb1c to your computer and use it in GitHub Desktop.
Sync git working copies' trunk and develop branches and prune local and remote deleted/orphan branches
This file contains 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 -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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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
andtrunk
/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
, andchmod +x
-it.Because the script is named
git-groom
, git will now recognize thegroom
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 ofgit groom
), just name the file accordingly (e.g.git-sync
).Notes