Skip to content

Instantly share code, notes, and snippets.

@briangordon
Last active September 16, 2022 17:51
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save briangordon/02c2d2dc52825f0673b74beca2b8b1c1 to your computer and use it in GitHub Desktop.
Save briangordon/02c2d2dc52825f0673b74beca2b8b1c1 to your computer and use it in GitHub Desktop.
Aliases for code reviewing GitHub pull requests using a GitFlow/OneFlow branching model
*****************************************************************************************************************************
Introduction
The code review workflow that I prefer is to check out a feature branch, then `reset --soft` to move the branch HEAD to
just before the changes. That way I still have all of the changes in my working copy, and those exact changes are staged
for commit. My IDE will highlight the changed lines right in the editor and let me click the gutter to view a quick diff.
This is incredibly useful. But problems arise when develop has been merged into a running PR, bringing along a whole bunch
of other unrelated changes that have already been reviewed. I don't want all of those other changes to be highlighted in
my IDE, but I do want them in my working copy.
GitHub's "Files changed" tab handles this perfectly. It only shows the files relevant to the pull request. If at some point
in the PR's history someone has clicked the button to auto-merge develop into the feature branch, none of those merged
commits affect what appears in "Files changed" unless the merge commit also includes a manual conflict resolution fix.
Unfortunately, this has been tedious to reproduce locally, especially for pull requests with lots of merges.
Below are two git aliases which will set up this scenario in your working tree automatically.
*****************************************************************************************************************************
Usage
* git review pr-number [base-branch]
This alias loads up GitHub pull request number $pr-number into your working tree. Your working copy and index are set
to the contents of the latest commit in the pull request, and all relevant changes are staged for commit. You can
optionally provide $base-branch if the PR is merging somewhere other than to the default (develop).
* git review-merge pr-number [base-branch]
This is the same as the previous alias, but it will leave you in a merging state. This may be useful if you want to
commit the merge yourself and force push it to $base-branch bypassing GitHub's merge button.
*****************************************************************************************************************************
Installation
These two aliases come in TWO FLAVORS. You should choose one of the two flavors based on your preferences and copy the
corresponding alias definitions for that flavor to your ~/.gitconfig.
-----------------------------------------------------------------------------------------------------------------------------
| FLAVOR ONE (RECOMMENDED): Your working tree will be ALWAYS left in a detached head state. If you don't know what that |
| means then I recommend that you choose this flavor. |
-----------------------------------------------------------------------------------------------------------------------------
[alias]
review = "!sh -c 'pr=$0 && base=${1:-develop} && if [ \"$0\" = \"sh\" -o \"$2\" != \"\" ]; then echo \"Usage: git review pr-number [base-branch]\"; false; fi && git fetch origin \"$base\" && git fetch origin \"refs/pull/$pr/head\" && git checkout $(git merge-base \"origin/$base\" FETCH_HEAD) && git merge --squash FETCH_HEAD'"
review-merge = "!sh -c 'pr=$0 && base=${1:-develop} && if [ \"$0\" = \"sh\" -o \"$2\" != \"\" ]; then echo \"Usage: git review pr-number [base-branch]\"; false; fi && git fetch origin \"$base\" && git fetch origin \"refs/pull/$pr/head\" && git checkout $(git merge-base \"origin/$base\" FETCH_HEAD) && git merge --no-commit --no-ff FETCH_HEAD'"
-----------------------------------------------------------------------------------------------------------------------------
| FLAVOR TWO (ADVANCED): Your working tree will NORMALLY be left in a detached head state. However, it won't leave HEAD |
| detached at the same commit as your local $base-branch. Instead, it will re-attach HEAD to your |
| local $base-branch since it's there anyway. Beware that this can potentially be confusing if you |
| haven't git pulled and your local $base-branch is different from origin/$base-branch. |
-----------------------------------------------------------------------------------------------------------------------------
[alias]
review = "!sh -c 'pr=$0 && base=${1:-develop} && if [ \"$0\" = \"sh\" -o \"$2\" != \"\" ]; then echo \"Usage: git review pr-number [base-branch]\"; false; fi && git fetch origin \"$base\" && git fetch origin \"refs/pull/$pr/head\" && mergebase=$(git merge-base \"origin/$base\" FETCH_HEAD) && git checkout -f $mergebase && if [ \"$mergebase\" = \"$(git show-ref -s \"refs/heads/$base\")\" ]; then echo \"This PR already incorporates the latest changes from $base. HEAD is moving to $base.\"; git symbolic-ref HEAD \"refs/heads/$base\"; fi && git merge --squash FETCH_HEAD'"
review-merge = "!sh -c 'pr=$0 && base=${1:-develop} && if [ \"$0\" = \"sh\" -o \"$2\" != \"\" ]; then echo \"Usage: git review-merge pr-number [base-branch]\"; false; fi && git fetch origin \"$base\" && git fetch origin \"refs/pull/$pr/head\" && mergebase=$(git merge-base \"origin/$base\" FETCH_HEAD) && git checkout -f $mergebase && if [ \"$mergebase\" = \"$(git show-ref -s \"refs/heads/$base\")\" ]; then echo \"This PR already incorporates the latest changes from $base. HEAD is moving to $base.\"; git symbolic-ref HEAD \"refs/heads/$base\"; fi && git merge --no-commit --no-ff FETCH_HEAD'"
*****************************************************************************************************************************
Troubleshooting
If your GitHub remote is not named "origin" then you should rename it or find/replace in the alias definitions to substitute
your custom name.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment