This little bash snippet will let you open a GitHub or GitLab pull request from the command line on most Unix-like systems (OSX, Ubuntu, etc.), without using any magic libraries, ZSH tricks or other dependencies.
Here's how it looks in action OSX:
And Ubuntu:
The script is available as the gpr.sh gist. You can also find it in my dotfiles, in the git.sh file.
The Script
Here's the script in its entirety:
GREEN='\033[0;32m'
RESET='\033[0m'
gpr() {
branch=$(git symbolic-ref -q HEAD)
branch=${branch
branch=${branch:-HEAD}
echo "Opening pull request for ${GREEN}${branch}${RESET}..."
push_output=`git push origin -u ${branch} 2>&1`
echo ""
echo ${push_output}
link=$(echo ${push_output} | grep -o 'http.*' | sed -e 's/[[:space:]]*$//')
if [ ${link} ]; then
echo ""
echo "Opening: ${GREEN}${link}${RESET}..."
python -mwebbrowser ${link}
fi
}
How It Works
Blow-by-blow, let's take a look.
GREEN='\033[0;32m'
RESET='\033[0m'
To make colouring console output easier, we create strings with the escape code required to set the 'green
' colour, and reset the text colour.
gpr() {
branch=$(git symbolic-ref -q HEAD)
branch=${branch
branch=${branch:-HEAD}
Now we define the gpr
(Git Pull Request) function. We'll need to push the current branch, so we need to get the current branch name. There's plenty of discussion on how this works on Stack Overflow: How to get the current branch name in Git. Essentially, we just get the symbolic name for the head of our current branch, which will be something like this:
refs/heads/my-new-branch
We then use Bash substring removal to rip out the ref/heads/ part. If we have no branch (for example, we are detached), we just use HEAD
as the branch name.
Next, we have this:
echo "Opening pull request for ${GREEN}${branch}${RESET}..."
push_output=`git push origin -u ${branch} 2>&1`
echo ""
echo ${push_output}
We've previously defined some string
s which include the escape codes to colour terminal output. Now we just show the user the branch we're going to push, push it and then store all of the output in the push_output
variable.
The 2>&1
idiom is a common one. This simply makes sure we put all stderr
output (which is always file descriptor 2) into stdout
(which is always file descriptor 1). This means whether the program writes output to stdout
or stderr
, we capture it. There's a nice write-up on this in the blog post 'Understanding Shell Script's idiom: 2>&1
'.
The output from Git push will be dependent on the Git server being used. For GitHub, it'll look like this:
remote:
remote: Create a pull request for 'feat/doc-cleanup' on GitHub by visiting:
remote: https://github.com/dwmkerr/dotfiles/pull/new/feat/doc-cleanup
remote:
To github.com:dwmkerr/dotfiles
* [new branch] feat/doc-cleanup -> feat/doc-cleanup
Branch feat/doc-cleanup set up to track remote branch feat/doc-cleanup from origin.
Now all we want to do is see if there is any text which starts with http
and if there is, then open it. Here's how we do that:
link=$(echo ${push_output} | grep -o 'http.*' | sed -e 's/[[:space:]]*$//')
if [ ${link} ]; then
echo ""
echo "Opening: ${GREEN}${link}${RESET}..."
python -mwebbrowser ${link}
fi
This uses grep
to rip out everything from http
onwards, and the sed
to remove any trailing whitespace. If we have found a link, we use python
to open it (which is a fairly safe cross-platform solution).
That's it! When you have a branch ready which you want to push and create a pull request from, just run:
gpr
And the branch will be pushed to origin
, and if there is a Pull Request webpage, it'll be opened.
Prior Art
My colleague Tobias recently shared a nice trick we worked out to open a GitLab merge request - which also now works for GitHub:
I wanted to be able to use the same trick in Ubuntu and other Linux distros, but realised it relied on oh-my-zsh and assumed OSX with Chrome as the browser, so tweaked it to the above. Thanks Tobi!