From 7b347954bf9aa858a5e2ff31f0bdd977c567ef98 Mon Sep 17 00:00:00 2001 From: Max Kostovetski Date: Thu, 3 Sep 2026 18:55:03 -0700 Subject: [PATCH] Fix Bitbucket branch and commit URLs Bitbucket Cloud needs different paths than the shared defaults: - Commits live at /commits/, not /commit/ (the singular 404s). - /src/ 404s when the branch name contains a slash (e.g. release/9.12.x), because Bitbucket reads the first path segment as the ref. Browse via /src/HEAD/?at= with the slash percent-encoded; plain refs keep the simpler /src/. Both changes are scoped to bitbucket.org, so GitHub, CodeCommit, and Bitbucket Server are unaffected. Adds bats coverage for the commit URL and the slash-branch source view. --- git-open | 15 +++++++++++++-- test/git-open.bats | 12 ++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/git-open b/git-open index a367db6..8a4f8ee 100755 --- a/git-open +++ b/git-open @@ -199,7 +199,14 @@ else fi if [[ "$domain" == 'bitbucket.org' ]]; then - providerBranchRef="/src/$remote_ref" + # Bitbucket Cloud 404s on /src/ when the branch name contains a slash: it reads the + # first path segment as the ref. Browse via HEAD and pass the real branch through ?at= + # (slashes percent-encoded); plain refs keep the simpler /src/. + if [[ "$remote_ref" == */* && -n "$branch" ]]; then + providerBranchRef="/src/HEAD/?at=${remote_ref//\//%2F}" + else + providerBranchRef="/src/$remote_ref" + fi elif [[ "${#pathargs[@]}" -ge 3 && ${pathargs[${#pathargs[@]} - 3]} == 'scm' ]]; then # Bitbucket server always has /scm/ as the third to last segment in the url path, e.g. /scm/ppp/test-repo.git # Anything before the 'scm' is part of the server's root context @@ -269,7 +276,11 @@ openurl="$protocol://$domain/$urlpath" if (( is_commit )); then sha=$(git rev-parse HEAD) - openurl="$openurl/commit/$sha" + if [[ "$domain" == 'bitbucket.org' ]]; then + openurl="$openurl/commits/$sha" + else + openurl="$openurl/commit/$sha" + fi elif [[ $remote_ref != "master" || "$file" ]]; then # simplify URL for master openurl="$openurl$providerBranchRef" diff --git a/test/git-open.bats b/test/git-open.bats index e891be5..e7e465a 100755 --- a/test/git-open.bats +++ b/test/git-open.bats @@ -385,6 +385,13 @@ setup() { assert_output "https://bitbucket.org/paulirish/crbug-extension/src/mytag" } +@test "bitbucket: commit" { + git remote set-url origin "git@bitbucket.org:paulirish/crbug-extension.git" + sha=$(git rev-parse HEAD) + run ../git-open "--commit" + assert_output "https://bitbucket.org/paulirish/crbug-extension/commits/${sha}" +} + @test "bitbucket: non-origin remote" { # https://github.com/paulirish/git-open/pull/4 git remote add bbclone "git@bitbucket.org:rwhitbeck/git-open.git" @@ -401,13 +408,14 @@ setup() { assert_output "https://bitbucket.org/kisom/consbri/src/devel" } -@test "bitbucket: open source view with a slash/branch" { +@test "bitbucket: slash branch source view via ?at=" { # https://github.com/paulirish/git-open/pull/26 # see https://github.com/paulirish/git-open/issues/80 for feat/branchname issues + # /src/bugfix/conftest_fix 404s (Bitbucket reads 'bugfix' as the ref), so browse HEAD?at= git remote set-url origin "https://bitbucket.org/guyzmo/git-repo.git" git checkout -B "bugfix/conftest_fix" run ../git-open - assert_output "https://bitbucket.org/guyzmo/git-repo/src/bugfix/conftest_fix" + assert_output "https://bitbucket.org/guyzmo/git-repo/src/HEAD/?at=bugfix%2Fconftest_fix" } @test "bitbucket: ssh:// clone urls" {