需求

最近团队正在开发一个版本对比工具,要求是把A1文件夹与A2对比,将A2中的增量部分,输出到update文件夹中,生成增量升级包/差分包。

方案研究

实现该功能的第一反应是,分别遍历2个文件夹,进行单个文件对比是否存在于MD5比对,并输出结果,但是这个绝对是最低级做法,并且时间复杂度为O(n²),基本上就是直接否定。

后来深入研究了内核补丁常用的diff + patch方案,即

diff -urNa dir1 dir2

生成了差异文件后,用patch命令进行文件的复制或者文件内容修改。这个很明显如果要实现需求还是要去人工代码解析diff的结果才行。也是复杂了。

突然。。或者是说类似动画片里面柯南那句masaka 搭配场景闪现的效果出现了...

能分析出文件夹差异,还能支持多种对比模式checksum、mod-time、size的,还能过滤掉svn不需要提交的二进制文件、中间文件,经常用于服务器端增量同步的,不就是rsync么。。。(该处rsync应该字号放大十倍,但是markdown改不了)

现在唯一要解决的问题是,rsync是从A文件夹同步到B文件夹,是否可以重定向这个同步的文件到C文件夹而不改变B文件夹内容呢?

翻看了rsync man之后oh ~ 这个--dry-run参数是演示trial的意思。。也就是说使用了dry-run就只能看,不会变了。。。
马上开始coding。。。

STEP1

A1.1是新文件夹,A1.0是旧文件夹,out是放置 A1.0到A1.1的保持目录结构的增量文件。

rsync --dry-run -rcnC --out-format="%n"  A1.1/  A1.0/

注意该处的-C参数是按照cvs的ignore规则来过滤不需要同步的文件,在CVS中,默认是不会提交二进制文件的,所以如果需要进行二进制文件提取,那就不要加C.
执行了该命令后,得到了一个A1目录的文件列表:
A1.1/system/app/
A1.1/system/app/A.apk
A1.1/system/app/B.apk
A1.1/system/app/C.apk
也就是差异文件,由于这里默认会显示出文件夹,所以要过滤掉以『/』结尾的文件夹的显示

rsync --dry-run -rcnC --out-format="%n"  A1.1/  A1.0/ |grep -v "/$"

这样就得到了一个纯增量文件的列表

STEP2

有了文件列表,复制的操作方法就很多了。可以继续使用rsync同步到新的out目录,以防止多次执行后错误文件修复问题
完整代码

rsync --dry-run -rcnC --out-format="%n"  A1.1/  A1.0/ |grep -v "/$"|xargs -I{} rsync -R A1/./{} out/

搞定!

总结

其实我们身边有很多常用的工具,具备强大的功能。其实作为程序猿这个群体,『浮躁』是一个界限将高手与菜鸟分开。其实高手并不是掌握了多少语言,懂了多少模式、收藏了多少的开源代码工具...
而是需要踏踏实实走好每一步。