Skip to content

Instantly share code, notes, and snippets.

@rickosborne
Last active December 22, 2015 07:59
Show Gist options
  • Save rickosborne/6441667 to your computer and use it in GitHub Desktop.
Save rickosborne/6441667 to your computer and use it in GitHub Desktop.
Rebase a bunch of branches in a safe(r) way.
#!/bin/bash
# Attempt to do the equivalent of:
# massrebase = "!sh -c 'for branch in $@; do git rebase $0 $branch; done;'"
if [[ -z "${SOURCE_BRANCH}" ]] ; then
SOURCE_BRANCH='origin/master'
fi
# Import some helper functions
. "$(git --exec-path)/git-sh-setup"
require_clean_work_tree 'catch up' 'Please commit or stash any changes.'
function usage {
echo "$0 branch1 branch2 ..."
echo "This script will attempt to catch-up the specified branches by:"
echo " 1. Checking out the branch."
echo " 2. Rebasing from $SOURCE_BRANCH."
echo " 3. Repeat as necessary."
echo "Branches can be globs, like foo*, and will catch-up all matches."
echo "Optional environment variables:"
echo " SOURCE_BRANCH='...' default: origin/master"
exit 1
}
if [[ -z "$1" || "$1" = "--help" || "$1" = "help" || "$1" = "-h" || "$1" = "-?" ]] ; then
usage
fi
REMOTE='origin'
SOURCE="$SOURCE_BRANCH"
RESET=$'\033[0m'
ERR=$'\033[31m'
WARN=$'\033[35m'
if [[ -n $(echo "$SOURCE_BRANCH" | grep '/') ]] ; then
REMOTE=$(echo "$SOURCE_BRANCH" | cut -d / -f 1)
SOURCE=$(echo "$SOURCE_BRANCH" | cut -d / -f 2)
fi
git checkout -q "$BRANCH"
git pull -q "$REMOTE" "$BRANCH"
# for each command-line argument ...
while (( "$#" )) ; do
# list all of the matching branches, as it could be a glob
BRANCHES=$(git branch --list "$1")
# for each matching branch
if [[ -z "$BRANCHES" ]] ; then
printf "${ERR}No branches matched '$1'.${RESET}\n"
else
while read -r TARGET ; do
if [[ $(echo "$TARGET" | cut -c 1) = '*' ]] ; then
# Remove the leading * from the current branch
TARGET=$(echo "$TARGET" | cut -d ' ' -f 2)
fi
# One last check to ensure the branch exists
if [[ -z $(git branch --list "$TARGET") ]] ; then
printf "${ERR}Branch '$TARGET' does not exist.${RESET}\n"
else
MERGE_RESULT=$(git merge-tree `git merge-base "$TARGET" "$SOURCE"` "$SOURCE" "$TARGET")
if [[ -n $(echo "$MERGE_RESULT" | grep -A3 'changed in both') ]] ; then
printf "${ERR}There are conflicts between '$SOURCE' and '$TARGET'${RESET}\n"
else
if [[ -z "$MERGE_RESULT" ]] ; then
printf "${WARN}It looks like '$TARGET' is an old, merged branch that could be deleted.${RESET}\n Remove it with: ${WARN}git branch -d '$TARGET'${RESET}\n"
else
echo "Catching-up '$TARGET' from '$SOURCE'"
git checkout -q "$TARGET"
git rebase -q "$SOURCE_BRANCH"
git checkout -q "$SOURCE"
fi
fi
fi
done <<< "$BRANCHES"
fi
shift
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment