If you use GitHub much, you'll likely find yourself having to repeatedly use the web interface to raise pull requests. The web interface is great and all, but it can really take you out of your flow if you're used to creating branches, rebasing, pushing, and pulling from the command line!

Creating a pull request

Luckily GitHub has a REST API that you can use to create pull requests instead, and a nice command line wrapper to invoke it called Hub! Hub wraps the git command line tool - effectively adding extra commands you can invoke from the command line. Once it's installed (and aliased) you'll be able to call:

> git pull-request

and a new pull request will be created in your repository:

New pull request

If you're someone who likes using the command line, this can really help streamline your workflow.

Installing Hub

Hub is available on GitHub so you can download binaries, or install it from source. As I use chocolatey on my dev machine, I chose to install Hub using chocolatey by running the following from an administrative powershell:

> choco install hub

Installing Hub

Chocolatey will download and install hub into its standard installation folder (C:\ProgramData\chocolatey by default). As this folder should be in your PATH, you can type hub version from the command line and you should get back something similar to:

> hub version
git version 2.15.1.windows.2  
hub version 2.2.9  

That's it, you're good to go. The first time you use Hub to create a pull request (PR), it will prompt you for your GitHub username and password.

Creating a pull request with Hub

Hub is effectively an extension of the git command line, so it can do everything git does, and just adds some helper GitHub methods on top. Anything you can do with git, you can do with hub.

You can view all the commands available by simply typing hub into the command line. As hub is a wrapper for git it starts by displaying the git help message:

> hub
usage: git [--version] [--help] [-C <path>] [-c name=value]  
           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
           [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
           <command> [<args>]

These are common Git commands used in various situations:

start a working area (see also: git help tutorial)  
   clone      Clone a repository into a new directory
   init       Create an empty Git repository or reinitialize an existing one
...

At the bottom, hub lists the GitHub specific commands available to you:

These GitHub commands are provided by hub:

   pull-request   Open a pull request on GitHub
   fork           Make a fork of a remote repository on GitHub and add as remote
   create         Create this repository on GitHub and add GitHub as origin
   browse         Open a GitHub page in the default browser
   compare        Open a compare page on GitHub
   release        List or create releases (beta)
   issue          List or create issues (beta)
   ci-status      Show the CI status of a commit

As you can see, there's a whole bunch of useful commands there. The one I'm interested in is pull-request.

Lets imagine we have already checked out a repository we own, and we have created a branch to work on a feature, feature-37:

Image of gitk showing master branch and the my-feature-branch branch

Before we can create a PR, we need to push our branch to the server:

> git push origin -u feature-37

To create the PR, we use hub. This will open up your configured text editor to enter a message for the PR (I use Notepad++) . In the comments you can see the commit messages for the branch, or if your PR only has a single commit (as in this example), hub will handily fill the message in for you, just as it does in the web interface:

Image of PR editor opened up

As you can see from the comments in the screenshot, the first line of your message forms the PR title, and the remainder forms the description of the PR. After saving your message, hub spits out the URL for your PR on GitHub. Follow that link, and you can see your shiny new PR ready and waiting approval:

PR created on GitHub.com

Hub can do lots more than just create pull requests, but for me that's the killer feature I use everyday. If you use more features, then you may want to consider aliasing your hub command to git as it suggests in the docs.

Aliasing hub as git

As I mentioned earlier, hub is a wrapper around git that provides some handy extra tweaks. It even enhances some of the standard git commands: it can expand partial URLs in a git clone to be github.com addresses for example:

> hub clone andrewlock/test

# expands to
git clone git://github.com/andrewlock/test.git  

If you find yourself using the hub command a lot, then you might want to consider aliasing your git command to actually use Hub instead. That means you can just do

> git clone andrewlock/test

for example, without having to think about which commands are hub specific, and which are available in git. Adding an alias is safe to do, you're not modifying the underlying git program or anything, so don't worry about that.

If you're using PowerShell, you can add the alias to your profile by running:

> Add-Content $PROFILE "`nSet-Alias git hub"

and then restarting your session. For troubleshooting and other scripts see https://github.com/github/hub#aliasing.

Streamlining PR creation with a git alias

I love how much time hub has saved me by keeping my hands on the keyboard, but there's one thing that was annoying me: having to run git push before opening the PR. I'm a big fan of Git aliases, so I decided to create an alias called pr that does two things: push, and create a pull request.

If you're new to git aliases, I highly recommend checking out this post from Phil Haack. He explains what aliases are, why you want them, and gives a bunch of really useful aliases to get started.

You can create aliases directly from the command line with git, but for all but the simplest ones I like to edit the .gitconfig file directly. To open your global .gitconfig for editing, use

> git config --global --edit

This will popup your editor of choice, and allow you to edit to your heart's content. Locate the [alias] section of your config file (or if it doesn't exist, add it), and enter the following:

[alias]
    pr="!f() { \
        BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD); \
        git push -u origin $BRANCH_NAME; \
        hub pull-request; \
    };f "

This alias uses the slightly more complex script format that creates a function and executes it immediately. In that function, we do three things:

  • BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD); - Get the name of the current branch from git and store it in a variable, BRANCH_NAME
  • git push -u origin $BRANCH_NAME; - Push the current branch to the remote origin, and associate it with the remote branch of the same name
  • hub pull-request - Create the pull request using hub

To use the alias, simply check out the branch you wish to create a PR for and run:

> git pr

This will push the branch if necessary and create the pull request for you, all in one (prompting you for the PR title in your editor as usual).

> git pr
Counting objects: 11, done.  
Delta compression using up to 8 threads.  
Compressing objects: 100% (11/11), done.  
Writing objects: 100% (11/11), 1012 bytes | 1012.00 KiB/s, done.  
Total 11 (delta 9), reused 0 (delta 0)  
remote: Resolving deltas: 100% (9/9), completed with 7 local objects.  
To https://github.com/andrewlock/NetEscapades.AspNetCore.SecurityHeaders.git  
 * [new branch]      feature-37 -> feature-37
Branch 'feature-37' set up to track remote branch 'feature-37' from 'origin'.  
https://github.com/andrewlock/NetEscapades.AspNetCore.SecurityHeaders/pull/40  

Note, there is code in the Hub GitHub repository indicating that hub pr is going to be a feature that allows you to check-out a given PR. If that's the case this alias may break, so I'll keep an eye out!

Summary

Hub is a great little wrapper from GitHub that just simplifies some of the things I do many times a day. If you find it works for you, check it out on GitHub - it's written in Go and I've no doubt they'd love to have more contributors.