2017-10-16 77 views
1

簡化,這是發生在我們身上:的Git默默合併爲更新應該是什麼衝突

  • 開始與這個文件有關master

    class SomeClass { 
        ... 
    } 
    
  • 創建分支featureA關`主。

  • featureA,更改文件:

    class SomeClass { 
        ... 
    } 
    
    extension SomeClass { 
        // implement feature A 
    } 
    
  • 創建分支featureB關`主。
  • featureB,更改文件:

    class SomeClass { 
        ... 
    } 
    
    class OtherClass { 
        // implement feature B 
    } 
    
  • 合併featureBmaster
  • featureA合併爲master

我們預計是:

class SomeClass { 
    ... 
} 

extension SomeClass { 
    // implement feature A 
} 

class OtherClass { 
    // implement feature B 
} 

或兩個以相反的順序添加,這是公平的。
實際上,Git應該可能會報告一個衝突:它沒有關於語義的知識,並且兩個「同時」更改無法調和。

我們得到是:

class SomeClass { 
    ... 
} 

class OtherClass { 
    // implement feature B 
} 

而不會發生衝突。也就是說,後面的提交(在另一個提交之前合併)默默地勝出。

這可以預防嗎?怎麼樣?

注意:如果我用上述步驟在一個乾淨的回購庫中嘗試此操作,則會在最後一步中遇到合併衝突。所以,無論這個問題是根植於我們在回購的其他方面。暗示讚賞,我不明白什麼可能會影響事情。或者,問題是diff算法被更復雜的代碼絆住了;在生產Swift代碼中,我們在一邊有兩個擴展,另一邊有嵌套類型的枚舉。

+0

是否使用過任何[合併策略](https://git-scm.com/docs/merge-strategies)? –

+0

@MarcinArmatys據我所知,只有默認的'git merge'已被使用。 – Raphael

回答

1

一些交叉的檢測與同試圖合併:

  • 在Ubuntu上使用Git 2.7.4和MELD 3.14.2,我看到git mergegit merge -s patience衝突。
  • 在Mac上,使用Git 2.11.0和Meld 3.16.0,我看到沒有與任一合併命令發生衝突。

    相反,有

    ==== BASE ==== 
    } 
    ==== BASE ==== 
    

    在文件的結尾,所以我認爲MELD不能解析DIFF正確這裏。

  • 在同一臺Mac和同一合併期間,AppCode 2017.3中的差異查看器顯示衝突。

似乎該版本的Meld在解析某些差異時遇到了麻煩。它沒有向我顯示衝突,所以在將它標記爲已解決之前,我沒有正確解決它。

注意:重現這顯然需要更多的「匹配」線;我的問題中的一個小例子並沒有這樣做。

0

正如你所說,當你試圖單獨重現它時,這會正確地產生衝突。

我最好在這一點猜測是你的分支之一的developper合併其他developper分支到自己,並通過刪除第二類定義解決衝突。

+0

不,沒有任何分支合併到另一個分支中。 – Raphael

1

最主要的錯誤合併的情況下,你能證明不是人爲錯誤是Git的合併使用Gi​​t的diff文件作爲輸入來考慮。如果diff文件上的瑣碎物品,如關閉括號線碰巧有正確的縮進同步,混帳可以把合併的結果是很好的縮進的地方,因此編譯,但在語義上是不適合,因此不功能

如果你說服Git不要在瑣事上同步,它更可能檢測實際衝突。您可以通過更改合併時使用的差異算法來實現此目的。您可以嘗試選擇patiencehistogram算法,使用-X patience-X histogram。有關細節的(簡短的)討論,請參閱第3章(第65頁)的結尾部分,我週末的進度不太大,book

+0

謝謝,我不知道有不同的差異算法可供選擇。不幸的是,他們中沒有一個似乎能夠正確識別差異。而且,說實話,我不知道一個基於行的diff *可以如何*。我不確定'git merge'是如何從差異(顯示,差異)到決定什麼是編輯以及什麼是衝突。 – Raphael

+0

在內部,由於Git具有文件的合併基礎版本和文件的兩個分支頂端版本,因此它只需要注意每個diff的行跨度範圍。調用雙方L(左/本地)和R(右/遠程)。假設我們通過起始行號對聯合編輯的差異進行排序。 「當前」更改(從L或R)跨越基本文件的某個行範圍[K..K + N)。如果「下一個」差異來自這個*不是來自哪一個,也跨越相同的範圍,則存在衝突。否則,應用此更改並轉到實際的下一個(可能來自相同的L/R而不是其他)。 – torek

+1

根據我的測試(我還沒有通過源代碼挖掘出來),這個算法稍微調整了一下,假設結束,但不是開始,延長一行,所以如果雙方在相同的位置。 (我們不知道哪些加法應該發生* first *。)另外我不確定我是否正確地表述了這些 - 它確實有助於將它轉換爲詳細的算法,或者研究那裏的一個算法(I相信Git採用了RCS合併算法,所以Tichy的工作可能適用)。 – torek