开发者

Diff of two directory trees to create file/folder level patch (incl. binary files)

开发者 https://www.devze.com 2023-04-06 18:58 出处:网络
There\'s lots of solutions for creating a file level patch f开发者_如何学Pythonor text files and the like. What I\'m looking for is an easy script/shell command that will compare oldversion/ newversio

There's lots of solutions for creating a file level patch f开发者_如何学Pythonor 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.

Previously, we were using the hack:

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

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

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

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


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

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:

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.

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..)


diff -ruN oldversion newversion


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:

# 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号