如何将两个文件夹区分为多个补丁文件

时间:2012-09-10 14:36:43

标签: linux ubuntu command-line diff

首先,我尝试在askubuntu上问同样的事情,但我没有到达那里...... https://askubuntu.com/questions/186114/how-to-diff-two-folders-to-multiple-patch-files/186121#comment231985_186121

所以,我会复制/粘贴在这里希望SO给我一个有效的解决方案......

我不是一个unix家伙所以我会继续问:

我有以下问题 - 两个包含大量子文件夹的文件夹。我需要区分它们。

我试过了:

diff -drupN vanila_kernel_3.0.8 my_kernel_3.0.8 > kernel.patch

导致185mb文件...而不是我想要的。

我希望diff的结果是许多较小的补丁,理想情况下,每个更改的文件都有一个补丁内容。这意味着我必须改变我使用diff的方式,我需要把它放在某种循环中......所以我试着运行这个小脚本

for file in original_308/*.*; do
    diff -dupN "$file" "my_308/${file##*/}" > "$file".patch
done

但它不起作用:/

理想情况下,我希望每个更改都有一个.patch文件,但是为原始文件更改的文件提供补丁会很好(因为我可以过滤新添加的文件并将其复制过来)

有人能为我提供一个体面的方式吗?

更新: 我知道这些文件夹和4546个新添加的文件之间有231个已更改的文件...我只对生成这231个补丁感兴趣。我甚至有一个包含这231个文件名的文件,因此也可以在脚本中使用。

我用它来生成更改日志

diff -qdr -x *.o -x *.cmd -x *.d original_308 my_308 | sed "s/^.* and \(.*\) differ/\1/" | sort > changes.txt

并且只打印更改的文件名,由“仅在my_308”文件中落后...... 231个文件位于该文件的顶部(前231行)

所以让我们说清楚 - 我想要源文件的.patch文件。如果补丁最终可以在补丁// file_name.c.patch中结束,那真的很棒......

如果你给我PERL脚本,请告诉我如何最好地使用它们,因为我不明白垃圾。请不要让我失望。我需要移植,测试和运行这个东西,我在unix命令和无形脚本ffs上浪费时间。

5 个答案:

答案 0 :(得分:2)

这样的东西?

DIR1="vanila_kernel_3.0.8"
DIR2="my_kernel_3.0.8"
OUTDIR="patches"
SUFFIX=".patch"

while IFS="," read f1 f2; do
  filename=${f1#$DIR1}  # remove base dir name
  outfile="${OUTDIR}/${filename}${SUFFIX}"
  mkdir -p $(dirname $outfile)  # make sure output directory exist

  diff -dupN "$f1" "$f2" > "$outfile"
done < <(diff -qdr $DIR1 $DIR2 | awk '/differ$/{print $2","$4}')

快速解释:

diff -qdr $DIR1 $DIR2 | awk '/differ$/{print $2","$4}'

这应该会为您提供source_file,dest_file格式中已更改的文件列表。将其传递给while ...read..会为每个更改的文件运行循环体,文件名存储为f1和f2。

filename=${f1#$DIR1}  # remove base dir name

这会删除文件名的尾部(通过删除基目录),这样我们就可以确定输出补丁文件的正确路径。之后,只需要确保输出目录存在,并在f1f2上写出差异结果。

所有文件名的引号确保我们可以处理文件名中的空格。

答案 1 :(得分:2)

你可以抓住&lt; Learning Perl&gt;预订并在一周内学习,Perl非常酷,请不要称之为垃圾。这是用于生成补丁的shell脚本

find ./original_308 -type f | while read file
do
  nfile="./my_308/${file#*original_308/}"
  if [ -f $nfile ]; then
    patchfile="./patch/${file#*original_308/}.patch"
    mkdir -p `dirname $patchfile`
    echo "checking $file $nfile"
    diff -dupN "$file" "$nfile" > "$patchfile" && rm "$patchfile"
  fi
done

diff xxx&gt; patch&amp;&amp; rm patch只会删除空的补丁文件。

答案 2 :(得分:1)

这应该适用于kernel.patch文件,即使您提供给diff的选项与上面显示的选项不同:

perl -ne 'if(m{^diff .* (.*/.*) (.*/.*)}) {
              my $f = $1;
              $f =~ s{/}{_}g;
              open $FH, ">", "$f.patch" or die $!;
          } else {
              print {$FH} $_;
          }' kernel.patch

如果您的文件名包含空格,则可能会中断。

答案 3 :(得分:1)

感谢大家的贡献......这是最终结果

#!/bin/bash                               
FOLDER_OLD="original"
FOLDER_NEW="changed"
FOLDER_PATCHES="./fresh_patches"

echo "Generating changelog for $FOLDER_OLD --> $FOLDER_NEW"
diff -qdr ${FOLDER_OLD} ${FOLDER_NEW} | sed "s/^.* and \(.*\) differ/\1/" | sort > newchanges.txt

mkdir -p ${FOLDER_PATCHES}                                                                                                           
for newfile in `find $FOLDER_NEW -type f`
do
sufix=${newfile#${FOLDER_NEW}/}
oldfile="${FOLDER_OLD}/${sufix}"

if [ -f $oldfile ]; then
    patchfile="${FOLDER_PATCHES}/`echo $sufix |sed 's/\//_/g'`.patch"
    if [ "`diff $oldfile $newfile`" != "" ]; then
        echo "Make patch ${patchfile}"
        diff -dupN "$oldfile" "$newfile" > "$patchfile"
    fi
else
patchfile="${FOLDER_PATCHES}/ADDONS/${newfile#$FOLDER_NEW}"
    echo "Copy $newfile --> $patchfile"
    mkdir -p "`dirname ${patchfile}`"
    cp $newfile $patchfile
fi
done

该脚本首先生成一个已更改的文件列表和仅对新项目/文件夹唯一的文件;然后它为每个文件生成一个补丁文件,并将新添加的文件复制到ADDONS文件夹(对于新项目是唯一的)

答案 4 :(得分:0)

  1. 列表项

             $ diff -rauB  old_dir   new_dir   >  patchfile_name
    
             $ patch --dry-run -p1 -i patchfile_name
    
    
             $ patch -p1 -i patchfile_name
    
  2. 这会在两个目录之间创建一个补丁。