How I Rebase PRs

The Wrong Way

Hate is a strong word, but I very much dislike Github’s PR review / approve / merge flow.

My Better Way

I don’t like merge commits. I also don’t like merging in 5+ commits with names like “wip”, “bugfix”, “trying again” on a feature add.

To avoid all of that without having a lot of back and forth, here’s my approach

  1. Work from the PR branch
    • git remote add ... the user/org of the PR request, locally
    • git checkout ... their branch, as is
  2. Rebase on the latest, and squash junk commits
    • git rebase ... the with the current main/master
    • git rebase -i ... to squash the fixups
  3. Update the PR with the up-to-date, conflict free history:
    • git push --force ... to update the PR
    • note: this only works if the user/org has allowed you to write to their PR branch - which is usually the case since it’s the default

However, that’s a real headache to do because github doesn’t provide a nice copy/paste snippet.

And so I created my own little script so that I can just copy/paste two pieces of info from the PR page and get rolling:

# Usage
gh-review <project-name> <fork-abbrev> [branch-name] [fork-project-name]
# Example
gh-review awesome-sauce rando:patch-1 add-feature-x

Here’s the source:

gh-review:

#!/bin/bash
set -e
set -u

# The goal here is to be able to copy and paste from the limited info
# that we get from Github and review a PR _The Right Way™_:
if [[ -z ${2:-} ]]; then
    echo ""
    echo "Usage:"
    echo '    gh-review <project-name> <fork-abbrev> [branch-name] [fork-project-name]'
    echo ""
    echo "Example:"
    echo "    gh-review awesome-sauce rando:patch-1 add-feature-x"
    echo ""
    echo "Scenario:"
    echo "    - You maintain 'github.com/you/awesome-sauce'"
    echo "    - A PR comes in from 'guthub.com/rando/awesome-sauce'"
    echo "    - They've used the default branch name of 'patch-1'"
    echo "    - You want to work on this as branch 'add-feature-x'"
    echo ""
    exit 1
fi

# Here we "parse" the fork abbrevation we get from github:
my_repo="${1}"
my_pr="${2}"
pr_remote="$(echo "${my_pr}" | cut -d':' -f1)"
pr_branch="$(echo "${my_pr}" | cut -d':' -f2-99)"
our_branch="${3:-"${pr_branch}"}"
their_repo="${4:-"${my_repo}"}"

# This (filled out) is the copy/paste snippet that I wish github would give me:
git remote add "${pr_remote}" "ssh://git@github.com/${pr_remote}/${their_repo}.git" || true
git fetch "${pr_remote}"
git checkout -b "${our_branch}" "${pr_remote}/${pr_branch}"

# This is my process for keeping my git history clean:
echo ""
echo "Here are your next steps:"
echo ""
echo "    # to bring up-to-date"
echo "    git rebase main"
echo ""
echo "    # squash extraneous commits messages with 'f' or 's' "
echo "    git rebase -i main"
echo ""
echo "    # push the clean history back to the remote"
echo "    git push --force '${pr_remote}' '${our_branch}':'${pr_branch}'"
echo ""

How to install gh-review:

chmod a+x gh-review

mkdir ~/.local/bin
mv gh-review ~/.local/bin

curl https://webinstall.dev/pathman | bash
pathman add ~/.local/bin

Another Shortcut

I maintain webinstall.dev, so I made a shorcut script webi-review that calls gh-review with the project name webi-installers so that I can copy/type less.

webi-review:

#!/bin/bash

set -e
set -u

gh-review webi-installers "$@"