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 products 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:

1 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:

1 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

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 import requests from requests.auth import HTTPBasicAuth import csv import warnings # Suppress urllib3 SSL warnings warnings.filterwarnings("ignore", category=UserWarning, module='urllib3') def fetch_commits_between_branches(username, password, workspace, repository, source_branch, destination_branch): print(f"Fetching commits between {source_branch} and {destination_branch}...") base_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 } auth = HTTPBasicAuth(username, password) commits = [] next_page_url = base_url while next_page_url is not None: response = requests.get(next_page_url, auth=auth, params=params) response.raise_for_status() page_json = response.json() commits.extend(page_json['values']) next_page_url = page_json.get('next') print(f"Fetched {len(commits)} commits so far...") print("Completed fetch.") return commits def fetch_pull_requests_details(username, password, workspace, repository, pull_request_id): url = f"https://api.bitbucket.org/2.0/repositories/{workspace}/{repository}/pullrequests/{pull_request_id}" params = {'fields': 'state,author.display_name,updated_on'} auth = HTTPBasicAuth(username, password) print(f"Fetching details for pull request {pull_request_id}...") response = requests.get(url, auth=auth, params=params) response.raise_for_status() return response.json() def fetch_pull_requests_for_commit(username, password, workspace, repository, commit_hash): url = f"https://api.bitbucket.org/2.0/repositories/{workspace}/{repository}/commit/{commit_hash}/pullrequests" params = {'fields': 'values.id,next,values.links.self.href,values.title'} auth = HTTPBasicAuth(username, password) print(f"Fetching pull requests for commit {commit_hash}...") response = requests.get(url, auth=auth, params=params) response.raise_for_status() page_json = response.json() return page_json['values'] def fetch_pull_request_state(username, password, workspace, repository, pull_request_id): url = f"https://api.bitbucket.org/2.0/repositories/{workspace}/{repository}/pullrequests/{pull_request_id}" params = {'fields': 'state'} auth = HTTPBasicAuth(username, password) print(f"Fetching state for pull request {pull_request_id}...") response = requests.get(url, auth=auth, params=params) response.raise_for_status() return response.json()['state'] def generate_csv_report(username, password, workspace, repository, source_branch, destination_branch): commits = fetch_commits_between_branches(username, password, workspace, repository, source_branch, destination_branch) commit_hashes = [commit['hash'] for commit in commits] csv_rows = [] for commit_hash in commit_hashes: pull_requests = fetch_pull_requests_for_commit(username, password, workspace, repository, commit_hash) for pr in pull_requests: pr_id = pr['id'] title = pr['title'] commit_state = fetch_pull_request_state(username, password, workspace, repository, pr_id) # Fetch pull request details to get author_display_name and updated_on pr_details = fetch_pull_requests_details(username, password, workspace, repository, pr_id) author_display_name = pr_details['author']['display_name'] updated_on = pr_details['updated_on'] csv_rows.append([commit_hash, pr_id, title, commit_state, author_display_name, updated_on]) with open('report.csv', 'w', newline='') as csvfile: csv_writer = csv.writer(csvfile) csv_writer.writerow(['Commits', 'Pull Request', 'Title', 'State', 'Author', 'Updated On']) csv_writer.writerows(csv_rows) print("CSV report generated successfully.") # API Authentication username = '' # use your bitbucket username password = '' # use your app password workspace = '' # eg: 'my-workspace' repository = '' # eg: 'test' source_branch = '' # eg: 'development' destination_branch = '' # eg: 'master' generate_csv_report(username, password, workspace, repository, source_branch, destination_branch)  

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 April 7, 2025

Still need help?

The Atlassian Community is here for you.