簡體   English   中英

以編程方式預合並Merurial(或git)

[英]Programmatically pre-merge in mercurial (or git)

我們經常遇到某些常見的,無信息的合並沖突,尤其是在合並回歸測試輸出時。 我希望能夠以編程方式忽略與某些模式匹配的行(例如,“如果某行或區域與該正則表達式匹配,則從其他補丁中獲取補丁”),但是我仍然想切換到交互式合並工具來處理文件中的其他沖突(如果有的話)(而不必手動重新合並第一行。)

如果我與任何工具(例如:merge3或我可能設計的任何工具)預先合並,然后與另一個工具重新合並,那么它似乎總是從頭開始。 對於已經解決的沖突,有什么辦法可以“保存我的工作”?

我們使用mercurial ,但是如果git的過程類似,請告訴我。

Git中的過程有所不同,但是您應該能夠在任何一個系統中實現所需的功能。

TL; DR是您必須編寫自己的合並工具(或Git中的合並驅動程序)。 該合並工具應比較這三個輸入文件並進行所需的任何合並,然后使用一組新的基本文件和輸入文件運行常規的低級合並驅動程序。

首先,請注意Mercurial有其自己的“ premerge”定義。 有關更完整的說明,請參見https://www.mercurial-scm.org/wiki/MergeToolConfiguration 我認為您的問題完全不涉及這種合並。 相反,您想要編寫Mercurial稱為合並工具的內容 (Git將此稱為合並驅動程序 。)

讓我們定義一些定義,以便大家都同意術語。 運行hg mergegit merge ,選擇兩個特定的提交進行合並。 一種是您當前的提交,由於Mercurial使用該名稱,因此我們將其稱為local 我們將調用其他犯下其他出於同樣的原因。 (Mercurial有時將第二個稱為“ 遠程” ,但主要是內部使用的--ours和“ --theirs ”稱為“ 本地遠程” ,或者稱為“ 本地”和“ 其他” :Git在保持一致性方面根本不好。)

您簽出本地提交並運行hg merge othergit merge other ,Mercurial或Git將找到合並基礎提交,它們都稱為合並基礎或僅稱為基礎。

在兩個系統中,所有三個有趣的提交均表示為快照:這是基本提交時的文件。 這是與本地提交相同的文件(可能還有一些新文件,一些已刪除文件,一些已重命名文件)。 這是與其他提交相同的文件。 嘿, 鈴鼓人 版本系統先生,請為我合並。

高級合並

VCS必須做的第一件事是將每個基本提交文件與每個本地提交文件和每個其他提交文件配對。 整個文件上可能有兩個操作(創建,重命名或刪除)。 特別是,如果在一次或兩次提交中對文件進行了重命名,則VCS必須處理此問題。 如果在一次或兩次提交中刪除了文件,則VCS必須處理該文件。 如果兩次提交都創建了基礎文件中不存在的文件,則VCS也必須處理該文件。 其中一些很簡單:如果僅在兩次提交之一中對文件F進行了重命名,那么,我們只是在最終結果中對它進行了重命名,而其他情況下則照常合並更改。 但是其他更改彼此沖突:如果兩個提交都重命名了文件,VCS應該使用哪個名稱? 我稱這些沖突為高級沖突。 1個

在這里,Git優於Mercurial。 Mercurial使您可以立即為每個高級沖突選擇解決方案,以便它知道每個文件的最終命運。 2 Git使您推遲此決定(盡管Git中的基礎實現存在問題)。 一會兒,我會提到更多。 這部分,您不能在Mercurial中很好地實現自動化(或者至少不能上一次嘗試)。 幸運的是,對於這兩種VCS,此類沖突很少見。

低級合並

現在我們知道了所有文件的命運(或已在Git中推遲了此決定),特別是Mercurial將使用您選擇的工具(通過--tool$HGMERGE )合並每個文件。 我將其稱為低級合並,以區別於將文件配對和確定文件名的高級過程。 此低級合並過程在“ Mercurial如何內部合並”的 答案中概述

記住,我們有三個輸入:基本輸入,本地輸入和其他輸入。 最終合並將有兩個父母:本地父母和其他父母。 與基礎版本相比,我們可以認為每個低級文件在任一父級中都是“更改”的。 或者,該文件可能與其中一個或兩個父文件中的文件相同。 如果根本沒有觸摸該文件(如果在所有三個提交中都完全相同),則無需執行任何操作:最終文件應與基本文件匹配。 如果僅在一個父對象中(相對於本地對象而言,在本地或另一父對象中)對文件進行了修改,那么實際上仍然沒有任何事情要做; 我們可以只使用修改后的一個。

如果兩個父母都以完全相同的方式更改了文件,則我們使用哪個父母都沒有關系。 但是請注意, 此Wiki頁面指出此過程適用:

對於父母雙方都更改過的每個文件...

這里有一些微妙之處,值得一看的是Git和Mercurial之間的另一個區別。

在Git中,當我們有三個來自B(基本),L(本地)和O(其他)的文件時,我們真正擁有的是三個哈希ID 哈希ID唯一地標識內容,因此我們可以立即分辨出哪些文件匹配,哪些文件不匹配。 如果L = O,則父母雙方都擁有相同版本的文件,而我們只取其中一個,而與B無關(兩者都進行了相同的更改,或者沒有人進行任何更改)。 否則,如果B = L或B = O,我們將選擇匹配的那個,因為那是發生更改的父項。 否則(B≠L,B≠O,L≠O),我們必須進行實數合並。

Mercurial不會按哈希ID存儲文件。 相反,它知道文件是否從B到L的提交沿某處以及從B到O的提交沿某處已更改。因此,它只是查看自B以來父母雙方的提交序列是否都修改了該文件。

所有這些的結果是,在Git中,只有所有三個輸入都不同時,合並驅動程序才會運行。 在Mercurial中,如果父母雙方都觸摸了文件,則合並工具可以運行,但是兩個甚至三個輸入都可能匹配。 在大多數情況下,這沒有什么區別,但在特殊情況下請記住這一點。 Mercurial內置的預合並(您沒有在說的)可以為您處理這種特殊情況,因此,除非您禁用預合並,否則您實際上不會看到它。

當合並驅動程序運行時,您將三個輸入和輸出文件的名稱傳遞給它,如示例中從我的第一個Mercurial Wiki鏈接:

mymergetool.args = $local $other $base -o $output

(這來自您的.hgrc或等效文件)。 在Git中,除了在.gitconfig或類似文件中定義合並驅動程序外.gitconfig類似:

driver = filfre %O %A %B

然后從.gitattributes文件引用此驅動程序,這三個輸入文件之一也是輸出文件(有關詳細信息,請參見gitattributes文檔 )。

合並工具/合並驅動程序必須讀取這三個輸入文件,並使用它們來計算和寫入正確的輸出文件,這是版本控制系統所看到的一步 您可以在內部使用任意多個步驟。 完成后,如果輸出文件是完全合並的正確結果,則應以狀態0退出,如果合並需要手動編輯或進一步工作,則應以非零(通常為1)狀態退出。

對於您的情況,您將分析差異,自己組合一些更改,創建三個新的輸入文件,然后在該文件上運行其他文件合並工具。 Mercurial似乎沒有運行其內部低級別文件合並的好方法; 該Wiki頁面建議使用GNU diff3來完成這項工作,並包括一個運行diff3的腳本,如果它指示沖突,請在產生的有沖突的文件上運行vi或其他編輯器。

Git包含git merge-file命令,該命令對任何三個輸入文件進行三向合並(實際上,您可以直接從Mercurial使用git merge-file )。 請注意,如果git merge-filediff3能夠成功合並文件,它們都已經退出0,否則不能退出零。


1 Mercurial允許在此處選擇不同的合並算法,並且有多種選擇:請參閱Consensus MergeBid Merge Git的,也允許不同的合並算法,它調用策略 ,它的默認值是它所謂的遞歸策略。 在某些情況下,要達到合並的高級階段,就可以選擇文件以進行低級合並過程,或者在Git遞歸合並的情況下, 構造文件。

2源代碼建議Mercurial可以將其推遲到以后,以節省合並狀態中的高級沖突。 我一直不停地戳它,但是卻找不到找到這種方法的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM