Created
February 12, 2021 21:55
-
-
Save GuyPaddock/6433ed4432aa457bcadb407812c3c751 to your computer and use it in GitHub Desktop.
Transplant (rebase) a range of commits from one branch onto another
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
#!/usr/bin/env bash | |
# Stop on undefined variables and errors | |
set -u | |
set -e | |
get_commit_parent() { | |
local target_commit="$1"; | |
local _parent_commit=`git log --pretty=%P -n 1 "${target_commit}"`; | |
local parent_count=`echo "${_parent_commit}" | wc | awk '{ print $2; }'`; | |
if [ "${parent_count}" -ne "1" ]; then | |
echo "'${target_commit}' must have only one parent (parents are '${parent_commit}')." >&2; | |
exit 1; | |
else | |
export parent_commit="${_parent_commit}"; | |
fi | |
} | |
do_transplant() { | |
local target_branch="$1"; | |
local parent_of_first_commit="$2"; | |
local last_commit="$3"; | |
set -x; | |
git checkout "${target_branch}"; | |
# Checkout a new temporary branch at the current location | |
git checkout -b tmp; | |
# Move the target branch to the head of the new patchset | |
git branch -f "${target_branch}" "${last_commit}"; | |
# Rebase the patchset onto tmp, the old location of the target branch | |
git rebase \ | |
--onto tmp "${parent_of_first_commit}" "${target_branch}" \ | |
--committer-date-is-author-date; | |
set +x; | |
cleanup_transplant; | |
} | |
function abort_transplant() { | |
local target_branch="$1"; | |
set -x; | |
git rebase --abort; | |
git checkout tmp; | |
git branch -f "$target_branch" tmp; | |
git checkout "$target_branch"; | |
set +x; | |
cleanup_transplant; | |
} | |
function cleanup_transplant() { | |
set -x; | |
# Delete temporary branch | |
git branch -D tmp; | |
set +x; | |
} | |
function echo_error() { | |
message="$1"; | |
echo "$message" 1>&2; | |
} | |
function print_usage() { | |
script_name=`basename "${0}"`; | |
echo_error "GIT Transplant -- Used to transplant a range of commits from one branch (for"; | |
echo_error "example, 'develop') onto another (for example, a hotfix)."; | |
echo_error ""; | |
echo_error "This script requires GIT and can only be run inside a non-bare GIT repo."; | |
echo_error ""; | |
echo_error "Pass --abort as the fourth parameter to abort a transplant that is "; | |
echo_error "in-progress, rolling branches back to their original state."; | |
echo_error ""; | |
echo_error "Pass --cleanup as the fourth parameter to cleanup after a transplant "; | |
echo_error "that you manually completed successfully after being interrupted by "; | |
echo_error "merge conflicts."; | |
echo_error ""; | |
echo_error "Usage: ${script_name} <target branch> <first commit hash (inclusive)> \\"; | |
echo_error " <last commit hash (inclusive)> [--abort|cleanup]"; | |
} | |
if [[ ($# -ne 3) && (($# -ne 4) || (($# -eq 4) && ($4 != '--abort') && \ | |
($4 != '--cleanup'))) ]]; then | |
print_usage; | |
exit 1; | |
else | |
if [[ $# -eq 4 ]]; then | |
if [ $4 == '--abort' ]; then | |
abort_transplant "$1"; | |
elif [[ $4 == '--cleanup' ]]; then | |
cleanup_transplant; | |
fi; | |
else | |
export parent_commit=""; | |
get_commit_parent "$2" && do_transplant "$1" "${parent_commit}" "$3"; | |
fi; | |
fi; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment