2016-12-27 261 views
1

試圖瞭解爲什麼命令不是git merge --squash真的git rebase -squash?

git merge --squash mybranch 

不叫

git rebase -squash mybranch 

因爲它似乎它的操作更像是底墊比合並。我的理解是,它會在提交樹中搜索,直到它找到當前分支的一個通用基本提交併且mybranch。然後它將所有從該基節點到mybranch頭部的提交重新應用(重新綁定)到當前分支的頭部。但是,這樣做到索引/工作區,以便它可以作爲單個提交應用。完成後,沒有合併節點,因爲在正常合併中顯示合併的兩個分支。我有正確的理解嗎?

+0

'merge --squash'只是將分支中的所有提交合併爲一個。它不會修改歷史記錄。 –

+0

Andy所說的是在合併發生之前發生擠壓,所以從目標分支的角度來看,它仍然只是看到合併。 –

+0

我的觀點是在經常合併之後,圖形顯示合併的兩個分支合併成一個合併節點,但合併後--squash&commit圖形顯示兩個分支仍然是分開的,但是mybranch的變化被壓扁爲單個提交到當前分支上。對我來說,這看起來更像是一個已經被壓縮到一個單一提交中的rebase。但我所問的真正問題是,如果我的概念是什麼合併--squash確實是從根本上是正確的並且來自@torek的擴展答案,我得出結論,雖然還有更多複雜的細節尚待學習。 – JonN

回答

2

那麼,合併和重新組合基本上是不同的操作。合併 - 我指的是一個普通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)。現在,所有三個mergemerge --squashrebase會給你的東西結束,我們可能只是畫這樣一幅畫面:

...--o--*--o--o--A--B' <-- ??? 
     \   ? 
      B????????? <-- ??? 

內容的新提交B',即最終的快照,是在所有三種情況下都是一樣的。但是,對於git merge,新提交將在分支mainbr上,並且將指向提交AB,其中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所做的那樣。那麼爲什麼確實會自動停止