My team recently started using BitBucket to collaborate on a project. We didn’t make the choice - it was made for us. Historically, we’ve used GitHub. However, since we were going to be using it, I figured we might as well make the most of it. On the surface, BitBucket seems like a good deal. It’s got pipelines and deployments built in. Being made by Atlassian, you’d think that it integrates better with JIRA than any other source control system. It’s also significantly cheaper than GitHub. All of this sounded great, until… Code Review.

But, before I start complaining, a bit of background about our workflow. We have an organization on BitBucket. That organization has a repository (let’s call it Repo). Each person on the team, forks Repo, creates a branch on their fork, does some work, and files a PR. After this, at least one other member of the team has to review the PR, and provide constructive feedback. The reviewer(s) and author may go back and forth a few times until they both agree the PR is good to go. When things are good to go, we merge the PR, and we’re done.

This workflow worked great for us when we were on GitHub. There’s one huge problem with BitBucket though - you can’t seem to be able to check out a PR locally! BitBucket’s UI for review is fine, but it is no substitute for being able to look at the code in your IDE, with a debugger on standby. On GitHub checking out a PR locally was trivial. I was really quite baffled when the same process didn’t work on BitBucket.

So I went looking to Google, looking for help. I came across this post that suggested that I had to make a minor change to the GitHub way, and things would work. Cool! Except… Nope. Didn’t work. Turns out, that only works on an older version of BitBucket Server (previously called Stash). Ugh.

So not knowing what to do, I filed a support ticket to Atlassian asking them if they had a solution to this problem. The support person responded (very politely) with a link to this page. Unfortunately… that doesn’t work either, for several reasons.

  1. They ask you to hover over a DOM element, wait for the browser to show the URL it points to, and use that for the next step. Wait what!? That sounds ridiculous!
  2. Turns out, the DOM element that article refers to doesn’t even point to a link anymore.
  3. Even if I could manage to predict the URL, the URL will be an https url, and we don’t use https to work with git, we prefer ssh.
  4. Even if you’re willing to use https, you’d still need to have read access to the forked repo (which unlike GitHub, BitBucket does not set up by default when someone forks your repo).

Wow. Just… Wow.

Then I figured, there must definitely be some way of downloading a patch file of the PR? GitHub has a way to do this. Turns out, nope.

The Atlassian support person later pointed me to this issue and said they’d be fixing this issue soon. But, I looked a little closer at the issue, and it’s been open since, wait for it… 2012. 6 years! Good lord!

This is when I started seriously considering wasting the absurd amount of time it’d take to get us off BitBucket, and back on to GitHub. Before I gave up hope though, I figured it was worth looking into the BitBucket API to see if there was some way to get this to work. Fortunately, that did not let me down. There’s an endpoint that allows you to get a PR as a patch.

I set about trying to get this to work, and quickly ran across the hell hole that is OAuth2. I was about to give up again, when I noticed this section way at the bottom of the page:

Basic auth Basic HTTP Authentication as per RFC-2617 (Digest not supported). Note that Basic Auth with username and password as credentials is only available on accounts that have 2-factor-auth / 2-step-verification disabled. If you use 2fa, you should authenticate using OAuth2 instead.

Cool! I wasn’t using 2fa anyway, so time to get this working. After a bit of finagling, I came up with this snippet which I stuck into my ~/.zshrc:

function co_bb_pr() {
    curl -u "<USERNAME>:<PASSWORD>" https://bitbucket.org/api/2.0/repositories/<ORG>/<REPO>/pullrequests/$1/patch -L -o $1.patch && git apply $1.patch
}

I can now run:

co_bb_pr 27

And have a PR 27 checked out locally.

Finally.

If you have a better way of doing this, please let me know! I’m @gopalkri.