如何使用patch和diff合并两个文件并自动解决冲突

如何使用patch和diff合并两个文件并自动解决冲突

我已阅读有关 diff 和 patch 的内容,但我不知道如何应用我需要的内容。我想它非常简单,所以为了展示我的问题,请使用这两个文件:

xml文件

<resources>
   <color name="same_in_b">#AAABBB</color>
   <color name="not_in_b">#AAAAAA</color>
   <color name="in_b_but_different_val">#AAAAAA</color>
   <color name="not_in_b_too">#AAAAAA</color>
</resources>

b.xml

<resources>
   <color name="same_in_b">#AAABBB</color>
   <color name="in_b_but_different_val">#BBBBBB</color>
   <color name="not_in_a">#AAAAAA</color>
</resources>

我想要一个输出,如下所示(顺序无关紧要):

<resources>
   <color name="same_in_b">#AAABBB</color>
   <color name="not_in_b">#AAAAAA</color>
   <color name="in_b_but_different_val">#BBBBBB</color>
   <color name="not_in_b_too">#AAAAAA</color>
   <color name="not_in_a">#AAAAAA</color>
</resources>

合并应包含遵循以下简单规则的所有行:

  1. 仅在一个文件中的任何行
  2. 如果一行具有相同的名称标签但具有不同的值,则从第二个行中获取值

我想在 bash 脚本中应用此任务,因此如果另一个程序更适合,则不一定需要使用 diff 和 patch 来完成

答案1

你不需要patch这个;它用于提取更改并发送它们,而无需文件中未更改的部分。

用于合并文件的两个版本的工具是merge,但正如@vonbrand所写,您需要两个版本分歧的“基本”文件。要在没有它的情况下进行合并,请diff像这样使用:

diff -DVERSION1 file1.xml file2.xml > merged.xml

#ifdef它将包含 C 风格/ “预处理器”命令中的每组更改#ifndef,如下所示:

#ifdef VERSION1
<stuff added to file1.xml>
#endif
...
#ifndef VERSION1
<stuff added to file2.xml>
#endif

如果两个文件之间的行或区域不同,您将得到“冲突”,如下所示:

#ifndef VERSION1
<version 1>
#else /* VERSION1 */
<version 2>
#endif /* VERSION1 */

因此,将输出保存在文件中,然后在编辑器中打开它。搜索#else出现的任何地方,并手动解决它们。然后保存文件并运行它grep -v以删除剩余的#if(n)def#endif行:

grep -v '^#if' merged.xml | grep -v '^#endif' > clean.xml

将来,请保存文件的原始版本。merge借助额外信息可以为您提供更好的结果。 (但要小心:merge就地编辑其中一个文件,除非您使用-p。请阅读手册)。

答案2

sdiff(1) - 并排合并文件差异

使用该--output选项,这将以交互方式合并任意两个文件。你用简单的命令选择更改或编辑更改。

您应该确保EDITOR设置了环境变量。 “eb”等命令的默认编辑器通常是ed, 行编辑器

EDITOR=nano sdiff -o merged.txt file1.txt file2.txt

答案3

merge(1)可能更接近您想要的,但这需要两个文件有一个共同的祖先。

一种(肮脏的!)方法是:

  1. 去掉第一行和最后一行,使用grep(1)排除它们
  2. 将结果粉碎在一起
  3. sort -u留下排序列表,消除重复项
  4. 替换第一行/最后一行

嗯……大概是这样的:

echo '<resources>'; grep -v resources file1 file2 | sort -u; echo '</resources>'

可能做。

答案4

另一个可怕的黑客 - 可以简化,但是:P

#!/bin/bash

i=0

while read line
do
    if [ "${line:0:13}" == '<color name="' ]
    then
        a_keys[$i]="${line:13}"
        a_keys[$i]="${a_keys[$i]%%\"*}"
        a_values[$i]="$line"
        i=$((i+1))
    fi
done < a.xml

i=0

while read line
do
    if [ "${line:0:13}" == '<color name="' ]
    then
        b_keys[$i]="${line:13}"
        b_keys[$i]="${b_keys[$i]%%\"*}"
        b_values[$i]="$line"
        i=$((i+1))
    fi
done < b.xml

echo "<resources>"

i=0

for akey in "${a_keys[@]}"
do
    print=1

    for bkey in "${b_keys[@]}"
    do
        if [ "$akey" == "$bkey" ]
        then
            print=0
            break
        fi
    done

    if [ $print == 1 ]
    then
        echo "  ${a_values[$i]}"
    fi

    i=$(($i+1))
done

for value in "${b_values[@]}"
do
    echo "  $value"
done

echo "</resources>"

相关内容