2012-02-04 20 views
0

我有三棵源樹,A,B和C.A是原始樹。 B和C是由2個不同開發人員創建的A的修改。提取兩個補丁文件的公共子集

我已與B和A A的DIFF與C.

但也有認爲是常見的兩種差異文件的許多變化。意思A不是B和C的最新發散點,而是A被修改爲D點(我沒有),B和C被修改爲D.

我的問題是:我可以用兩個diff文件(除了手工)來提取它們的最大公共子集?所以,我認爲應用子集作爲一個補丁A到d

編輯1:插圖:

A ---> D ---> B 
     \---> C 

編輯2:我已經看過patchutils的工具,但一個也沒找到,做什麼,我需要。我也看過this question,但是那裏提到的方法沒有給出正確的輸出。

回答

0

我不知道你會怎麼做手工,但你可以看看3路合併概念:http://en.wikipedia.org/wiki/Merge_(revision_control)#Three-way_merge

一些偉大的版本控制系統採用3路合併爲它的合併算法(如作爲Mercurial)。你也可以在這裏尋找獨立的3路合併工具:https://stackoverflow.com/questions/460198/best-free-3-way-merge-tool-for-windows

+0

我是一個狂熱的git用戶,我也許可以用它爲我的任務......但如果有人曾經遇到過這樣的proble我想知道m之前,git和mercurial當然是在 – 2012-02-04 06:20:59

+0

左右,如果不是3路合併就不會出世;) – LeleDumbo 2012-02-04 06:53:01

0

好吧,我想出了以下解決方案(不使用git,mercurial等)。 (免責聲明:可有錯別字,可能需要更改在你的身邊工作)

基本的方法/算法如下:

  1. 拆分兩個差異文件爲較小的組件

  2. 比較與那些其它的和一個diff文件的組件選擇那些在兩個

  3. 是相同的加入所選擇的組件來創建具有正確的格式
  4. 新diff文件

我的每個diff文件都有文件級別的差異,每個文件級別的差異都有一個或多個hunk。如果組分我的意思是文件級組件,則可以提取與patchutils工具「splitdiff」和「combinediff」進行如下:

$ # Step 1 
$ mkdir AB_components; cp AB.diff AB_components; cd AB_components 
$ splitdiff -ad AB.diff 
$ cd .. 
$ mkdir AC_components; cp AC.diff AC_components; cd AC_components 
$ splitdiff -ad AC.diff 
$ cd .. 
$ 
$ # Step 2 
$ mkdir AD_components; 
$ for f in `diff -rs AB_components AC_components | grep 'are identical$' | cut -d' ' -f2 | cut -d'/' -f2`; do cp AB_components/$f AD_components; done 
$ 
$ # Step 3 
$ cd AD_components; touch AD.diff 
$ for f in `ls ._*`; do combinediff AD.diff $f > tmpfile; mv tmpfile AD.diff; done 

但是如果組件我的意思是個人的帥哥然後splitdiff是不夠的。我發現了一個工具here,它將一個文件分割成單獨的區塊(我必須對該腳本稍作修改才能使其在我的機器上工作......特別是我必須註釋掉「require」file.rb'「行)。

對於步驟2,我不得不運行迴路雙查找「相同」大塊:

$ for f in `ls AB_components.mod/*`; do for g in `ls AC_components.mod/*`; do diff -s $f $g | grep 'are identical$'; done; done > identical_hunks 
$ for f in `cat identical_hunks | cut -d' ' -f2`; do cp AB_components/`basename $f` AD_components; done 

對於組合我不得不跟隨一個兩步過程:

  • 步驟3第1部分:我首先組合了屬於同一個文件的hunk,爲每個文件創建一個diff
  • 第3步第2部分:我用combinediff加入這些diff文件以創建一個最終diff文件

對於步驟3部分1,I創建了下面的外殼腳本(讓我們稱之爲combinehunks.sh):

#!/bin/bash 
filename=$1 
echo 'diff header line:' 
firstpatchfile=`ls -1v $filename.*.patch | head -1` 
head -2 $firstpatchfile 
files=`ls -1v $filename.*.patch` 
for f in $files; do tail -n +3 $f; done 

和我用它如下:

$ mkdir AD_filelevel_components; cd AD_filelevel_components 
$ for f in `ls ../AD_components/* | rev | cut -d'.' -f3- | rev | sort | uniq`; do ../combinehunks.sh $f > `basename $f`.patch; done 

步驟3部分2與文件級別情況下的步驟3相同,除了使用AD_filelevel_components目錄而不是AD_components。

注意事項/備註:

  1. 我曾與這個工作在繼續之前,以除去從---+++標題行時間戳(時間戳通常是不同的,並會不必要地保持從是相同的差異分量)

  2. 我還從程序之前的diff文件中刪除了Only in ...行。

  3. 對於塊級別的工作,我必須在比較之前更改@@行。基本上我刪除了第二部分行,即將@@ -nnn,nn +mmm,mm @@更改爲@@ -nnn,nn @@。注意AB_components.mod與AB_components的使用如上所述。這僅用於比較。進入最後差異的Hunks必須有正確的@@行,否則combinediff將報告錯誤

  4. 'diff file'和'patch file'我的意思是同樣的事情。在整個工作中,我使用統一的diff格式專門即diff -u

AB_components.mod這樣被創造:

$ cp -r AB_components{,.mod} 
$ cd AB_components.mod 
$ for f in `ls`; do sed -i -e 's/@@ \(.*\) \(.*\) @@$/@@ \1 @@/g' $f; done 

編輯1:我不得不採取以下額外步驟來解決該問題與馬車Ruby代碼(在下面我的評論中提到):

$ cd ..; cp -r AB_components{,.mod2}; cd AB_components.mod2 
$ for f in `ls`; do echo $f:`tail -1 $f`; done | grep ':diff ' | cut -d':' -f1 > ../bad_files 
$ for f in `cat ../bad_files`; do head -n -1 ../AB_components/$f > $f; done 
+0

剛發現:gist ruby​​代碼是越野車...要不是那個或者我刪除了「require」file.rb'「這一行使它產生不正確的結果...大約30%的輸出文件在文件末尾顯示虛假的「差異」行... 仍在解決問題... – 2012-02-06 19:07:48