Open a GitHub Pull Request From Your Terminal

You finally did it! You finished writing your new feature and it's fully tested. You write up a snazzy commit message and hit enter. Your command line is telling you that you have a clean branch and you want to share it with the world RIGHT NOW!

Unfortunately, you have a few mind-numbing steps to take before everyone can bask in the glory of your code. First, you have to push the branch to your remote repository. Next, you have to open up the GitHub repo and click on the "New pull request" button. Then you have to manually select the branch you just published. Finally, you can start writing your PR and share it.

Wouldn't it be nice if you could skip all these steps with one command? Jose can help!

My colleague Logan Henson mentioned this in "Tip 3" of his incredibly helpful post, Building a Great Pull Request. I have made some minor improvements since then. I highly recommend reading his blog post.

The process to automate this is a bit more complicated than can be achieved using a bash alias, so we're going to use bash functions. I recommend using Oh My Zsh, since you're able to easily add functions to the ~/.oh-my-zsh-custom/custom/functions.zsh file.

I'll post my functions here and we can go over what they're doing.

Bash Functions to Open a GitHub Pull Request

The openpr() function does all of the heavy lifting. Using commands like git, awk, sed, and cut, it generates the GitHub Pull Request URL using the remote configured in your local repository. Let's dissect what it does.

# Open the Pull Request URL for your current directory's branch (base branch defaults to master)
function openpr() {
  github_url=`git remote -v | awk '/fetch/{print $2}' | sed -Ee 's#(git@|git://)#https://#' -e 's@com:@com/@' -e 's%\.git$%%' | awk '/github/'`;
  branch_name=`git symbolic-ref HEAD | cut -d"/" -f 3,4`;
  pr_url=$github_url"/compare/master..."$branch_name
  open $pr_url;
}

# Run git push and then immediately open the Pull Request URL
function gpr() {
  git push origin HEAD

  if [ $? -eq 0 ]; then
    openpr
  else
    echo 'failed to push commits and open a pull request.';
  fi
}

Generate the GitHub Repo URL (github_url)

github_url=`git remote -v | awk '/fetch/{print $2}' | sed -Ee 's#(git@|git://)#https://#' -e 's@com:@com/@' -e 's%\.git$%%' | awk '/github/'`;

git remote -v lists all of your configured remote repositories. This script assumes that you only have one GitHub remote URL. If your repo has more than one, you will need to add some logic to account for that.

Image showing the result of running git remote -v

awk '/fetch/' takes the result of the git remote call and grabs the line that contains the text "fetch".

At this point, the resulting text looks something like:

origin git@github.com:tightenco/symposium.git (fetch)

If you think about exploding each section of that line by spaces, then you end up with this array-like structure:

['origin', 'git@github.com:tightenco/symposium.git', '(fetch)']

The next command, {print $2}, prints the second of those items. So at this point, we have the text:

git@github.com:tightenco/symposium.git

Now, we use the sed command to modify the text to make it a GitHub URL.

git@github.com:tightenco/symposium.git

turns into

https://github.com/tightenco/symposium.

The final awk command filters out any non-GitHub URLs. This is usually only applicable if you have multiple remotes configured in your repo and one of them is not a GitHub remote.

We have now generated the GitHub URL for the remote repository regardless of whether the repository was cloned using SSH or HTTPS.

Grab the Local Branch Name (branch_name)

We need to get the local branch name so we know which branch we're going to compare in the pull request.

branch_name=`git symbolic-ref HEAD | cut -d"/" -f 3,4`;

By running git symbolic-ref HEAD we get the full reference for the current branch we're on. The result looks something like:

refs/heads/master

We need to explode that string by using / as a delimiter, which would give us an array-like structure of ['refs', 'heads', 'master'] and grab the 3rd item.

We can do this by using the cut command. -d"/" sets the delimiter and -f 3 grabs the 3rd item.

However, sometimes I namespace my branches with my initials like jas/some-feature. So in order for this command to work with that naming structure, I need to use -f 3,4 which grabs everything between the 3rd and 4th item. Feel free to adjust that according to your workflow.

Generate Pull Request Compare URL (pr_url)

Next, we need to generate the URL that will allow us to create the Pull Request. I have it hard-coded to merge into the remote master branch, but you can modify that if you like.

pr_url=$github_url"/compare/master..."$branch_name

This command constructs the full URL for the pull request using the GitHub base URL and branch name we generated in the previous commands. It sets that value to the variable pr_url.

https://github.com/tightenco/symposium/compare/master...jas/some-feature.

The open command automatically opens that URL in your browser. Visiting this URL will open the "Comparing changes" page and all you have to do is click "Create pull request" to write your notes. No need to select specific branches.

The Create Pull Request button on the branch compare page.

But we're not done yet. We still need to publish our branch before it can even be compared. That's where the gpr() function comes in.

Publish Branch to Remote First

function gpr() {
  git push origin HEAD

  if [ $? -eq 0 ]; then
    openpr
  else
    echo 'failed to push commits and open a pull request.';
  fi
}

gpr() is a simple function that will publish your local branch to the remote by using git push origin HEAD.

If that command succeeds, then openpr() is called, otherwise, it displays an error that the branch could not be published.

And that's it. Now you can use the gpr command straight from your command line to automatically open a page to compare two remote branches and start the Pull Request process automatically!