Understanding Diff view in Bitbucket Server
When creating a Pull Request, the Diff view in Bitbucket Server compares the changes between branches with the ultimate goal of providing an overview of which changes will be merged when a merge is performed.
In other words, the git diff starts at the common ancestor.
This also applies to the following use cases:
- Comparing branches
- Comparing tags
This is achieved by running the Git merge-base command.
Let's check the behaviour with a step-by-step example.
In this example there are three branches involved:
Step #1 - Create the branches
These three branches are created in the following order:
The following commands have been used for the creation of these branches:
# Define the source branch for the checkout git checkout master # target_branch: a branch with master as source git checkout -b target_branch git push origin target_branch # source_branch_A: a branch with target_branch as source git checkout -b source_branch_A git push origin source_branch_A # source_branch_B: a branch with target_branch as source git checkout target_branch # To reset the source branch to target_branch git checkout -b source_branch_B git push origin source_branch_B
The git log command returns the following
git log --oneline --abbrev-commit --all --graph --decorate * bfa489b (HEAD -> source_branch_B, origin/master, origin/HEAD, target_branch, source_branch_A, master) final
The branches will be presented as follows in the Bitbucket Server Commits page:
Step #2 - Change the target_branch
Apply a change to the target branch, commit it and push the change to the remote repository.
git checkout target_branch # change the file git add file1.txt git commit -m "change on target_branch" git push origin target_branch
When checking the Diffs tab in a pull request, no changes are shown between the two branches.
The screenshot shows
source_branch_A will present the same behaviour.
This is the same, empty, result of the following Git command:
git diff $(git merge-base source_branch_B target_branch) source_branch_B
Note that when comparing the two branches with 2 . instead of one, the change applied to the target_branch is shown:
git diff source_branch_B..target_branchdiff --git a/file1.txt b/file1.txt index 6168ae0..f99b4b2 100644 --- a/file1.txt +++ b/file1.txt @@ -1,3 +1,6 @@ +A change on the target_branch
Step #3 - Change the source_branch_A
Apply a change to the source_branch_A branch, commit it and push the change to the remote repository.
git checkout source_branch_A # change the file git add file1.txt git commit -m "change on source_branch_A" git push origin source_branch_A
When checking the Diffs tab in a pull request, the changes applied to the
source_branch_A are shown.
This is the same result of the following Git command:
git diff $(git merge-base source_branch_A target_branch) source_branch_A diff --git a/file1.txt b/file1.txt index 6168ae0..43bb5b6 100644 --- a/file1.txt +++ b/file1.txt @@ -25,3 +25,5 @@ master2 + +A change on source_branch_A
A merge commit hash is generated by Bitbucket by performing a Merge Base, when a pull request is created. This hash can be retrieved by checking the content of the $BITBUCKET_HOME/shared/data/repositories/<repository_id>/stash-refs/pull-requests/<pull_request_id>/merge.
When we create a Pull Request for a source branch to the target branch, the diff is as follows:
2019-03-18 14:14:03,250 DEBUG [http-nio-25160-exec-2] bitadmin @7FMTJ5x854x1106x0 15ddvyz 0:0:0:0:0:0:0:1 "GET /rest/api/latest/projects/~BITADMIN/repos/mine/pull-requests/1/changes HTTP/1.1" c.a.s.i.s.g.p.DefaultPullRequestRefHelper ~BITADMIN/mine:1@5: Resolving effective diff (7e955114c9c616fc8cb0c9b676fa08052c3b03bb -> d805b33ef5b64a874f082890225d4860e5279a5e)
Here, 7e955114c9c616fc8cb0c9b676fa08052c3b03bb is the new commit ready to be merged and d805b33ef5b64a874f082890225d4860e5279a5e is the latest commit on the target branch.
When the pull request is merged, we can see that content of $BITBUCKET_HOME/shared/data/repositories/<repository_id>/stash-refs/pull-requests/<pull_request_id>/merge was 7d86796957509036b0520a1d1881e4594235ee08
cat /bitbucket-home/atlassian-bitbucket-5.16.0/shared/data/repositories/2/stash-refs/pull-requests/1/merge 7d86796957509036b0520a1d1881e4594235ee08
So the effective diff that needs to be shown on the UI is calculated as the diff between d805b33ef5b64a874f082890225d4860e5279a5e and 7d86796957509036b0520a1d1881e4594235ee08 since 7d86796957509036b0520a1d1881e4594235ee08 is the automatic merge commit that was done by bitbucket.
This can be checked using git show command:
git show 7d86796957509036b0520a1d1881e4594235ee08 commit 7d86796957509036b0520a1d1881e4594235ee08 Merge: d805b33 7e95511 Author: bitadmin <email@example.com> Date: Mon Mar 18 12:33:50 2019 +1100 Automatic merge
Even when the Merge is done on the PR, the value in $BITBUCKET_HOME/shared/data/repositories/<repository_id>/stash-refs/pull-requests/<pull_request_id>/merge still stays the same.
When selecting an individual commit in the diff view, Bitbucket shows the diff between those two commits only.
In both cases, the following two git commands are run:
/usr/local/bin/git diff-tree -C -r --format=%H <hash_1> <hash_2> -- /usr/local/bin/git diff -C --color=never -U10 --dst-prefix=dst:// --src-prefix=src:// <hash_1> <hash_2> – <files>
When selecting the "All changes in this pull request" option, the <hash_1> used will be the one from the merge commit generated by Bitbucket when the pull request was created.
/usr/local/bin/git diff-tree -C -r --format=%H <hash_1> <hash_2> -- /usr/local/bin/git diff -C --color=never -U10 --dst-prefix=dst:// --src-prefix=src:// <merge commit hash> <hash_2> – <files>
Q: Does this apply only to a branch comparison or a diff in a pull request?
A: No, this also applies to a tag comparison. The following example shows that no Diff are displayed, even if a new change has been pushed to the target branch (as in Step #2 above):
Q: If I change the order of the compare and I see a difference, is it wrong?
A: No, that's expected and it depends on the Git changes applied.