Fork synchronization
Forks drift from upstream fast. This recipe uses bb repo view to discover the upstream clone URL and plain git for the fetch, rebase and push.
Prerequisites
Section titled “Prerequisites”- Your local clone is the fork, not the upstream.
originpoints at your fork.- The upstream is reachable as a separate remote (we’ll add it if missing).
- You have permission to push to your fork’s
main(or whichever branch you want to keep in sync).
Recipe: one-shot sync
Section titled “Recipe: one-shot sync”#!/bin/bash# sync-fork.sh - Keep a fork's main branch in sync with its upstream.set -euo pipefail
UPSTREAM_WORKSPACE="${UPSTREAM_WORKSPACE:?set UPSTREAM_WORKSPACE}"UPSTREAM_REPO="${UPSTREAM_REPO:?set UPSTREAM_REPO}"BRANCH="${BRANCH:-main}"
# 1. Look up the upstream clone URL via bb (HTTPS).# Pipe --json to external `jq -r`: the built-in --jq JSON-encodes its# output, so the URL would come back wrapped in literal double quotes.upstream_url=$(bb repo view -w "$UPSTREAM_WORKSPACE" -r "$UPSTREAM_REPO" --json \ | jq -r '.links.clone[] | select(.name == "https") | .href')
if [ -z "$upstream_url" ]; then echo "Could not resolve HTTPS clone URL for $UPSTREAM_WORKSPACE/$UPSTREAM_REPO" >&2 exit 1fi
# 2. Add the upstream remote if it isn't there.if ! git remote get-url upstream >/dev/null 2>&1; then echo "Adding upstream remote: $upstream_url" git remote add upstream "$upstream_url"else git remote set-url upstream "$upstream_url"fi
# 3. Fetch upstream and your fork.git fetch upstream "$BRANCH"git fetch origin "$BRANCH"
# 4. Switch to the branch and rebase onto upstream.git checkout "$BRANCH"git rebase "upstream/$BRANCH"
# 5. Push the rebased branch back to your fork.# Use --force-with-lease, NOT --force, so concurrent fork-side pushes aren't clobbered.git push --force-with-lease origin "$BRANCH"
echo "Fork '$BRANCH' synced with upstream $UPSTREAM_WORKSPACE/$UPSTREAM_REPO"UPSTREAM_WORKSPACE=acme \ UPSTREAM_REPO=widget \ BRANCH=main \ ./sync-fork.shRecipe: sync, then open a pull request for a feature branch
Section titled “Recipe: sync, then open a pull request for a feature branch”After syncing main, rebase your feature branch and open a pull request (PR) back to upstream.
bb pr create cannot do this. Its -s/--source and -d/--destination are both plain branch names resolved inside the -w/-r repository, so it has no way to name your fork as the source — pointing it at upstream either 404s or opens a same-repo PR in upstream. Use bb api to POST the cross-fork body yourself.
#!/bin/bashset -euo pipefail
UPSTREAM_WORKSPACE="${UPSTREAM_WORKSPACE:?set UPSTREAM_WORKSPACE}"UPSTREAM_REPO="${UPSTREAM_REPO:?set UPSTREAM_REPO}"FORK_WORKSPACE="${FORK_WORKSPACE:?set FORK_WORKSPACE}" # your workspaceFORK_REPO="${FORK_REPO:?set FORK_REPO}" # your fork's repo slugFEATURE_BRANCH="${FEATURE_BRANCH:?set FEATURE_BRANCH}"TITLE="${TITLE:-Update from $FEATURE_BRANCH}"DESTINATION="${DESTINATION:-main}"
# 1. Sync main, then rebase the feature branch onto fresh main.BRANCH=main ./sync-fork.sh
git checkout "$FEATURE_BRANCH"git rebase maingit push --force-with-lease origin "$FEATURE_BRANCH"
# 2. Open a PR in the upstream repository, sourced from the fork's branch.# Build the body with jq so a title containing quotes or backslashes# can't break the JSON.jq -n \ --arg title "$TITLE" \ --arg source "$FEATURE_BRANCH" \ --arg fork "$FORK_WORKSPACE/$FORK_REPO" \ --arg destination "$DESTINATION" \ '{ title: $title, source: { branch: { name: $source }, repository: { full_name: $fork } }, destination: { branch: { name: $destination } } }' \ | bb api POST "/repositories/$UPSTREAM_WORKSPACE/$UPSTREAM_REPO/pullrequests" --input -The path is fully interpolated from shell variables, so bb api has no {workspace}/{repo} placeholders left to substitute. Don’t mix the two forms in one path.
UPSTREAM_WORKSPACE=acme UPSTREAM_REPO=widget \ FORK_WORKSPACE=myuser FORK_REPO=widget \ FEATURE_BRANCH=feat/login \ TITLE="Add login button" \ ./sync-and-pr.shCross-fork PRs require that the upstream repository accepts forks as sources and that your token can read it. If Bitbucket rejects the request, its message is printed to stderr as ✗ … and the CLI exits 1. Re-run with --json to get the same error as one compact line on stderr:
{"name":"APIError","code":2003,"message":"You do not have access to create a pull request","statusCode":403}Related
Section titled “Related”- Repository Context — how
bbresolves workspace/repo from your git remote bb repo view— used here to fetch the upstream HTTPS clone URLbb pr create— same-repository PRs, where the source branch lives in the target repository- Raw API access —
bb api, used here for the cross-fork POST