Skip to content

Instantly share code, notes, and snippets.

@douglascayers
Last active August 1, 2023 02:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save douglascayers/ab002909d09a6c2f13810b0de202da08 to your computer and use it in GitHub Desktop.
Save douglascayers/ab002909d09a6c2f13810b0de202da08 to your computer and use it in GitHub Desktop.
Iteratively backmerges pull requests in sequence using the GitHub and Git CLIs
#!/bin/bash
# For when you have a train of pull requests lined up like A -> B -> C -> D
# and you make a change to base D that you now want backmerged to C then B then A.
set -e
# ----------------------------------------------------------------------------
# List the pull request number (e.g. 42) in order that the backmerges
# should occur, not necessarily numerically.
PULL_REQUESTS=(
42 # https://github.com/your-org/your-repo/pull/42
43 # https://github.com/your-org/your-repo/pull/43
40 # https://github.com/your-org/your-repo/pull/40
)
# ----------------------------------------------------------------------------
# $1 = message to log
function log_info() {
# https://stackoverflow.com/a/5947802/470818
local LIGHT_BLUE='\033[0;34m'
local NC='\033[0m' # No Color
echo "" >&2
echo -e "${LIGHT_BLUE}> ${1} ${NC}" >&2
echo "" >&2
}
# $1 = message to log
function log_warn() {
# https://stackoverflow.com/a/5947802/470818
local YELLOW='\033[0;33m'
local NC='\033[0m' # No Color
echo "" >&2
echo -e "${YELLOW}> ${1}${NC}" >&2
echo "" >&2
}
# Gets the pull request number from the given url or current git repo.
# $1 = pull request url (optional)
function get_pr_id() {
local pr_url="${1}"
gh pr view ${pr_url} --json number | jq -r '.number'
}
# Checks out a pull request into the current git repo.
# $1 = pull request url or number (required)
function git_checkout() {
local pr_id="$(get_pr_id ${1})"
local pr_title=$(get_pr_title ${1})
log_info "checking out pull request -- ${pr_title} -- #${pr_id}"
gh pr checkout ${pr_id}
}
# Get the base branch name of the currently checked out git repository.
# $1 = pull request url or number (optional)
function get_base_ref() {
local pr_id="${1}"
gh pr view ${pr_id} --json baseRefName | jq -r '.baseRefName'
}
# Get the title of the pull request.
# $1 = pull request url or number (optional)
function get_pr_title() {
local pr_id="${1}"
gh pr view ${pr_id} --json title | jq -r '.title'
}
# $1 = pull request url or number (optional)
function backmerge_base_ref() {
local pr_id="${1}"
local base_ref="$(get_base_ref ${pr_id})"
log_info "backmerging branch ${base_ref}"
git merge "origin/${base_ref}" --no-edit
}
function push_merged_changes() {
log_info "pushing merged changes to ${get_head_ref}"
git push
}
function git_fetch() {
git fetch --all --force --prune --prune-tags --no-tags
}
function await_user_to_continue() {
# https://stackoverflow.com/a/5947802/470818
local YELLOW='\033[0;33m'
local NC='\033[0m' # No Color
# https://twitter.com/douglascayers/status/1628175887786029056
log_warn "[ press <enter> to push changes ]"
read -p ''
}
# ----------------------------------------------------------------------------
git_fetch
for pr_url in "${PULL_REQUESTS[@]}"; do
git_checkout ${pr_url}
merge_result=$(backmerge_base_ref)
if [ "${merge_result}" != "Already up to date." ]; then
await_user_to_continue
push_merged_changes
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment