Хорошо, ребята, я придумал следующее решение (без использования git, mercurial и т. Д.).(ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: может иметь опечатки, может потребоваться изменения для работы на вашей стороне)
Основной метод / алгоритм заключается в следующем:
Разделить оба файла diff на более мелкие компоненты
Сравните компоненты одного файла сравнения с компонентами другого и выберите те, которые идентичны в обоих
- Объедините выбранные компоненты, чтобы создать новый файл сравненияфайл с правильным форматированием
Каждый из моих файлов различий имеет разности на уровне файлов, и каждый разностный уровень имеет один или несколько блоков.Если под компонентами я подразумеваю компоненты уровня файла, то извлечение может быть выполнено с помощью инструментов patchutils «splitdiff» и «комбинированный» следующим образом:
$ # 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 недостаточно,Я нашел инструмент здесь , который разбивает файл на отдельные фрагменты (мне пришлось внести небольшие изменения в этот скрипт, чтобы он работал на моем компьютере ... в частности, мне пришлось закомментировать файл «require».рб '"линия).
Для шага 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: я сначала объединил фрагменты, принадлежащие к одному и тому же файлу (файлам), чтобы создать разность для каждого файла
- Шаг 3, часть 2: я использовал комбинированный файл, чтобы объединить эти файлы различий для созданияокончательный файл сравнения
Для шага 3, часть 1, я создал следующий сценарий оболочки (назовем его combhunks.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 выше. Это только для сравнения.Ловушки, которые идут в финальную разность, должны иметь правильные строки @@, в противном случае вместе сiffiff будет сообщать об ошибках
Под «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: мне пришлось взятьследующий дополнительный шаг, чтобы исправить проблему с ошибочным кодом рубина (упомянутый в моем комментарии ниже):
$ 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