`
saybody
  • 浏览: 902541 次
  • 性别: Icon_minigender_2
  • 来自: 西安
文章分类
社区版块
存档分类
最新评论

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世界。

分享到:
评论

相关推荐

    quilt patch管理

    ### Quilt Patch Management详解 #### 引言 随着开源项目的不断发展与完善,针对特定需求而进行的定制化修改变得越来越普遍。这些修改通常通过补丁(patch)的形式应用于原始源码之上,以此来适应不同的环境或功能...

    Quilt使用入门介绍.pdf

    lxy@lxy-PC:~/quilt_exercise$ quilt new int-1.diff Patch patches/int-1.diff is now on top 2. 查看当前栈顶补丁文件 lxy@lxy-PC:~/quilt_exercise$ quilt top patches/int-1.diff 3. 将指定文件与当前栈顶...

    openwrt 制作patch

    该文件中包含diff和patch的相关选项。 - 配置Quilt的命令示例如下: ``` cat>~/.quiltrc QUILT_DIFF_ARGS="--no-timestamps --no-index --color=auto" QUILT_REFRESH_ARGS="--no-timestamps --no-index" QUILT...

    quilt-0.46

    Quilt 是一个在 Linux 环境中广泛使用的补丁管理工具,特别是在系统维护和软件开发过程中。它的主要功能是帮助用户管理和应用一系列的文本差异(即补丁),这些差异通常用于更新或修改源代码。在Linux环境中,尤其是...

    quilt-0.48.tar.gz

    `quilt`是一款非常实用的补丁管理工具,它主要用于处理和应用Unix/Linux系统的文本文件补丁。在标题提到的`quilt-0.48.tar.gz`文件中,我们看到的是`quilt`工具的0.48版本,这个版本是为Ubuntu操作系统量身定制的。 ...

    Python-Quilt一个数据包管理器像管理代码那样管理数据

    Python-Quilt 是一个专为此目的设计的数据包管理器,它借鉴了软件工程中的代码管理理念,使得数据可以像代码一样被版本控制、共享和复用。通过Python接口,用户能够轻松地组织、检索和分发大数据集,极大地提高了...

    Python库 | quilt3-3.3.0-py3-none-any.whl

    在Python的生态系统中,有许多库用于处理不同任务,quilt3就是其中之一,它专注于提供一个简单、高效的方式来组织和分发大量的数据文件。 Quilt3库的版本3.3.0是为Python 3设计的,"py3-none-any"表明这个whl文件是...

    Quilt使用入门介绍.docx

    你可以使用`quilt previous`和`quilt next`来查看已应用的补丁和下一个待应用的补丁。`quilt applied`和`quilt unapplied`分别用于查看已应用和未应用的补丁列表。 在使用Quilt时,`quilt new`命令用于创建一个新的...

    bbb-preempt-rt-kernel-patch::gear: BeagleBone Black PREEMPT RT 补丁使用 OSADL 补丁和 linux 3.12

    您只需要运行sudo ./bbb-patch.sh start /dev/sdb /dev/sdb 使用所需的设备更改 /dev/sdb工作流程bbb-patch 脚本将: 下载 linux 内核 3.12 和 debian 镜像 (requeriments.sh) 在 Linux 源 (osadl-patch.sh) 上应用...

    Linux Kernel In A Nutshell.pdf

    - **使用quilt管理补丁**:介绍如何使用quilt工具高效地管理和应用补丁文件。 - **git版本控制系统**:概述了如何使用git来跟踪和管理内核源代码的变更。 - **ketchup工具**:介绍了一种用于自动更新内核源代码至...

    quilt:Hyperledger Quilt-Interledger协议的实现

    为问题加上标签和前缀,以便于识别与之相关的项目。ilp核心 ilp-core模块是任何Interledger Java项目的基础库,提供支持ILPv4协议(在定义)的服务接口,数据包定义和数据模型。 这些原语构成Interledger协议套件的...

    linux 2.4.18补丁

    - **Quilt**:一个工具集,用于管理和应用 Linux 内核补丁集。Quilt 提供了一种更有效的方式处理复杂的补丁集,特别是在开发过程中需要频繁地添加或移除补丁时。 - **Ramdisk**:一种基于内存的临时文件系统,通常...

    Linux深入浅出系统移植

    理解如何应用和管理补丁,使用 quilt 或 git-patch 等工具是必要的技能。 4. **编译环境配置**:编译环境的设置对于成功移植至关重要。这包括配置内核选项,比如裁剪不必要的模块,以适应目标板的资源限制;设置...

    Quilt-开源

    1. 将Quilt库添加到你的项目依赖中。 2. 配置你的构建脚本(如Ant的build.xml或Maven的pom.xml),以便在执行测试时调用Quilt。 3. 运行测试,Quilt会收集覆盖率数据。 4. 分析生成的覆盖率报告,了解测试的全面性和...

    PyPI 官网下载 | quilt3-3.5.0-py3-none-any.whl

    与传统的源代码包(.tar.gz或.zip)不同,.whl文件可以直接被pip安装,无需编译步骤,这大大提高了安装速度和成功率,特别是在跨平台或有特定环境需求的场景下。 Quilt3是一个强大的数据包管理工具,它借鉴了软件...

    PyPI 官网下载 | quilt-2.8.4-py3-none-any.whl

    它提供了一种简洁的方法来组织、存储和共享大型数据集,使得团队成员可以在不离开 Python 环境的情况下访问这些数据。通过 Quilt,你可以创建数据包,每个包都包含元数据、数据文件和文档,确保数据的可重复使用性...

    PyPI 官网下载 | quilt-lang-0.4.6.tar.gz

    **PyPI 官网下载 | quilt-lang-0.4.6.tar.gz** PyPI(Python Package Index)是Python开发者发布和获取Python软件包的主要平台。`quilt-lang-0.4.6.tar.gz`是一个从PyPI官网下载的压缩文件,它包含了一个名为`quilt...

    Linux Kernel in a Nutshell--linux kernel技术手册

    - **使用quilt管理补丁**:方便地管理和应用多个补丁。 - **git**:分布式版本控制系统,用于跟踪源代码的变化。 - **ketchup**:一种自动化内核更新工具。 ##### 7.2 参考文献 - 提供了进一步阅读的相关书籍和...

Global site tag (gtag.js) - Google Analytics