免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 829 | 回复: 0
打印 上一主题 下一主题

细述patch与diff的使用 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-02-26 14:16 |只看该作者 |倒序浏览

                    
都是网上搜集的内容,太多,没全看,但是总的来说,在用diff命令时,我认为比较好的参数组合是upr。
也就是diff -upr 原文件(夹) 新文件(夹) >输出文件
diff & patch
diff和patch是一对工具,在数学上来说,diff是对两个集合的差运算,patch是对两个集合的和运算。
diff比较两个文件或文件集合的差异,并记录下来,生成一个diff文件,这也是我们常说的patch文件,即补丁文件。
patch能将diff文件运用于
原来的两个集合之一,从而得到另一个集合。举个例子来说文件A和文件B,经过diff之后生成了补丁文件C,那么着个过程相当于 A -B =
C ,那么patch的过程就是B+C = A 或A-C =B。因此我们只要能得到A, B,
C三个文件中的任何两个,就能用diff和patch这对工具生成另外一个文件。
这就是diff和patch的妙处。下面分别介绍一下两个工具的用法:
1. diff的用法
diff后面可以接两个文件名或两个目录名。 如果是一个目录名加一个文件名,那么只作用在那么个目录下的同名文件。
如果是两个目录的话,作用于该目录下的所有文件,不递归。如果我们希望递归执行,需要使用-r参数。
命令diff A B > C
,一般A是原始文件,B是修改后的文件,C称为A的补丁文件。不加任何参数生成的diff文件格式是一种简单的格式,这种格式只标出了不一样的行数和内
容。我们需要一种更详细的格式,可以标识出不同之处的上下文环境,这样更有利于提高patch命令的识别能力。这个时候可以用-c开关。
2. patch的用法
patch用于根据原文件和补丁文件生成目标文件。还是拿上个例子来说
patch A C 就能得到B, 这一步叫做对A打上了B的名字为C的补丁。
之一步之后,你的文件A就变成了文件B。如果你打完补丁之后想恢复到A怎么办呢?
patch -R B C 就可以重新还原到A了。
所以不用担心会失去A的问题。
其实patch在具体使用的时候是不用指定原文件的,因为补丁文件中都已经记载了原文件的路径和名称。patch足够聪明可以认出来。但是有时候会有点小问
题。比如一般对两个目录diff的时候可能已经包含了原目录的名字,但是我们打补丁的时候会进入到目录中再使用patch,着个时候就需要你告诉
patch命令怎么处理补丁文件中的路径。可以利用-pn开关,告诉patch命令忽略的路径分隔符的个数。举例如下:
A文件在
DIR_A下,修改后的B文件在DIR_B下,一般DIR_A和DIR_B在同一级目录。我们为了对整个目录下的所有文件一次性diff,我们一般会到DIR_A和DIR_B的父目录下执行以下命令
diff -rc DIR_A DIR_B > C
这个时候补丁文件C中会记录了原始文件的路径为 DIR_A/A
现在另一个用户得到了A文件和C文件,其中A文件所在的目录也是DIR_A。
一般,他会比较喜欢在DIR_A目录下面进行patch操作,它会执行
patch
但是这个时候patch分析C文件中的记录,认为原始文件是./DIR_A/A,但实际上是./A,此时patch会找不到原始文件。为了避免这种情况我们可以使用-p1参数如下
patch -p1
此时,patch会忽略掉第1个”/”之前的内容,认为原始文件是 ./A,这样就正确了。使用patch
patch附带有一个很好的帮助,其中罗列了很多选项,但是99%的时间只要两个选项就能满足我们的需要:
patch -p1
patch -R
-p1选项代表patchfile中
文件名左边目录的层数,顶层目录在不同的机器上有所不同。要使用这个选项,就要把你的patch放在要被打补丁的目录下,然后在这个目录中运行path
-p1
补丁Patch是天才程序员、Perl的发明者Larry
Wall发明的,它应高效地交流程序源代码之需求而生,随着以Linux为代表的开发源代码运行的蓬勃发展,patch这个概念已经成为开放源代码发起
者、贡献者和参与者的集体无意识的一部分。patch只包含了对源代码修改的部分,这对于开放源代码社区的协同开发模式具有重要意义,意味的软件新版本的
发布和对软件的缺陷或改进可以以更小的文件发布,可以减少网络的传输量,方便软件维护者的管理工作。
patch文件有多种格式,不同平台上所支持的格式不尽相同,但最常见的是context格式和unified格式。context格式被广泛使用,是
patch文件格式事实上的标准。该格式包含了差异部分及其邻近的若干行,邻近就是所谓的上下文,这些行虽然没有变化,但它们出现在patch文件使得还
原patch的程序具备更强的容错性。unified格式常见于GNU的patch实现,以patch形式发布的linux内核就使用了该格式。此外,还
有其它比较少用的格式,如Normal格式,并排对比模式(side-by-side),ed script和RCS
script模式等。除了并排对比模式方便用户观察文件差异,其它格式大多数是为了兼容旧的patch格式。
patch的工具
patch有十分丰富的工具,在Unix/Linux系统下diff/patch是最主要的patch命令行工具。另外,一些版本控制软件
TortoiseCVS、 Subversion,
WinMerge及集成开发环境如Eclipse包含了patch生成、应用的功能。使用命令行工具生成在Unix/Linux系统下只需要使用diff
命令,在Windows下可以安装Cygwin来模拟Unix环境,当然有时候Cygwin显得过于庞大,此时可以使用unxutils,它是常用的
GNU命令在Windows系统上的移植版,其中包含了diff和patch命令。从
http://unxutils.sourceforge.net下
载该软件包后,将其usr\local\wbin目加到Path环境变量即可使用这些命令。
产生补丁生成patch命令用diff命令,该命令的基本用法是: diff [选项] 旧文件或目录
新文件或目录该命令根据选项产生新旧文件或目录之间的patch,并把该patch输出到标准输出上。选项用来指定输出的patch文件格式,如果比较的是目录是否需要递归,对只在一边目录中存在的文件的处理方法,如何处理空格、制表符、小写等;常用选项有
-c 表示产生context格式的patch -u 表示产生unified格式的patch -r
表示对目录进行递归操作,用于产生整个代码树的patch -N
表示如果文件不存在则将其等价为空文件,这个用于产生有文件增加或删除的patch
接下来,需要指定比较的对象,它们可以是文件,也可以时目录。旧版本列在前面,新版本列在后面。当然,文件或目录也可以从标准输入获得。此时,文件或目录名称用减号"-"表示。实例:
cat build.xml |diff -y -W 100 - build-1.10.xml
以每列100个字符的宽度并排对比输出build.xml和build-1.10.xml之间的差异到屏幕(标准输出)
diff -c web.xml web2.xml > web.xml.diff
产生web2.xml相对于web.xml的修改的上下文格式补丁文件到web.xml.diff中去
diff -crN src src_XFIRE > xfire-patch.diff
产生代码树src_XIRE相对于代码树src的上下文补丁文件到xfire-patch.diff中去,在src_XFIRE中新增的文件的内容也会被包含在补丁中。
打补丁打补丁可以使用命令行工具patch。它的基本用法是:patch -pnum
例子: cd src patch -p1
void main() { printf("HELLO THE WORLD!\n"); }
使用以下命令生成补丁文件hello.patch $diff -u hello.c hello-new.c
>hello.patch
diff可以对整个目录进行比较,生成补丁文件 例如有hello-1.0
和hello-1.1两个目录,其中hello-1.1为hello-1.0的更新 命令: $diff -ruNa hello-1.0
hello-1.1 >hello-1.1.patch
2.patch的使用 把补丁运用到原代码上的命令为patch patch [-b] suffix
如果patch失败,patch会把成功的行打上补丁,失败的行存为以.rej为后缀的文件折,并生成原文件的备份,如果成功则不生成备份。
-b选项可以指定后缀名。
注意:运行patch所在的目录应该与用diff生成补丁的时候一致。例如,上面在hello-1.0目录的上层目录生成补丁文件,patch时也应该在此目录进行。============================================
diff && path- -
diff diff是生成源码补丁的必备工具。其命令格式为:
 diff [命令行选项] 原始文件 新文件
常用命令行选项如下:
   -r 递归处理目录     -u 输出统一格式(unified format)
   -N patch里包含新文件   -a patch里可以包含二进制文件
  它的输出在stdout上,所以你可能需要把它重定向到一个文件。diff的输出有“传统格式”和“统一格式”之分,现在大都使用统一格式:
  传统格式示例:
   [hahalee@builder]$ diff a.txt b.txt
   1a2
   > here we insert a new line
   3d3
   
  统一格式示例:
   [hahalee@builder]$ diff -u a.txt b.txt
   --- a.txt Thu Apr 6 15:58:34 2000
   +++ b.txt Thu Apr 6 15:57:53 2000
   @@ -1,3 +1,3 @@
   This is line one
   +here we insert a new line
   and this is line two
   -why not this third line?
 
 通过比较可以看出,传统格式的patch文件比较小,除了要删除/插入的行外没有冗余信息。统一格式则保存了上下文(缺省是上下各三行,最少需要两
行),这样,patch的时候可以允许行号不精确匹配的情况出现。另外,在patch文件的开头明确地用---和+++标示出原始文件和当前文件,也方便
阅读。要选用统一格式,用 u 开关。
通常,我们需要对整个软件包做修改,并生成一个patch文件,下面是典型的操作过程。这里就要用到前面介绍的几个命令行开关了:
  tar xzvf software.tar.gz # 展开原始软件包,其目录为software
  cp _a software software-orig # 做个修改前的备份
  cd software
  [修改,测试……]
  cd ..
  diff _ruNa software-orig software >
software-my.patch
 
 现在我们就可以保存software-my.patch做为这次修改的结果,至于原始软件包,可以不必保存。等到下次需要再修改的时候,可以用
patch命令把这个补丁打进原始包,再继续工作。比如是在linux kernel
上做的工作,就不必每次保存几十兆修改后的源码了。这是好处之一,好处之二是维护方便,由于unified
patch格式有一定的模糊匹配能力,能减少原软件包升级带来的维护工作量(见后)
patch
  patch命令跟diff配合使用,把生成的补丁应用到现有代码上。常用命令行选项:
  patch [命令行选项] [待patch的文件[patch]]
  -pn patch level(n是数字) -b[后缀] 生成备份,缺省是.orig
为了说明什么是patch level,这里看一个patch文件的头标记。
  diff -ruNa xc.orig/config/cf/Imake.cf
xc.bsd/config/cf/Imake.cf
  --- xc.orig/config/cf/Imake.cf Fri Jul 30 12:45:47 1999
  +++ xc.new/config/cf/Imake.cf Fri Jan 21 13:48:44 2000
 
 这个patch如果直接应用,它会去找xc.orig/config/cf目录下的Imake.cf文件,假如你的源码树的根目录是缺省的xc而不是
xc.orig,除了mv xc xc.orig之外,有无简单的方法应用此patch呢?patch
level就是为此而设:patch会把目标路径名砍去开头patch level个节(由/分开的部分)。在本例中,可以用下述命令:cd
xc; patch _p1
  如果patch成功,缺省是不建备份文件的(注:FreeBSD下的patch工具缺省是保存备份),如果你需要,可以加上 b
开关。这样把修改前的文件以“原文件名.orig”的名字做备份。如果你喜欢其它后缀名,也可以用“b 后缀”来指定。
  如果patch失败,patch会把成功的patch行给patch上,同时(无条件)生成备份文件和一个.rej文件。.rej文件里是没有成功提交的patch行,需要手工patch上去。这种情况在原码升级的时候有可能会发生。
  关于二进制文件的说明:binary文件可以原始方式存入patch文件。diff可以生成(加-a选项),patch也可以识别。如果觉得这样的patch文件太难看,解决方法之一是用uuencode处理该binary文件。
rcs
  单个文件的版本控制/管理,适合对少量文件进行版本控制,不适合小组进行项目协作开发。优点:使用简便;缺点:功能有限。RCS常用命令有ci/co/rcsdiff。
rcs用一个后缀为“,v”的文件保存一文件的内容和所有修改的历史信息,你可以随时取出任意一个版本,用rcs保存程序就不必为不同版本分别备份。
ci _ check in,保存新版本 co _ check out,取出当前(或任意)版本
cvs 是多平台的,开发可以在多种平台比如,可以把linux上的CVS Repository通过samba
export出来在Windows平台上做开发。现在很多软件包里包含有*NIX/Windows/MacOS等多平台支持代码,cvs的跨平台特性可提
供最好的多平台开发支持。
  不过,cvs的操作是直接基于文件系统的,在需要大量远程协作的场合问题很多,远程的NFS
mount效率太差,也会有安全问题。新版本的cvs自身内建了Client/Server支持,也可以利用Unix上传统的远程交互手段来通讯。
  1,通过rsh(也可用ssh替换)
  2,使用cvs自带的C/S用户认证:pserver(缺省端口2401)
  3,使用kerberos的gserver、kserver
# 可以把库文件拷贝到 /etc/ld.so.conf 中列举出的任何目录中,并以 root 身份运行 ldconfig;或者# 运行
export LD_LIBRARY_PATH='pwd',它把当前路径加到库搜索路径中去。 1> ldd
工具 ldd 用来显示执行文件需要哪些共享库, 共享库装载管理器在哪里找到了需要的共享库.
2> soname
共 享库的一个非常重要的,也是非常难的概念是 soname--简写共享目标名(short for shared object
name)。这是一个为共享库(.so)文件而内嵌在控制数据中的名字。如前面提到的,每一个程序都有一个需要使用的库的清单。这个清单的内容是一系列库
的 soname,如同 ldd 显示的那样,共享库装载器必须找到这个清单。
soname 的关键功能是它提供了兼容性的标准。当要升级系统中的一个库时,并且新库的 soname 和老的库的 soname
一样,用旧库连接生成的程序,使用新的库依然能正常运行。这个特性使得在 Linux
下,升级使用共享库的程序和定位错误变得十分容易。
在 Linux 中,应用程序通过使用 soname,来指定所希望库的版本。库作者也可以通过保留或者改变 soname
来声明,哪些版本是相互兼容的,这使得程序员摆脱了共享库版本冲突问题的困扰。
查看/usr/local/lib 目录,分析 MiniGUI 的共享库文件之间的关系
3> 共享库装载器
当 程序被调用的时候,Linux
共享库装载器(也被称为动态连接器)也自动被调用。它的作用是保证程序所需要的所有适当版本的库都被调入内存。共享库装载器名字是 ld.so
或者是 ld-linux.so,这取决于 Linux libc
的版本,它必须使用一点外部交互,才能完成自己的工作。然而它接受在环境变量和配置文件中的配置信息。
文件 /etc/ld.so.conf 定义了标准系统库的路径。共享库装载器把它作为搜索路径。为了改变这个设置,必须以 root
身份运行 ldconfig 工具。这将更新 /etc/ls.so.cache 文件,这个文件其实是装载器内部使用的文件之一。
对软件的评价:代码的稳定性、友好性、代码的易读性、统一的风格、技巧。
1。尽量少的使用全局变量
2。局部变量一定要初始化,特别是指针变量
3。成员函数功能单一,不要过分追求技巧,函数体不要过长。
4。最好有头文件
5。关于变量名的长短问题
6。设计函数时考虑到通用性
7。申请内存时,一定先要释放。注意 if 问题。
8。对浮点数比较大小时注意不要使用 ==
9。最好不要用 goto 语句
10。所有成员函数要单出口单入口
11。函数中,要先检验参数的合法性
12。最好所有的函数都有返回值,表明错误的原因。
13。注释问题
14。类型转化一律用显示转换。
15。定义宏说,参数使用括号,结果也应该括起来
  • define SUB(a,b) ((a)-(b))
    3*SUB(3,4-5);
    16。变量长度一定要用 sizeof 来求
    17。malloc 后千万别忘 free 及使指针等于 NULL。
    18。字符串拷贝时尽量少使用 sprintf,而使用 memcpy,最后别忘加上'\0'
    19。慎重选择编译时的优化选项。
    20。小组开发时,注意代码风格的统一。
    ====================================
    diff命令比较两个不同的文件或不同目录下的两个同名文件.
    在使用diff时,可以用选项来定制输出格式.patch程序将读取diff的输出和所比较文件中的一个来重新生成另一个.diff手册的作者写道:"如果你认为diff是通过从一个文件中减去另一个来生成这两个文件的差别文件,那就可以认为
    patch是使用这个差别文件和其中的一个源文件来生成另一个源文件".
    diff命令的一般语法为:
    diff [option] srcfile dstfile
    diff在运行时试图找到在srcfile和dstfile里都一样的很多连续行,在碰到srcfile和dstfile里不一样的行时运行被打打断,这些有差别的行称为块(hunk).
    diff的命令行选项合参数
    选项 描述
    -a 将所有的文件看作文本,既使文件看起来像是二进制的也不例外,并且进行逐行比较
    -b 忽略块中空白数目的改变
    -B 忽略插入或删除空行造成的改变
    -c 产生"上下文"(context)格式的输出
    -C[num]
    产生"上下文"(context)格式的输出,显示块前后num行的内容,如果不指定num的值,则显示块前后3行的内容
    -H 修改diff处理大文件的方式
    -i 忽略大小写,同样对待大写和小写字母
    -I regexp 忽略插入或删除与正则表达式regexp匹配的行
    -l 将输出结果通过pr命令处理加上页码
    -p 显示出现块的C函数
    -q 只报告文件是否不同;不输出差别
    -r 比较目录时,进行递归比较
    -s 报告两个文件相同(默认的行为是不报告相同的文件)
    -t 输出时tab扩展为空白
    -u 产生"统一"(unified)格式的输出
    -U[num]
    产生"统一"(unified)格式的输出,显示块前后num行的内容,如果不指定num的值,则显示块前后3行的内容
    -v 打印diff的版本号
    -w 逐行比较时忽略空白
    -W cols 如果产生并排格式的输出(参见-y) ,让输出的每一列有cols个字符宽
    -x pattern 当比较目录时,忽略匹配模式pattern的任何文件和子目录
    -y 产生并排格式的输出
    Retrieved from "
    http://172.16.36.23/oswiki/index.php?title=Diff%26patch
    "
                   
                   
                   
                   

    本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/67414/showart_1844248.html
  • 您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

    北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年举报专区
    中国互联网协会会员  联系我们:huangweiwei@itpub.net
    感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP