Bitbucket Compare 與 git diff 的關係:一個 squash merge 引發的疑問
為什麼會遇到這個問題?
同事在他的 repo 裡,從 develop 開了一個 PR,要合併到 test branch。合併完成後,理論上兩個分支應該同步,結果在 Bitbucket Compare 一看,develop 還領先 test 好幾個 commit。這時候我們都愣住了:不是已經 merge 了嗎?怎麼還有差異?
開始調查
第一步,我去查 Bitbucket Compare 的 Compare 功能到底怎麼判斷差異。結果發現它底層用的是:
1 | |
而不是:
1 | |
這兩個符號差一個點,但語意不同,建議在文章中統一用法說明如下:
- A..B(兩個點):比較 A 與 B 的 HEAD 差異(等同
git diff A B)。 - A…B(三個點):比較從共同祖先(merge base)到 B 的差異(等同
git diff $(git merge-base A B) B;也就是從分歧點開始的差異)。
用下面的圖示來解釋:
1 | |
git diff develop..test比較的是 commit E(test HEAD)和 C(develop HEAD)之間的差異。git diff develop...test比較的是從共同祖先(此例為 B)到 E 的差異(等同git diff B E)。
因此 Bitbucket Compare 顯示的差異,其實是基於「分歧點(merge base)」,而非單純比較兩個分支的 HEAD。
關鍵線索
我注意到這個 PR 沒有在 test branch 產生 merge commit。再去看 Bitbucket 的 merge strategy 設定,發現有人啟用了 squash merge,並設為預設。
這就解釋了所有問題:squash merge 不會保留原本 develop branch 的 commit 歷史。它會把 PR 的變更壓縮成一個新的 commit,直接新增到 test branch。因此 develop 上的那些原始 commit 並未被帶到 test,分歧點依然存在(在 test 上看到的是新的單一 commit,而不是原來的一連串 commit)。
用命令驗證:
1 | |
看到的結果會與 Bitbucket Compare 的結果一致。
結論
這不是 Bug,而是 squash merge 的特性。建議使用時機與注意事項:
- 若希望 commit 歷史乾淨、把多個小 commit 合併成單一變更,可在個人或短期 feature 分支使用 squash merge。
- 若希望保留完整 commit 歷史、或希望 Bitbucket Compare 顯示兩個分支的歷史一致,請使用帶 merge commit 的合併策略(不要 squash)。
Reference
Bitbucket Compare 與 git diff 的關係:一個 squash merge 引發的疑問
https://my-blog.pages.dev/2025-12-07/git-diff-and-squash-merge/