那麼,合併和重新組合基本上是不同的操作。合併 - 我指的是一個普通git merge
,創建一個新的合併提交,確實通過提交圖形的最近的共同承諾找回來:
...--o--*--o--o--A <-- mainbr
\
B--C--D--E <-- sidebr
在這裏,最近的公共承諾是*
。合併過程然後將比較(如在git diff
中)提交*
與提交A
以找出「我們做了什麼」,並且比較*
針對提交E
來找出「他們做了什麼」。然後它使一個新的單一合併提交,有兩個家長:
...--o--*--o--o--A---M <-- mainbr
\ /
B--C--D--E <-- sidebr
其連接兩個歷史,並結合「我們所做的事情」和「他們做了什麼」,所以版本比較*
VS M
給「之一每個變化「。
請注意,您在這裏沒有選擇合併基礎:Git計算出來,就是這樣。
另一方面,可以告訴Rebase分別承諾複製以及複製它們的位置。確實,默認情況下,它再次找到提交*
- 但它然後複製原始提交,一個接一個,使用git cherry-pick
或等效;最後,它將分支標籤移動到指向上次複製的提交。
...--o--*--o--o--A <-- mainbr
\ \
\ B'-C'-D'-E' <-- sidebr
\
B--C--D--E
提交的原始鏈(B-C-D-E
,在這種情況下)還是在儲存庫中,並且仍然容易找到:它們可以通過散列ID中找到,並且在引用日誌爲sidebr
,並且如果任何其他分支或標籤名稱使它們可達,它們仍然可以通過該名稱到達。
做什麼git merge --squash
是隻稍微修改合併過程:而不是使合併提交M
,Git的經過合併機械像往常一樣,版本比較合併基礎,你不要選擇,對當前提交和其他提交,並將索引和工作樹中的更改組合在一起。它當時沒有明顯的理由 -stops,讓你運行git commit
提交的結果,當你這樣做,這是一個普通的非合併提交,使整個圖形的片段看起來像這樣:
...--o--*--o--o--A--F <-- mainbr
\
B--C--D--E <-- sidebr
現在,內容提交F
-the 快照樹從產生的合併,相同提交M
,當我們做一個真正的合併的內容,和這裏是真正的踢球者,這是也當我們進行rebase時,與承諾E'
的內容相同。
此外,假設在側分支sidebr
上只有一個提交(B
)。現在,所有三個merge
,merge --squash
和rebase
會給你的東西結束,我們可能只是畫這樣一幅畫面:
...--o--*--o--o--A--B' <-- ???
\ ?
B????????? <-- ???
和內容的新提交B'
,即最終的快照,是在所有三種情況下都是一樣的。但是,對於git merge
,新提交將在分支mainbr
上,並且將指向提交A
和B
,其中sidebr
指向B
;對於git merge --squash
,新的提交將在mainbr
上,並將僅指向A
;併爲git rebase
,新的承諾將在sidebr
,什麼也沒有明顯的指向B
可言的,我們應該以此爲借鑑:
...--o--*--o--o--A <-- mainbr
\ \
B B' <-- sidebr
因爲mainbr
將繼續指向提交A
。
最後,這看起來更像是一個合併,而不是像一個rebase那樣。 (不過,我會更開心,如果它不叫「南瓜合併」的說法。)
由Git的發現*
的方法有所不同:它實際上不是一個單一的承諾,而只是一個(通常)非常大的一組提交的最後一個提交,即所有可從<upstream>
參數到git rebase
的參數。 (令人困惑的是,合併的基礎也可以是一組提交的,但它是一個集受到很大的限制。最好不要潛入圖論呢。:-))
如果我們想它要停止,我們可以使用--no-commit
,就像我們爲常規非壁球git merge
所做的那樣。那麼爲什麼確實會自動停止?
'merge --squash'只是將分支中的所有提交合併爲一個。它不會修改歷史記錄。 –
Andy所說的是在合併發生之前發生擠壓,所以從目標分支的角度來看,它仍然只是看到合併。 –
我的觀點是在經常合併之後,圖形顯示合併的兩個分支合併成一個合併節點,但合併後--squash&commit圖形顯示兩個分支仍然是分開的,但是mybranch的變化被壓扁爲單個提交到當前分支上。對我來說,這看起來更像是一個已經被壓縮到一個單一提交中的rebase。但我所問的真正問題是,如果我的概念是什麼合併--squash確實是從根本上是正確的並且來自@torek的擴展答案,我得出結論,雖然還有更多複雜的細節尚待學習。 – JonN