GitHub from the CLI with Hub
For fans of the command line who are also regular users of GitHub there’s a great option for integrating Git & GitHub commands into the same CLI workflow.
It’s called hub and it’s maintained by GitHub. While the README is okay, there a few missing details and I couldn’t find any other tutorials on getting started. So I decided to write one!
This tutorial covers:
- Configuration of auto-completion and
- Authentication and remote repo creation
- More thorough usage example with GitHub Flow
Only continue if you are already familiar with Git as well as browser-based usage of GitHub. To get up-to-speed see GitHub’s own on-demand training courses
As per the README, you can install on Mac, Windows and Fedora with the package managers Homebrew, Chocolatey and DNF respectively.
I’ll provide instructions specific for Ubuntu (tested on 16.04 and 17.10) but you should be able to follow along with modifications for most OSes.
First download the latest of either version 2.3.0 or the latest stable binary for Linux. In this tutorial, I’ll be using version 2.3.0 for some newer features (assigning issues to a user). At this moment it’s not stable (v2.2.9 is) but should be soon.
To install we’ll untar and run the
install script, which creates the
/usr/local/bin and a manpage.
tar zxvf hub-linux-ARCH-X.Y.Z.tgz sudo hub-linux-ARCH-X.Y.Z/install
You can confirm the install (your versions will likely be different):
$ hub version git version 2.11.0 hub version 2.3.0-pre10
Integrate with git command and enable auto-completion
Both these parts are optional, as we can now use all of
functionality. But two options to consider for a better experience are:
- aliasing it with
- enable auto-completion for a better experience
For auto-completion, first we need to put the
file included in the release somewhere permanent.
sudo cp etc/hub.bash_completion.sh /usr/local/etc
Now, for Ubuntu, we’ll add the following lines to
# Alias hub with git eval "$(hub alias -s)" # Enable hub auto-completion if [ -f /usr/local/etc/hub.bash_completion ]; then . /usr/local/etc/hub.bash_completion fi
To see the effects, open a new terminal or run
source ~/.bashrc, then
confirm success with:
$ git version git version 2.11.0 hub version 2.3.0-pre10
Also hit tab after
git and you should see auto-completion display a
list of available commands.
Authenticate and Create Repos
To use hub we need to authenticate with GitHub. This is done by providing your login credentials.
hub will store your username and an oauth token in a
You can delete the token anytime in https://github.com/settings/tokens
to revoke access.
Logging in and Brand New Repository
hub expands certain
git commands with additional options while
creating new ones:
git initis one it expands, with the
-gflag, hub will initialize a repo while automatically adding a remote
git createis a new command with hub, it will create the repo on GitHub
git browseis another new command it will open GitHub in your default browser
Let’s try these both with our throwaway “hubapp”:
git init -g hubapp # you'll be asked for your credentials if you're first time cd hubapp echo "# My New Hub App" > README.md #optional but let's put something in there git add . git commit -m "Initial commit" git create # hubapp now exists on GitHub! git push -u origin master git browse # will open hubapp on GitHub in your browser
Existing Local Repository
A more typical scenario is where you’ve done some work on a new project locally and want to create it on GitHub. Now you can run a simple command instead of:
- Opening up your browser
- Logging into GitHub
- Creating a project on GitHub
- Adding your remote locally
- Hopefully getting it right the first time
Let’s say you’re in an existing app with some killer potential called “theNextFacebook” and want to start some GitHub collaboration.
git create # remote added and repo created on GitHub under your user's namespace git push -u origin master # that's it! git browse # optionally, open in your browser
Alternatively add an ORG/NAME argument to
git create the repo under an
organization’s namespace instead (your user will need the required
permissions in the organization).
GitHub Flow with git+hub
In this final part we’ll see that we can complete
GitHub Flow from the CLI with
hub commands. Let’s pretend we’re working on a small project
with a few contributors using the
Shared Repository Model.
- Create and assign an issue
- Create and work on a topic branch
- Sync with GitHub and rebase on master for a clean history
- Push and create pull request
- Merge with master and close issue
Create an issue
First we’ll create an issue and assign ourselves:
git issue create -a mygithubusername
Your default text editor will open. The first line will be the title while the rest will be the description. For example:
Add fetch user action To be called by multiple components for a customized interface
Just save and close and the issue is created! You can list the issues
Work on a topic branch
Next, we’ll create a branch both locally and on GitHub. The second part is optional at this moment, but provides visibility to peers on what’s being worked on.
git checkout -b fetch-user-action git push -u origin !$ # note: !$ is a bash shortcut for last word of last command
…we develop, test and commit changes locally…
Great. Now, everything is working nicely, so let’s do a pull request, but let’s pretend two things have happened:
- we have multiple commits in this topic branch, including typo fixes
- buddy just pushed his own changes on another feature, so our topic branch is behind master
We want a clean commit history when our branch is merged into master, so how do we achieve this?
Rebase and Sync
First let’s squash our multiple commits into one. For simplicity’s sake let’s say we only have two our topic branch:
$ git log --oneline 513568e Fix typo... oops 5dda11f Finished fetch user ...older commits
We’ll run an interactive
git rebase -i HEAD~2
Git will show you this in your text editor:
pick 5dda11f Finished fetch user pick 513568e Fix typo... oops # ... A bunch of instructions
All we need to do is tell Git to squash the 2nd commit, then save and close. We’ll use a special type of squash called “fixup” which also discards the commit message, but incorporates the changes into the first commit. If we used “squash” instead we’d have an opportunity to rewrite the entire commit message (an unncessary step in this specific scenario).
pick 5dda11f Finished fetch user fixup 513568e Fix typo... oops
git log again will show one commit in the place of these two,
with a new hash but the same message “Finished fetch user”.
Now let’s update our master branch and use rebase again. We’re using rebase here to apply our commit on top of any interim changes made to master by our buddy. This way we can avoid the noisy and unnecessary “merge commit”.
git sync # use the new sync command to tersely update master locally git diff master # check to see if there are may be any conflicts warranting a different approach git rebase master # rebase your branch commit on top of master
If there were no unresolvable conflicts, you’ll get this message:
First, rewinding head to replay your work on top of it... Applying: Finished fetch user
If there is an unresolvable conflict, you’ll need to deal with that (Git
will help you a lot here) then use
rebase --continue. I’m not going to
go into detail on this here, so instead I’ll suggest some resources:
- For more on the why and how of rebasing the topic branch check out this article.
- Some additional instructions on resolving conflicts and rebase –continue.
Create Pull Request
Next, let’s push and create a pull request at the same time. We’ll
assign ourselves, but you can also ask for “reviewers” to check the
quality of the work with the
-r flag. As we’ll likely be practising
this flow alone the first few times let’s skip the reviewers part.
git push #this pushes to topic branch remotely git pull-request -a reviewersusername
Similar to the issue, you will now write your PR message. Make sure
the body includes a reference to the original issue, so it will be
closed automatically, for example put “Closes #11” in the body
where NUM is substituted with number of the issue. To get the issue
Add fetch user action Closes #1
Merge and Close
Now let’s finally merge the topic branch and push, closing the pull request and issue at the same time.
git checkout master git merge fetch-user-actions git push
Note, if you are merging someone else’s work on a PR assigned to you,
you would run
git sync to ensure master is up-to-date locally, then
git merge origin/fetch-user-actions.
If you’re happy to delete the topic branch now, just run:
git branch -d fetch-user-actions git push origin --delete !$
That’s it! Everything’s been done via the command line. Of course mix this up with browser-based activity where it makes sense. But if you love the command line, having both options in your tool belt is pretty awesome.