fmddlmyy的专栏

伐木丁丁鸟鸣嘤嘤

fmddlmyy
fmddlmyy的公告

最近评论
慧军:还是设计自己的UI方案比较好,不能认为WM流行就照抄WM的。WM更大的市场是在商业应用,UI上面就不见得好了。
abbot:very good!
htbegin:很不错!
luxiaoyan:我安装了doxygen, graphviz, 生成的的文档无法显示类图,不知道是怎么回事,请各位帮忙解决一下,谢谢阿。
liaoliaopro:这个应该是表达式求值顺序的问题吧?gcc从左开始求值,vc从右开始求值,最后产生这样的结果。
文章分类
收藏
    相册
    个人主页
    fmddlmyy的留言板
    Mime 手机中文输入引擎
    伐木丁丁鸟鸣嘤嘤——我的个人主页
    历法计算程序
    我的程序
    我的随笔集
    存档
    订阅我的博客
    XML聚合  FeedSky

    原创 Linux之旅(1): diff, patch和quilt (下)收藏

    新一篇: GB18030编码研究以及GBK、GB18030与Unicode的映射 | 旧一篇: Linux之旅(1): diff, patch和quilt (上)

    Linux之旅(1): diff, patch和quilt (下)

    2 quilt

    我们自己的项目可以用cvs或svn管理全部代码。但有时我们要使用其他开发者维护的项目。我们需要修改一些文件,但又不能直接向版本管理工具提交代码。自己用版本管理工具重建整个项目是不合适的,因为大多数代码都是别人维护的,例如Linux内核。我们只是想管理好自己的补丁。这时可以使用quilt。

    2.1 基本概念

    quilt是一个帮助我们管理补丁的程序。quilt的命令格式类似于cvs:

    quilt 子命令 [参数]

    0.46版的quilt有29个子命令。

    掌握quilt的关键是了解使用quilt的流程。使用quilt时,我们会在一个完整的源代码树里工作。只要我们在源代码树里使用了quilt命令,quilt就会在源代码树的根目录建立两个特殊目录:patches和.pc。quilt在patches目录保存它管理的所有补丁。quilt用.pc目录保存自己的内部工作状态,用户不需要了解这个目录。

    patches/series文件记录了quilt当前管理的补丁。补丁按照加入的顺序排列,早加入的补丁在前。quilt用堆栈的概念管理补丁的应用。

    我们在应用补丁A前,必须先应用所有早于补丁A的补丁。所以,patches/series中的补丁总是从上向下应用。例如:上图中,补丁1到补丁5是已经应用的补丁。我们可以将已应用的补丁想象成一个向下生长的堆栈,栈顶就是已应用的最新补丁。应用补丁就是将补丁入栈,撤销补丁就是将补丁出栈。

    我们在源代码树中作任何修改前,必须用"quilt add"命令将要修改的文件与一个补丁联系起来。在完成修改后,用"quilt refresh"命令将修改保存到已联系的补丁。下面我们通过一篇流程攻略来认识一下quilt的命令。

    2.2 导入补丁

    我们把 old-prj.tar.bz2 想象成Linux内核,我们把它解压后,进入代码树的根目录:

    $ mkdir qtest; cd qtest; tar xvjf ../old-prj.tar.bz2; mv old-prj prj; cd prj

    在修改代码前,我们通常要先打上官方补丁。在quilt中,可以用import命令导入补丁:

    $ quilt import ../../prj.diff

    Importing patch ../../prj.diff (stored as prj.diff)

    执行improt命令后, prj 目录会多出一个叫 patches 的子目录:

    $ find patches/ -type f

    patches/prj.diff

    patches/series

    quilt在这个目录存放所有补丁和前面介绍的series文件。quilt的大多数命令都可以在代码树的任意子目录运行,不一定要从根目录运行。我们可以用applied命令查询当前已应用的补丁。

    $ quilt applied

    No patches applied

    目前还没有应用任何补丁。unapplied命令查询当前还没有应用的补丁,top命令查询栈顶补丁,即已应用的最新补丁:

    $ quilt unapplied

    prj.diff

    $ quilt top

    No patches applied

    我们可以使用push命令应用补丁,例如:

    $ quilt push -a

    Applying patch prj.diff

    patching file src/drv/drv1.h

    patching file src/sys/sys1.c

    patching file src/sys/sys1.h

    patching file src/usr/usr1.c

    patching file src/usr/usr1.h

    Now at patch prj.diff

    push的"-a"参数表示应用所有补丁。在使用push命令后,prj 目录会多了一个叫.pc的隐含子目录。quilt用这个目录保存内部状态,用户不需要了解这个目录。应用补丁后,我们再使用applied、unapplied和top命令查看:

    $ quilt applied

    prj.diff

    $ quilt unapplied

    File series fully applied, ends at patch prj.diff

    $ quilt top

    prj.diff

    2.3 修改文件

    我们必须将对源代码树所作的任何改动都和一个补丁联系起来。add命令将文件的当前状态与补丁联系起来。add命令的格式为:

    quilt add [-P 补丁名] 文件名

    如果未指定补丁名,文件就与栈顶补丁联系起来。目前,我们的栈顶补丁是官方补丁。我们不想修改这个补丁,可以用new命令新建一个补丁:

    $ quilt new drv_p1.diff

    Patch drv_p1.diff is now on top

    $ quilt top

    drv_p1.diff

    $ quilt applied

    prj.diff

    drv_p1.diff

    $ quilt unapplied

    File series fully applied, ends at patch drv_p1.diff

    然后用add命令向栈顶补丁添加一个准备修改的文件:

    $ cd src/drv; quilt add drv2.h

    File src/drv/drv2.h added to patch drv_p1.diff

    add命令为指定补丁保存了指定文件的当前快照,当我们执行refresh命令时,quilt就会检查文件的变化,将差异保存到指定补丁中。使用"quilt diff -z [-P 补丁名] [文件名]"可以查看指定补丁指定文件的当前改动。省略-P参数表示查看当前补丁的改动,省略文件名表示查看所有改动。我们修改drv2.h后,执行diff命令:

    $ quilt diff -z

    Index: prj/src/drv/drv2.h

    ===================================================================

    --- prj.orig/src/drv/drv2.h 2008-03-02 13:37:34.000000000 +0800

    +++ prj/src/drv/drv2.h 2008-03-02 13:38:53.000000000 +0800

    @@ -1,7 +1,7 @@

    -#ifndef APP1_H

    -#define APP1_H

    +#ifndef DRV2_H

    +#define DRV2_H

     

    -#include "def1.h"+#include "def2.h" #endif

     

    只要文件已经与我们希望保存改动的补丁联系过了,我们就可以多次修改文件。使用"quilt files [补丁名]"命令可以查看与指定补丁关联的文件。使用"quilt files -val"可以查看所有补丁联系的所有文件。"-v"参数表示更友好的显示,"-a"参数表示显示所有补丁,"-l"参数显示补丁名。例如:

    $ quilt files

    src/drv/drv2.h

    $ quilt files -val

    [prj.diff] src/drv/drv1.h

    [prj.diff] src/sys/sys1.c

    [prj.diff] src/sys/sys1.h

    [prj.diff] src/usr/usr1.c

    [prj.diff] src/usr/usr1.h

    [drv_p1.diff] src/drv/drv2.h

    "quilt refresh [补丁名]"刷新补丁,即将指定补丁的文件变化保存到补丁。省略文件名表示刷新栈顶补丁。我们refresh后,查看补丁文件:

    $ quilt refresh

    Refreshed patch drv_p1.diff

    $ cat ../../patches/drv_p1.diff

    Index: prj/src/drv/drv2.h

    ===================================================================

    --- prj.orig/src/drv/drv2.h 2008-03-02 12:42:21.000000000 +0800

    +++ prj/src/drv/drv2.h 2008-03-02 12:46:25.000000000 +0800

    @@ -1,7 +1,7 @@

    -#ifndef APP1_H

    -#define APP1_H

    +#ifndef DRV2_H

    +#define DRV2_H

     

    -#include "def1.h"

    +#include "def2.h"

     

    #endif

     

    "quilt diff -z"命令不会显示已经保存的差异。"quilt diff"显示所有的差异,不管是否保存过。

    2.4 再做几个补丁

    在增加文件前,我们要先将准备增加的文件与补丁联系起来。我们新建一个补丁,然后新增两个文件src/applet/applet1.h和src/applet/applet1.c。

    $ cd ..; quilt new more_p1.diff

    Patch more_p1.diff is now on top

    $ quilt add applet/applet.c

    File src/applet/applet.c added to patch more_p1.diff

    $ quilt add applet/applet.1

    File src/applet/applet.1 added to patch more_p1.diff

     

    看看我们增加的文件:

    $ quilt files

    src/applet/applet.1

    src/applet/applet.c

     

    哎呀,文件名写错了。我们可以用"remove"命令从补丁中删除关联文件:

    $ quilt remove applet/applet.1

    rm: remove write-protected regular empty file `.pc/more_p1.diff/src/applet/applet.1'? y

    File src/applet/applet.1 removed from patch more_p1.diff

    $ quilt remove applet/applet.c

    rm: remove write-protected regular empty file `.pc/more_p1.diff/src/applet/applet.c'? y

    File src/applet/applet.c removed from patch more_p1.diff

    $ quilt files

    $ quilt add applet/applet1.h

    File src/applet/applet1.h added to patch more_p1.diff

    $ quilt add applet/applet1.c

    File src/applet/applet1.c added to patch more_p1.diff

    $ quilt files

    src/applet/applet1.c

    src/applet/applet1.h

     

    好了,现在可以创建新文件:

    $ mkdir applet

    $ echo -e "#ifndef APPLET1_H\n#define APPLET1_H\n#include \"def1.h\"\n#endif">applet/applet1.h

    $ echo -e "#include \"applet1.h\"">applet/applet1.c

    $ quilt refresh more_p1.diff

    Refreshed patch more_p1.diff

     

    刷新补丁后,我们再修改文件drv2.h。修改前一定要先将文件与准备保存改动的补丁联系起来:

    $ quilt add drv/drv2.h

    File src/drv/drv2.h added to patch more_p1.diff

    $ vi drv/drv2.h

    $ quilt diff -z drv/drv2.h

    Index: prj/src/drv/drv2.h

    ===================================================================

    --- prj.orig/src/drv/drv2.h 2008-03-02 14:19:35.000000000 +0800

    +++ prj/src/drv/drv2.h 2008-03-02 14:31:28.000000000 +0800

    @@ -1,7 +1,7 @@

    #ifndef DRV2_H

    #define DRV2_H

     

    -#include "def2.h"

    +#include "def1.h"

     

    #endif

     

    我们再新建一个补丁,然后删除两个文件。删除文件前也要先为文件建立关联:

    $ quilt new more_p2.diff

    Patch more_p2.diff is now on top

    $ quilt add app/*

    File src/app/app1.c added to patch more_p2.diff

    File src/app/app1.h added to patch more_p2.diff

    File src/app/app2.c added to patch more_p2.diff

    File src/app/app2.h added to patch more_p2.diff

    $ rm -rf app

    $ quilt refresh

    Refreshed patch more_p2.diff

     

    我们再修改applet/applet1.h:

    $ quilt edit applet/applet1.h

    File src/applet/applet1.h added to patch more_p2.diff

    $ quilt refresh

    Refreshed patch more_p2.diff

     

    "quilt edit"在调用"quilt add"后自动启动编辑器。用refresh命令刷新补丁。

    对了,前面为more_p1.diff修改drv2.h后还没有刷新呢。我们查看修改并刷新:

    $ quilt diff -z -P more_p1.diff

    Index: prj/src/drv/drv2.h

    ===================================================================

    --- prj.orig/src/drv/drv2.h 2008-03-02 14:19:35.000000000 +0800

    +++ prj/src/drv/drv2.h 2008-03-02 14:31:28.000000000 +0800

    @@ -1,7 +1,7 @@

    #ifndef DRV2_H

    #define DRV2_H

     

    -#include "def2.h"

    +#include "def1.h"

     

    #endif

     

    Warning: more recent patches modify files in patch more_p1.diff

    $ quilt refresh more_p1.diff

    More recent patches modify files in patch more_p1.diff. Enforce refresh with -f.

    $ quilt refresh -f more_p1.diff

    Refreshed patch more_p1.diff

    quilt会抱怨更新的补丁修改了补丁more_p1.diff的文件。这是在说more_p2.diff修改了applet1.h。我们知道这和我们要刷新的drv2.h没关系,所以可以用-f参数强制刷新。

    2.5 管理补丁

    series命令可以查看series文件中的补丁:

    $ quilt series

    prj.diff

    drv_p1.diff

    more_p1.diff

    more_p2.diff

    "quilt patches 文件名"显示修改了指定文件的所有补丁,例如:

    $ quilt patches drv/drv2.h

    drv_p1.diff

    more_p1.diff

    "quilt annotate 文件名"显示指定文件的修改情况,它会指出哪个补丁修改了哪一行。例如:

    $ quilt annotate drv/drv2.h

    1 #ifndef DRV2_H

    1 #define DRV2_H

     

    2 #include "def1.h"

    #endif

    1 drv_p1.diff

    2 more_p1.diff

    我们可以使用push和pop命令应用补丁或撤销补丁,例如:

    $ quilt pop -a

    Removing patch more_p2.diff

    Restoring src/app/app1.c

    Restoring src/app/app2.c

    Restoring src/app/app2.h

    Restoring src/app/app1.h

    Restoring src/applet/applet1.h

     

    Removing patch more_p1.diff

    Restoring src/drv/drv2.h

    Removing src/applet/applet1.h

    Removing src/applet/applet1.c

     

    Removing patch drv_p1.diff

    Restoring src/drv/drv2.h

     

    Removing patch prj.diff

    Restoring src/sys/sys1.c

    Restoring src/sys/sys1.h

    Restoring src/drv/drv1.h

    Removing src/usr/usr1.c

    Removing src/usr/usr1.h

    No patches applied

    $ quilt top

    No patches applied

    $ quilt next

    prj.diff

    $ quilt previous

    No patches applied

    "quilt pop -a"撤销所有补丁。top命令显示栈顶命令,即当前应用的最新的补丁。next命令显示下一个可以应用的补丁。previous显示上一条应用过的补丁。"push 补丁A"将从上到下依次应用所有早于补丁A的补丁,最后应用补丁A。例如:

    $ quilt push more_p1.diff

    Applying patch prj.diff

    patching file src/drv/drv1.h

    patching file src/sys/sys1.c

    patching file src/sys/sys1.h

    patching file src/usr/usr1.c

    patching file src/usr/usr1.h

    Applying patch drv_p1.diff

    patching file src/drv/drv2.h

    Applying patch more_p1.diff

    patching file src/applet/applet1.c

    patching file src/applet/applet1.h

    patching file src/drv/drv2.h

    Now at patch more_p1.diff

    $ quilt top

    more_p1.diff

    $ quilt next

    more_p2.diff

    $ quilt previous

    drv_p1.diff

    "quilt push -a"应用所有补丁:

    $ quilt push -a

    Applying patch more_p2.diff

    patching file src/app/app1.c

    patching file src/app/app1.h

    patching file src/app/app2.c

    patching file src/app/app2.h

    patching file src/applet/applet1.h

    Now at patch more_p2.diff

    "quilt graph -all"可以为栈顶补丁的依赖关系生成dot文件。Graphviz的dot可以根据dot文件产生图片,例如:

    $ quilt graph --all > ../../more_p2.dot

    $ cd ../..; dot -Tpng more_p2.dot -o more_p2.png

    2.6 发布补丁

    只要将patches目录打包发布就可以了。例如:

    $ cd prj; tar cvjf prj-0.1-patches.tar.bz2 patches; mv prj-0.1-patches.tar.bz2 ../..

    用户先下载、解压补丁包对应的源代码树:

    $ cd ../..; mkdir user; cd user; tar xvjf ../old-prj.tar.bz2; mv old-prj/ prj

    然后下载、解压补丁:

    $ cd ../..; tar xvjf prj-0.1-patches.tar.bz2; cd user/prj

    最后把补丁目录链接到源代码树的patches目录,然后应用所有补丁:

    $ ln -sfn ../../patches/ patches

    $ quilt push -a

    Applying patch prj.diff

    patching file src/drv/drv1.h

    patching file src/sys/sys1.c

    patching file src/sys/sys1.h

    patching file src/usr/usr1.c

    patching file src/usr/usr1.h Applying patch drv_p1.diff

    patching file src/drv/drv2.h

    Applying patch more_p1.diff

    patching file src/applet/applet1.c

    patching file src/applet/applet1.h

    patching file src/drv/drv2.h

    Applying patch more_p2.diff

    patching file src/app/app1.c

    patching file src/app/app1.h

    patching file src/app/app2.c

    patching file src/app/app2.h

    patching file src/applet/applet1.h

    Now at patch more_p2.diff

    3 结束语

    在上面的流程攻略中,我们演示了19个quilt命令:add, annotate, applied, diff, edit, files, graph, import, new, next, patches, pop, previous, push, refresh, remove, series, top, unapplied。

    本次Linux之旅到此结束,欢迎您再次参加Linux之旅,一起探索浩瀚的Linux世界。

    发表于 @ 2008年03月02日 21:47:00|评论(loading...)|编辑|收藏

    新一篇: GB18030编码研究以及GBK、GB18030与Unicode的映射 | 旧一篇: Linux之旅(1): diff, patch和quilt (上)

    评论

    #rastevil 发表于2008-05-06 15:52:27  IP: 218.80.82.*
    Nice!
    #htbegin 发表于2008-08-07 17:16:05  IP: 218.108.40.*
    很不错!
    #abbot 发表于2008-08-20 12:44:29  IP: 221.10.25.*
    very good!
    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © fmddlmyy