Bitbucket pull request shows changes already in the destination branch
A Bitbucket pull request does not compare the source branch with the destination as it is now. It compares the source with the merge base, the last commit the two branches share (git's three-dot diff). Changes that reached the destination some other way, most often through a squash merge, are not in that shared history, so they show again. Atlassian calls this expected behaviour, in one article for Cloud and one for Data Center. Merging still changes only what is new. Below: how to see which files are really new, and how to make the pull request show only them.
What Bitbucket compares
- Bitbucket Cloud uses what Atlassian's Cloud article calls the "topic diff (2-way three-dot diff)": from the merge base to the head of the source branch. In the REST API, it is the diff or diffstat with
topic=true. - Bitbucket Data Center 7.0 and later shows the commits between the common ancestor and the tip of the source branch, the same three-dot diff (Atlassian's Data Center article).
To get the pull request's list of files on your machine:
git fetch
git diff --stat origin/main...origin/feature
And to see what merging would really change (git 2.38 or later), let git make the merge without touching your branches and compare it with the destination:
git diff --stat origin/main $(git merge-tree --write-tree origin/main origin/feature | head -1)
If the first command lists more files than the second, the extra ones are already in the destination.
A branch that was squash merged before
This is the case in Atlassian's Cloud article. A branch that stays open, such as qa or develop, is squash merged into main. A squash merge adds one new commit to main and does not record the branch's commits as merged, so the merge base stays where it was. The next pull request from the same branch shows the old changes again. In our test on November 2, five files were squash merged and one more was committed: the three-dot diff listed 6 files, the real merge 1.
To fix the branch once, merge the destination into it and push:
git switch qa
git merge origin/main
git push
The destination's newest commit then becomes the merge base, and the pull request shows only the new commit (6 files became 1 in the same test). If some of the squashed files changed again on the branch after the squash merge, this merge stops with a conflict on them (in our test, CONFLICT (add/add)). Keep the branch's version of those files: during this merge, git checkout --ours <file> takes the branch's side. Then git add them and git commit.
For good, do not squash merge a branch you keep using. Merge such branches with a merge commit, and keep squash merges for short-lived branches that are closed afterwards (Bitbucket merge strategies).
A branch built on a branch that was squash merged
feature-b was started from feature-a. feature-a was squash merged into main, and now the pull request for feature-b shows feature-a's changes too. Changing its destination to main does not help, because the merge base is still the old one. Move only feature-b's own commits onto main:
git switch feature-b
git rebase --onto origin/main {last commit of feature-a} feature-b
git push --force-with-lease
The last commit of feature-a is the newest one on the merged pull request's Commits tab. In our test, the pull request's diff went from 2 files to 1. A rebase rewrites the branch, so the push has to be forced; if the branch's permissions forbid rewriting history, Bitbucket refuses it ("pre-receive hook declined").
Parallel release branches
When two long-lived branches are merged into each other more than once, for example two release branches each merged into main and into another branch, they can have more than one merge base. Git picks one of them, and changes that are already in the destination can show. Atlassian's Data Center article walks through this and says it is not a Bitbucket fault when your own git diff shows the same.
git merge-base --all origin/main origin/release
More than one line means this case. Atlassian points to a workflow with one release branch at a time. Merging the destination into the source, as above, also leaves a single merge base.
Bitbucket pull requests in IntelliJ IDEA
Pull Request Inbox for Bitbucket, a plugin by Lesstep for JetBrains IDEs 2024.1 or later, shows a pull request's files in the IDE's diff viewer, compared from the merge base like Bitbucket's own page, on Cloud and Data Center. It can check out the pull request's branch (Checkout), where the commands above run, and after a push it shows what changed since your last review. Reading is free; creating, approving and merging pull requests are Pro (US$1.50 a month, with a 30-day trial).
Get it on JetBrains Marketplace
Bitbucket is a trademark of Atlassian; IntelliJ IDEA is a trademark of JetBrains s.r.o. This page is not affiliated with or endorsed by Atlassian or JetBrains.
More: Bitbucket merge strategies · What changed since your last review · Change a pull request's destination branch · 日本語