Opening Pull Requests from terminal

:  ~ 2 min read

I recently started using Tower, which, sadly, doesn't support opening Pull Requests. Since I was used to this after using GitUp and SourceTree, I now found the process of opening Pull Requests quite cumbersome. Here's my take on it, by making use of GitHub's hub gem and a bit of .bash_profile tinkering:

# This will return a string with your current branch name.
parse_git_branch() {
  git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ \1/'

# This will return a string with a friendly branch name
# If you have a ticketing system, the naming convention might be
# XXX-123-feature-name, so the output would be XXX-123 Feature name
formatted_git_branch() {
  # Replace all '-' with spaces
  pr_title="${branch//-/ }"
  # Check if it starts with XXX, otherwise we just return the capitalized name
  if [[ $pr_title == XXX* ]]; then
    # XXX-123 test
    if [[ ${pr_title:7:1} == " " ]]; then
      fl="$(echo ${pr_title:8:1} | tr '[:lower:]' '[:upper:]')"
      # XXX-1234 test
      fl="$(echo ${pr_title:9:1} | tr '[:lower:]' '[:upper:]')"
    fl="$(echo ${pr_title:0:1} | tr '[:lower:]' '[:upper:]')"
  # Using ${var^} returns me a 'bad substitute' error, thus the echo workaround
  echo "$pr_title"

# By default it will use the current branch as from and the -b for the base
perform_pull_request() {
  # Default to the development branch as base
  # If we pass an argument, that will be used as the base branch
  if [ -n "$1" ]; then
  # The `hub` command outputs the Pull Request `URL`
  pr_url=$(hub pull-request -b "$branch" -m "$(formatted_git_branch)")
  # Don't try to open the URL if anything went wrong (if the PR already exists, for example)
  if [ $? -eq 0 ]; then
    open "$pr_url"

alias gitpr=perform_pull_request

Final step is to add an Alfred workflow to easily run this from anywhere (here you can read on how that's done):

cd ~/path/to/project && gitpr

Now I can open a Pull Request from anywhere, defaulting to the most used base, development, but also being able to pass it in as an argument.