Linux Tour (1): diff, patch and quilt (lower) 2 quilt
We can use CVs or SVN to manage all code for our own projects. But sometimes we need to use projects maintained by other developers. We need to modify some files, but we cannot directly submit code to the version management tool. It is not appropriate to use version management tools to reconstruct the entire project, because most of the Code is maintained by others, such as the Linux kernel. We just want to manage our patches. In this case, you can use quilt.
2.1 Basic Concepts
Quilt is a program that helps us manage patches. The Command Format of quilt is similar to CVS:
Quilt subcommand [parameter]
Quilt of version 0.46 has 29 sub-commands.
The key to understanding quilt is to understand the process of using quilt. When using quilt, we will work in a complete source code tree. As long as we use the quilt command in the source code tree, quilt will create two special directories in the root directory of the source code tree: patches and. PC. Quilt saves all patches it manages in the patches directory. Quilt uses the. PC directory to save its internal working status. You do not need to know this directory.
The patches/series file records the patches currently managed by the quilt. Patches are arranged in the order they are added. The patches that are added earlier are in the first place. Quilt uses the concept of stack to manage patch applications.
Before applying patch a, we must apply all patches earlier than patch. Therefore, patches in patches/series are always applied from top to bottom. For example, patch 1 to patch 5 is an applied patch. We can think of an applied patch as a stack that grows down. The top of the stack is the latest patch that has been applied. An application patch is used to install the patch into the stack. An unpatched patch is used to install the patch out of the stack.
Before making ANY changes in the source code tree, we must use the "quilt Add" command to associate the file to be modified with a patch. After the modification is completed, run the "quilt refresh" command to save the modification to the associated patch. Next, let's take a look at the quilt command through a process strategy.
2.2 import Patches
We think of the old-prj.tar.bz2 as the Linux kernel, We decompress it and enter the root directory of the code tree:
$ Mkdir qtest; CD qtest; tar xvjf ../old-prj.tar.bz2; MV old-prj; CD prj
Before modifying the code, we usually need to install official patches first. In quilt, you can use the import command to import the patch:
$ Quilt import.../prj. Diff
Importing patch.../prj. Diff (stored as prj. Diff)
After the improt command is executed, the prj directory will contain a subdirectory named Patches:
$ Find patches/-type F
Patches/prj. Diff
Patches/series
Quilt stores all patches and series files in this directory. Most quilt commands can be run in any subdirectory of the code tree, not necessarily from the root directory. We can use the applied command to query the patches currently applied.
$ Quilt applied
No Patches applied
No Patches have been applied. The unapplied command queries patches that are not yet applied. The top command queries the top patch of the stack, that is, the latest patch applied:
$ Quilt unapplied
Prj. Diff
$ Quilt top
No Patches applied
We can use the push command to apply the patch, for example:
$ Quilt push-
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
The "-a" parameter of push indicates that all patches are applied. After the push command is used, the prj directory contains an implicit subdirectory named. PC. Quilt uses this directory to save the internal status. You do not need to know this directory. After applying the patch, we can use the applied, unapplied, and top commands to view the details:
$ Quilt applied
Prj. Diff
$ Quilt unapplied
File series fully applied, ends at patch prj. Diff
$ Quilt top
Prj. Diff
2.3 modify files
We must associate any changes made to the source code tree with a patch. The add command associates the current status of the file with the patch. The format of the add command is:
Quilt add [-P patch name] File Name
If no patch name is specified, the file is associated with the stack top patch. Currently, our stack top patch is an official patch. We don't want to modify this patch. We can use the new command to create a new patch:
$ 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
Then, run the Add command to add a file for modification to the stack top patch:
$ CD src/drv; quilt add drv2.h
File src/drv/drv2.h added to patch drv_p1.diff
The add command saves the current snapshot of the specified file for the specified patch. When we execute the refresh command, quilt checks the file changes and saves the differences to the specified patch. You can use "quilt diff-Z [-P patch name] [file name]" to view the current changes to the specified file of the specified patch. If the-p parameter is omitted, the current patch changes are viewed. If the file name is omitted, all changes are viewed. After modifying drv2.h, run the diff command:
$ Quilt diff-z
Index: prj/src/drv/drv2.h
========================================================== ======================================
--- Prj. orig/src/drv/drv2.h 13:37:34. 000000000 + 0800
++ Prj/src/drv/drv2.h 2008-03-02 13:38:53. 000000000 + 0800
@-+ @@
-# Ifndef app1_h
-# Define app1_h
+ # Ifndef drv2_h
+ # Define drv2_h
-# Include "def1.h" + # include "def2.h"
# Endif
As long as the file has been contacted with the patch we want to save the changes, we can modify the file multiple times. Run the "quilt files [Patch name]" command to view the files associated with the specified patch. Use "quilt files-Val" to view all the files of all patch contacts. "-V" indicates a more friendly display, "-a" indicates that all patches are displayed, and "-l" indicates the patch name. For example:
$ 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 [Patch name]" refresh the patch to save the file changes of the specified patch to the patch. If the file name is omitted, the top patch of the stack is refreshed. After refresh, check the patch file:
$ Quilt refresh
Refreshed patch drv_p1.diff
$ Cat.../patches/drv_p1.diff
Index: prj/src/drv/drv2.h
========================================================== ======================================
--- Prj. orig/src/drv/drv2.h 12:42:21. 000000000 + 0800
++ Prj/src/drv/drv2.h 2008-03-02 12:46:25. 000000000 + 0800
@-+ @@
-# Ifndef app1_h
-# Define app1_h
+ # Ifndef drv2_h
+ # Define drv2_h
-# Include "def1.h"
+ # Include "def2.h"
# Endif
The "quilt diff-z" command does not display the saved differences. "Quilt diff" shows all the differences, whether or not they are saved.
2.4 install several more patches
Before adding a file, we need to associate the file to be added with the patch. Create a new patch, and then add two files src/applet/applet1.h and 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. c Added to patch more_p1.diff
$ Quilt add applet/applet.1
File src/applet/applet.1 added to patch more_p1.diff
Look at the file we added:
$ Quilt files
Src/applet/applet.1
Src/applet. c
Oh, the file name is wrong. We can use the "Remove" command to delete the associated files from the patch:
$ 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. C '? Y
File src/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
Now you can create a new file:
$ 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
After the patch is refreshed, modify the file drv2.h. Before modification, you must first associate the file with the patch to be saved:
$ 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 14:19:35. 000000000 + 0800
++ Prj/src/drv/drv2.h 2008-03-02 14:31:28. 000000000 + 0800
@-+ @@
# Ifndef drv2_h
# Define drv2_h
-# Include "def2.h"
+ # Include "def1.h"
# Endif
Create a new patch and delete the two files. Before deleting an object, you must first establish an association for the object:
$ 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
Modify the 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" automatically starts the editor after "quilt Add" is called. Use the refresh command to refresh the patch.
By the way, the last modification to drv2.h for more_p1.diff has not been refreshed yet. Let's view the changes and refresh them:
$ Quilt diff-z-P more_p1.diff
Index: prj/src/drv/drv2.h
========================================================== ======================================
--- Prj. orig/src/drv/drv2.h 14:19:35. 000000000 + 0800
++ Prj/src/drv/drv2.h 2008-03-02 14:31:28. 000000000 + 0800
@-+ @@
# 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 will complain that the updated patch has modified the more_p1.diff file. This means that more_p2.diff modified applet1.h. We know this has nothing to do with the drv2.h to be refreshed, so we can use the-F parameter to force the refresh.
2.5 Patch Management
The series command can view the patches in the series file:
$ Quilt Series
Prj. Diff
Drv_p1.diff
More_p1.diff
More_p2.diff
"Quilt patches file name" displays all patches that have been modified for the specified file, for example:
$ Quilt patches drv/drv2.h
Drv_p1.diff
More_p1.diff
"Quilt annotate file name" shows the changes to the specified file. It indicates which patch has modified the row. For example:
$ 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
We can use the push and pop commands to apply or cancel the patch, for example:
$ Quilt pop-
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" undo all patches. The top command displays the TOP Command of the stack, which is the latest patch of the current application. The next command displays the next patch that can be applied. Previous displays the previous patch applied. "Push patch a" applies all patches earlier than patch a from top to bottom, and finally applies patch. For example:
$ 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" applies all patches:
$ Quilt push-
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" can generate a dot file for the dependency of the stack top patch. The dot of graphviz can generate images based on the dot file, for example:
$ Quilt graph -- all>.../more_p2.dot
$ Cd...; dot-tpng more_p2.dot-O more_p2.png
2.6 release patches
You only need to package and publish the patches directory. For example:
$ CD prj; tar cvjf prj-0.1-patches.tar.bz2 patches; MV prj-0.1-patches.tar.bz2 ../..
Download and decompress the source code tree corresponding to the patch package:
$ Cd...; mkdir user; CD user; tar xvjf ../old-prj.tar.bz2; MV old-prj/prj
Download and unzip the patch:
$ Cd...; tar xvjf prj-0.1-patches.tar.bz2; CD user/prj
Finally, link the patch directory to the patches directory of the source code tree and apply all the patches:
$ Ln-SFN.../../patches
$ Quilt push-
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 conclusion
In the previous procedure, we demonstrated 19 quilt commands: add, annotate, applied, diff, edit, files, graph, import, new, next, patches, Pop, previous, push, refresh, remove, series, top, unapplied.
This Linux tour ends now. You are welcome to join us on a Linux tour to explore the vast Linux World.