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

來源:互聯網
上載者:User
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世界。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.