用于创建文件/文件夹级别补丁的两个目录树的差异(包括二进制文件)

时间:2022-12-01 21:44:43

There's lots of solutions for creating a file level patch for text files and the like. What I'm looking for is an easy script/shell command that will compare oldversion/ newversion/ and give me a tree of files that I need to copy over oldversion to make it be equal to newversion (assuming files are not removed in the updated version). Note that the two folders contain both binary and text files.

有很多解决方案可以为文本文件等创建文件级补丁。我正在寻找的是一个简单的脚本/ shell命令,它将比较oldversion / newversion /并给我一个文件树,我需要复制oldversion以使其等于newversion(假设文件未在更新中删除)版)。请注意,这两个文件夹包含二进制文件和文本文件。

Previously, we were using the hack:

以前,我们使用黑客:

fdupes -qrf newversion/ oldversion/ | grep "newversion" | xargs rm;

fdupes -qrf newversion / oldversion / | grep“newversion”| xargs rm;

Leaving us with the folder "newversion" that could be packaged as a patch.

让我们留下可以打包为补丁的文件夹“newversion”。

Unfortunately, this turned out to be disastrous because fdupes does not consider filenames.

不幸的是,这被证明是灾难性的,因为fdupes不考虑文件名。

What'd be great is something like fdupes that actually did include the filename in the comparison.

什么是伟大的是像fdupes,实际上包括比较中的文件名。

3 个解决方案

#1


5  

The diff command can be asked to output filenames which differ.

可以要求diff命令输出不同的文件名。

diff --quiet --recurse --unidirectional-new-file OLDDIR NEWDIR

Files old/main and new/main differ
Files old/main.cpp and new/main.cpp differ
Files old/Makefile and new/Makefile differ
Files old/sounds/popalien.wav and new/sounds/popalien.wav differ
Files old/sounds/saucer.wav and new/sounds/saucer.wav differ

Of course, it's not a nice output, but since you're only looking for NEW files to package as a patch, a quick sed pipe works wonders:

当然,它不是一个很好的输出,但由于你只是寻找新的文件打包作为补丁,快速的sed管道工作奇迹:

diff --quiet --recurse -unidirectional-new-file OLDDIR NEWDIR | \
  sed "s/^.* and \(.*\) differ/\1/"

(broken for readability)

(为便于阅读而破)

new/main
new/main.cpp
new/Makefile
new/sounds/popalien.wav
new/sounds/saucer.wav

Spaces around 'and' and preceeding 'differ'

'和'之前的空格和'不同'之前的空格

The ORDER of the operands to diff makes a difference, first argument is left of ' and ', second is after. Watch out for that.

差异操作数的ORDER有所不同,第一个参数留下'和',第二个参数留在后面。注意这一点。

Also, if you delete a file from NEWDIR, this will not find it as given, only added or changed files. To also output filenames for files not found in either subdir, replace the --unidirection-new-file with --new-file. (short options exist for all except --unidirectional..)

此外,如果您从NEWDIR删除文件,则不会找到它,只会添加或更改文件。要同时输出在subdir中找不到的文件的文件名,请将--unidirection-new-file替换为--new-file。 (除了--unidirectional ..之外的所有短选项都存在。)

#2


1  

diff -ruN oldversion newversion

diff -ruN oldversion newversion

#3


0  

I know it has been long time. I needed same solution. I found this post but it was not sufficient. Then I found rsync can do the job IFF you ``patch`` identical copies, and don't need merging with other changes. I intend on using this with updating yum mirrors on disconnected machines. My full solution is a little more involved, and I am writing commands from memory so some fine details could be wrong, but at the core:

我知道已经很久了。我需要相同的解决方案我找到了这篇文章,但这还不够。然后我发现rsync可以完成IFF你``patch``相同的副本,并且不需要与其他更改合并。我打算用它来更新断开连接的机器上的yum镜像。我的完整解决方案涉及更多,我正在从内存中编写命令,因此一些细节可能是错误的,但核心:

# create identical copy "copy.0"
rsync -a master/ copy.0/

# Presumably transfer copy.0/ to another machine for offline use
# but copy.0 must not mutate outside of this process or sync probably
# will not work.

# some time later update master, e.g. rsync master from upstream mirror
# mutates master in some way, changes/adds/removes remove files including
# binaries
echo -n $'\001\002' > master/new.bin
rm master/gone.bin

# generate rsync batch that can be used to ``patch`` copy.0
# to become identical to master
rsync -a --delete --itemize-changes --only-write-batch=copy.0.batch \
    master/ copy.0/
# now the file copy.0.batch contains only the deltas to be applied

# transfer the batch file to where it needs to be applied

# apply the batch to copy.0
rsync -a --delete --itemize-changes --read-batch=copy.0.batch copy.0/

This takes care of deletions and many other things, probably permissions, timestamps etc, but I think it might not handle hard links as hard link and will probably create them as separate unlinked files.

这会处理删除和许多其他事情,可能是权限,时间戳等,但我认为它可能不会将硬链接作为硬链接处理,并且可能会将它们创建为单独的未链接文件。

#1


5  

The diff command can be asked to output filenames which differ.

可以要求diff命令输出不同的文件名。

diff --quiet --recurse --unidirectional-new-file OLDDIR NEWDIR

Files old/main and new/main differ
Files old/main.cpp and new/main.cpp differ
Files old/Makefile and new/Makefile differ
Files old/sounds/popalien.wav and new/sounds/popalien.wav differ
Files old/sounds/saucer.wav and new/sounds/saucer.wav differ

Of course, it's not a nice output, but since you're only looking for NEW files to package as a patch, a quick sed pipe works wonders:

当然,它不是一个很好的输出,但由于你只是寻找新的文件打包作为补丁,快速的sed管道工作奇迹:

diff --quiet --recurse -unidirectional-new-file OLDDIR NEWDIR | \
  sed "s/^.* and \(.*\) differ/\1/"

(broken for readability)

(为便于阅读而破)

new/main
new/main.cpp
new/Makefile
new/sounds/popalien.wav
new/sounds/saucer.wav

Spaces around 'and' and preceeding 'differ'

'和'之前的空格和'不同'之前的空格

The ORDER of the operands to diff makes a difference, first argument is left of ' and ', second is after. Watch out for that.

差异操作数的ORDER有所不同,第一个参数留下'和',第二个参数留在后面。注意这一点。

Also, if you delete a file from NEWDIR, this will not find it as given, only added or changed files. To also output filenames for files not found in either subdir, replace the --unidirection-new-file with --new-file. (short options exist for all except --unidirectional..)

此外,如果您从NEWDIR删除文件,则不会找到它,只会添加或更改文件。要同时输出在subdir中找不到的文件的文件名,请将--unidirection-new-file替换为--new-file。 (除了--unidirectional ..之外的所有短选项都存在。)

#2


1  

diff -ruN oldversion newversion

diff -ruN oldversion newversion

#3


0  

I know it has been long time. I needed same solution. I found this post but it was not sufficient. Then I found rsync can do the job IFF you ``patch`` identical copies, and don't need merging with other changes. I intend on using this with updating yum mirrors on disconnected machines. My full solution is a little more involved, and I am writing commands from memory so some fine details could be wrong, but at the core:

我知道已经很久了。我需要相同的解决方案我找到了这篇文章,但这还不够。然后我发现rsync可以完成IFF你``patch``相同的副本,并且不需要与其他更改合并。我打算用它来更新断开连接的机器上的yum镜像。我的完整解决方案涉及更多,我正在从内存中编写命令,因此一些细节可能是错误的,但核心:

# create identical copy "copy.0"
rsync -a master/ copy.0/

# Presumably transfer copy.0/ to another machine for offline use
# but copy.0 must not mutate outside of this process or sync probably
# will not work.

# some time later update master, e.g. rsync master from upstream mirror
# mutates master in some way, changes/adds/removes remove files including
# binaries
echo -n $'\001\002' > master/new.bin
rm master/gone.bin

# generate rsync batch that can be used to ``patch`` copy.0
# to become identical to master
rsync -a --delete --itemize-changes --only-write-batch=copy.0.batch \
    master/ copy.0/
# now the file copy.0.batch contains only the deltas to be applied

# transfer the batch file to where it needs to be applied

# apply the batch to copy.0
rsync -a --delete --itemize-changes --read-batch=copy.0.batch copy.0/

This takes care of deletions and many other things, probably permissions, timestamps etc, but I think it might not handle hard links as hard link and will probably create them as separate unlinked files.

这会处理删除和许多其他事情,可能是权限,时间戳等,但我认为它可能不会将硬链接作为硬链接处理,并且可能会将它们创建为单独的未链接文件。