我有三棵源树,A,B和C. A是原始树。 B和C是A的修改,由2个不同的开发人员创建。
我采用了A和B的差异,A和C。
但是两个差异文件中有许多常见的变化。含义A不是B和C的最新分歧点。相反,A被修改为D(我没有),B和C随后被修改为D.
我的问题是:我可以用两个差异文件(除了手工劳动)来提取它们的最大公共子集?以便我将该子集作为补丁应用于A以获得D
编辑1:插图:
A ---> D ---> B
\---> C
编辑2:我看过patchutils工具,但没找到能满足我需求的工具。我也查看了this question但是那里提到的方法没有给出正确的输出。
答案 0 :(得分:0)
我不知道你会如何手动完成这项工作,但你可以看一看三向合并概念: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
答案 1 :(得分:0)
好吧,伙计们,我提出了以下解决方案(不使用git,mercurial等)。 (免责声明:可能有拼写错误,可能需要更改才能在您身边工作)
基础方法/算法如下:
将两个差异文件拆分为较小的组件
将一个差异文件的组件与另一个差异文件的组件进行比较,并选择两者中相同的组件
我的每个diff文件都有文件级差异,每个文件级差异都有一个或多个帅哥。如果组件是指文件级组件,则可以使用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循环才能找到“相同的”帅哥:
$ 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部分,我创建了以下shell脚本(我们称之为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。
注意事项/说明:
在继续这项工作之前,我必须从---
和+++
标题行中删除时间戳(时间戳通常不同,并且会不必要地保持差异组件不相同)
我还在程序之前从diff文件中删除了Only in ...
行。
对于大块级别的工作,我必须在比较之前更改@@行。基本上我删除了第2部分的行,即将@@ -nnn,nn +mmm,mm @@
更改为@@ -nnn,nn @@
。注意AB_components.mod与上面的AB_components的使用。这仅用于比较。进入最后差异的亨克必须有正确的@@线,否则combineiff将报告错误
'diff file'和'patch file'我的意思是一样的。在整个这项工作中,我使用统一的差异格式,即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:我必须采取以下额外步骤来解决有问题的红宝石代码的问题(在下面的评论中提到):
$ 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