Bitbucket Cloud - How to programmatically list merged pull requests from a source branch during branch comparison

Platform Notice: Cloud Only - This article only applies to Atlassian apps on the cloud platform.

Summary

When comparing branches, we can view the commits listed that are part of the source branch, not the destination branch.

Branch Compare Page View:

(Auto-migrated image: description temporarily unavailable)

Previously, the Bitbucket branch compare page had a "merged pull requests" tab, displaying a list of pull requests merged into the source branch.

(Auto-migrated image: description temporarily unavailable)

However, this tab has been deprecated, as noted in this Atlassian Community post. There are a couple of workarounds that could be used in place of the missing "merged pull requests" tab:

1. If deployments are configured on the repository: The Deployment card contains a separate tab for "Merged pull requests," allowing users to see the list of merged pull requests associated with the branch being deployed.

2. The Commit view page offers functionality to preview all pull requests associated with a given commit. By utilizing this functionality along with the list of commits from the Branch Compare page, a comprehensive list of pull requests associated with all commits between two branches can be constructed.

However, scenarios may arise where deployments are not configured in the repository, or the list of commits could be extensive (e.g., 30+ commits). Manually accessing each commit page to check associated pull requests can be a time-consuming process.

Solution

The List commits API with the include and exclude parameters, retrieves the commits that are reachable from the source branch but not reachable from the destination branch.

Example:

https://api.bitbucket.org/2.0/repositories/{workspaceID}/{reposlug}/commits/?include=development&exclude=master

Using include=development and exclude=master in the Bitbucket API call retrieves the commits that are reachable from the development branch but not reachable from the master branch.

The include and exclude parameters in the Bitbucket API are typically used for specifying commit ranges. They do not directly replicate the behavior of git diff A...B. However, you can use them to retrieve commits between two points in the commit history, similar to what git log COMMIT_A..COMMIT_B does.

Once the commits are listed, we can iterate through each commit and list pull requests containing that commit using the Commit Pull Requests API

Example:

https://api.bitbucket.org/2.0/repositories/{workspaceID}/{reposlug}/commit/{commit}/pullrequests

In summary, we list all the pull requests already part of the source branch using APIs, allowing us to filter merged pull requests with the same. Below is a sample Python script that automates fetching the commits using list commits API and listing pull requests associated with each diff commit using commoit pull requests API, export the final list of pull requests to a CSV file "report.csv".

Sample Python Script:

API Script

#!/usr/bin/env python3 """ Generate a CSV report of commits between two branches and their associated PRs. • Auth via Atlassian account email + Bitbucket API token (scope: read:repository, read:pullrequest). """ import warnings warnings.filterwarnings("ignore", category=UserWarning, module="urllib3") import csv from datetime import datetime import requests from requests.auth import HTTPBasicAuth # ------------------------------------------------------------------ # 1. CONFIGURATION – fill these in: # ------------------------------------------------------------------ email = "your.email@example.com" # Atlassian account email token = "xxxxxxxxxxxxxxxxxxxxxxxxx" # Bitbucket API token workspace = "my-workspace" # your workspace ID repository = "my-repo" # your repo slug source_branch = "development" destination_branch= "master" # ------------------------------------------------------------------ # 2. HELPER to safely dig into nested dicts # ------------------------------------------------------------------ def safe(obj, *keys, default=""): for k in keys: if not isinstance(obj, dict): return default obj = obj.get(k) if obj is None: return default return obj # ------------------------------------------------------------------ # 3. Fetch commits between two branches # ------------------------------------------------------------------ def fetch_commits_between_branches(auth): print(f"Fetching commits from '{source_branch}' excluding '{destination_branch}'…") url = f"https://api.bitbucket.org/2.0/repositories/{workspace}/{repository}/commits" params = { "fields": "values.hash,next", "pagelen": 100, "include": source_branch, "exclude": destination_branch, } commits = [] while url: resp = requests.get(url, auth=auth, params=params, timeout=30) resp.raise_for_status() data = resp.json() commits.extend(data.get("values", [])) url = data.get("next") print(f" → {len(commits)} commits fetched so far…") print("Completed commit fetch.\n") return commits # ------------------------------------------------------------------ # 4. Fetch PRs that include a given commit # ------------------------------------------------------------------ def fetch_pull_requests_for_commit(commit_hash, auth): print(f" Fetching PRs for commit {commit_hash}…") url = f"https://api.bitbucket.org/2.0/repositories/{workspace}/{repository}/commit/{commit_hash}/pullrequests" params = {"fields": "values.id,values.title,values.state,values.author.display_name,values.updated_on"} resp = requests.get(url, auth=auth, params=params, timeout=30) resp.raise_for_status() return resp.json().get("values", []) # ------------------------------------------------------------------ # 5. Main: iterate commits → PRs → build CSV # ------------------------------------------------------------------ def generate_csv_report(): auth = HTTPBasicAuth(email, token) commits = fetch_commits_between_branches(auth) rows = [] for commit in commits: h = safe(commit, "hash") prs = fetch_pull_requests_for_commit(h, auth) for pr in prs: rows.append([ h, pr.get("id", ""), pr.get("title", "").replace("\n", " "), pr.get("state", ""), safe(pr, "author", "display_name"), pr.get("updated_on", ""), ]) # Write CSV with open("report.csv", "w", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow(["Commit Hash","PR ID","PR Title","PR State","Author","Updated On"]) writer.writerows(rows) print("\nCSV report generated: report.csv") if __name__ == "__main__": generate_csv_report()

Sample CSV Output:

Commits

Pull Request

Title

State

Author

Updated On

26f6bff57d3b2d04cee46ab7ebcf0ee1dae4d00d

110

ABC TEST1

MERGED

Suhas

2024-06-06T13:20:22.788867+00:00

ee1dae57d3b204cee46ab7ebcf0e0ee1dae4d00

111

ABC TEST2

OPEN

Suhas

2024-06-06T13:20:22.788867+00:00

5711992332b3741189bb66bd36d3332b374118

112

ABC TEST3

MERGED

Suhas

2024-06-06T13:20:22.788867+00:00

The above CSV output contains all the pull requests (with statuses such as open, merged, and others) associated with the source branch commits. We can filter the merged pull requests if required. This solution also enables other integrations where this data needs to be fetched programmatically. The API helps facilitate this process.

Updated on September 26, 2025

Still need help?

The Atlassian Community is here for you.