I want to be able to type git open-pr-github
and have my browser open to the GitHub URL to create a Pull Request (PR) for my current branch on the current project I’m working on. Here is how I built this to run on my computer running macOS.
Git Alias
This alias can be added to your ~/.gitconfig
file. The fastest way to add this is to run the following from the command line.
git config --global alias.open-pr-github '!f() { open "$(git ls-remote --get-url $(git config --get branch.$(git rev-parse --abbrev-ref HEAD).remote) | sed '"'"'s|git@github.com:\(.*\)$|https://github.com/\1|'"'"' | sed '"'"'s|\.git$||'"'"')/compare/$(git config --get branch.$(git rev-parse --abbrev-ref HEAD).merge | cut -d '/' -f 3-)?expand=1"; }; f'
Git Alias in Git Config
Instead of running the command above, you can manually add the following to your ~/.gitconfig
file.
[alias]
open-pr-github = "!f() { \
open \"$(git ls-remote --get-url $(git config --get branch.$(git rev-parse --abbrev-ref HEAD).remote) \
| sed 's|git@github.com:\\(.*\\)$|https://github.com/\\1|' \
| sed 's|\\.git$||'; \
)/compare/$(\
git config --get branch.$(git rev-parse --abbrev-ref HEAD).merge | cut -d '/' -f 3- \
)?expand=1\"; \
}; f"
The resulting alias behaves the same, the only difference is this manually added version is broken up over multiple lines for readability.
Pieces of the Puzzle
Get Current Local Branch Name
# Get current branch name
# e.g. "feat/add-open-github-pr"
git rev-parse --abbrev-ref HEAD
Get Remote Name for Current Branch
# Get remote for the current branch (e.g. "origin")
# Note: this will return nothing if the current branch is not tracking a remote branch.
# See https://git-scm.com/docs/git-config#Documentation/git-config.txt-branchltnamegtremote
git config --get branch.$(git rev-parse --abbrev-ref HEAD).remote
Get Remote Branch Name Being Tracked
# Get branch name on remote local branch is tracking
# e.g. "refs/heads/feat/add-open-github-pr"
# See https://git-scm.com/docs/git-config#Documentation/git-config.txt-branchltnamegtmerge
git config --get branch.$(git rev-parse --abbrev-ref HEAD).merge
Get Trim “refs/heads”
echo "refs/heads/feat/add-open-github-pr" | cut -d '/' -f 3-
Get Trimmed Remote Branch Name Being Tracked
# Get trimmed branch name on remote local branch is tracking
# i.e. remove the leading "refs/heads"
# e.g. "feat/add-open-github-pr"
git config --get branch.$(git rev-parse --abbrev-ref HEAD).merge | cut -d '/' -f 3-
Note on all of my projects the trimmed remote branch name being tracked is the same as your local branch name (e.g. feat/add-open-github-pr
), however you can track a remote branch with a different name (though this just seems like asking for trouble) so we jump through these extra hoops to ensure we have the correct remote branch name
Remote Remote URL
# Get the URL for the remote "origin"
# e.g. "git@github.com:ironcodestudio/ironcode-git-enhancements.git" (SSH)
# e.g. "https://github.com/ironcodestudio/ironcode-git-enhancements.git" (HTTPS)
git ls-remote --get-url origin
Note: these remote URLs come in two different formats, SSH and HTTPS
Get Remote URL Associated with the Current Branch
# Get the URL for the remote associated with the current branch
git ls-remote --get-url $(git config --get branch.$(git rev-parse --abbrev-ref HEAD).remote)
Normalize SSH style URL to HTTPS Style
Since the remote URL can be in two different formats (SSH or HTTPS), we apply a regular expression to normalize the URL to HTTPS style.
echo "git@github.com:ironcodestudio/ironcode-git-enhancements.git" | sed 's|^.*github.com[:/]\(.*\)$|https://\1|'
echo "https://github.com/ironcodestudio/ironcode-git-enhancements.git" | sed 's|^.*github.com[:/]\(.*\)$|https://\1|'
# both result in the same
https://github.com/ironcodestudio/ironcode-git-enhancements.git
Normalize Current Remote URL
# Normalize SSH style URL to HTTPS style
# (if the URL is already HTTPS style, make no changes)
git ls-remote --get-url $(git config --get branch.$(git rev-parse --abbrev-ref HEAD).remote) \
| sed 's|git@github.com:\(.*\)$|https://github.com/\1|'
Transform an HTTPS Style Remote URL to Browser URL
# Transform HTTPS URL to browser URL
# Remove .git from end of HTTPS style URL
echo "https://github.com/ironcodestudio/ironcode-git-enhancements.git" | sed 's|\.git$||'
Transform Remote URL (SSH or HTTPS) to Browser URL
echo "git@github.com:ironcodestudio/ironcode-git-enhancements.git" | sed 's|git@github.com:\(.*\)$|https://github.com/\1|'
echo "https://github.com/ironcodestudio/ironcode-git-enhancements.git" | sed 's|git@github.com:\(.*\)$|https://github.com/\1|'
# Both output the same
# https://github.com/ironcodestudio/ironcode-git-enhancements.git
Put the Pieces Together to Output the Browser URL
echo "$(git ls-remote --get-url $(git config --get branch.$(git rev-parse --abbrev-ref HEAD).remote) \
| sed 's|git@github.com:\(.*\)$|https://github.com/\1|' \
| sed 's|\.git$||')/compare/$(git config --get branch.$(git rev-parse --abbrev-ref HEAD).merge | cut -d '/' -f 3-)?expand=1"
Open Instead of Echo
open "$(git ls-remote --get-url $(git config --get branch.$(git rev-parse --abbrev-ref HEAD).remote) \
| sed 's|git@github.com:\(.*\)$|https://github.com/\1|' \
| sed 's|\.git$||')/compare/$(git config --get branch.$(git rev-parse --abbrev-ref HEAD).merge | cut -d '/' -f 3-)?expand=1"
Inspired by
Inspired by this Gist by rpavolovs and the git-open project by Paul Irish.
How this Differs
The solution here differs from these other solutions in that this solution has all of the code contained within the ~/.gitconfig
file.
Update to Accept Target Branch
This command has been updated to accept a <target>
branch.
git open-pr-github my-branch
will now open a PR into my-branch
instead of into the repo’s default branch.
See GitHub PR: Add optional target branch argument to “open-pr-github” alias.
Operating Systems other than macOS
This solution works on my Apple macOS machine.
If you are running on a Linux machine, you can try changing open
to xdg-open
in the script.
If you are on Windows, you can trying changing open
to start
.
I’ve not tested these so if you do, I’d love to hear the success or failure in the comments.
This is one of those examples of how far we’ll go to avoid a GUI lol. (Kidding!) I totally love this. I only use git on the cli and I’m definitely going to steal this.
+ 100 points for using sed.
Ha ha, yeah
sed
is definitely one of those tools I’m still learning but I see a ton of potential in it.Oh, and you used an animated gif! Aubrey is having a very good influence on you.
Note: I’ve updated this blog post to use
git rev-parse --abbrev-ref HEAD
instead ofgit branch --show-current
because--show-current
is only supported in Git version2.22.0
(released 2019-06-07.) or newer.git open-pr-github subsint
f() { open “$(git ls-remote –get-url $(git config –get branch.$(git rev-parse –abbrev-ref HEAD).remote) | sed ‘s|git@github.com:\(.*\)$|https://github.com/\1|’ | sed ‘s|\.git$||’)/compare/$(git config –get branch.$(git rev-parse –abbrev-ref HEAD).merge | cut -d / -f 3-)?expand=1”; }; f: 1: open: not found
I get this error while opening my PR
Hi Prateek,
The
open: not found
makes me guess you’re not running on a Mac, which in turn makes me realize I had not called out that I am on a Mac. I’ve added that information and included a new section, Operating Systems other than macOS. Hopefully, that information will be helpful.Thanks for brining this to my attention.