From 3d34ac8a55a0eae80ae27490e2f459f510b3cbf7 Mon Sep 17 00:00:00 2001 From: Manuel Traut Date: Wed, 23 Mar 2011 00:07:52 +0100 Subject: kernel-best-practices: added diff, patch, quilt, git just the basics :) Signed-off-by: Manuel Traut --- .../handout_kernel-best-practices_en.tex | 498 +++++++++++++++++++++ 1 file changed, 498 insertions(+) create mode 100644 kernel-devel/kernel-best-practices/handout_kernel-best-practices_en.tex (limited to 'kernel-devel') diff --git a/kernel-devel/kernel-best-practices/handout_kernel-best-practices_en.tex b/kernel-devel/kernel-best-practices/handout_kernel-best-practices_en.tex new file mode 100644 index 0000000..bd1140b --- /dev/null +++ b/kernel-devel/kernel-best-practices/handout_kernel-best-practices_en.tex @@ -0,0 +1,498 @@ +\input{confighandout} + +\subsection{Kernel Best-Practices} + +Linux development is heavily distributed. There are many powerful tools, which +assist the distributed development. The most important and powerful ones, will +be presented in this chapter. + +\subsubsection{diff and patch - the basics} + +Linux kernel development is based on patches. A patch is a file which describes +the changes between an original version of a source tree and a modified one. + +For simplicity, a source tree with only one file will be used as example: + +orig/hello.c + +\begin{lstlisting} +int main (int argc, char **argv) +{ + return 0; +} +\end{lstlisting} + +This source tree will be copied: + +\begin{lstlisting} +cp -a orig new +\end{lstlisting} + +The new source tree be modified: + +new/hello.c + +\begin{lstlisting} +#include + +int main (int argc, char **argv) +{ + printf ("Huhu World\n"); + return 0; +} +\end{lstlisting} + +The diff commands generates a patch file: + +\begin{lstlisting} +diff -Nur orig new > hello.patch +\end{lstlisting} + +The content of hello.patch is: + +\begin{lstlisting} +--- orig/hello.c 2011-03-22 22:38:40.796426752 +0100 ++++ new/hello.c 2011-03-22 22:39:02.472155769 +0100 +@@ -1,4 +1,7 @@ ++#include ++ + int main (int argc, char **argv) + { ++ printf ("Huhu World\n"); + return 0; + } +\end{lstlisting} + +The newly added lines are prefixed with a '+', removed lines with a '-'. + +If the patch file is more complex, diffstat informs you about the content: + +\begin{lstlisting} +diffstat hello.patch + hello.c | 3 +++ + 1 file changed, 3 insertions(+) +\end{lstlisting} + +Anyone who has the original source version, can apply the generated patch. The +result is an updated version of the source tree: + +\begin{lstlisting} +cd orig +patch -p1 < ../hello.patch +\end{lstlisting} + +With the argument -pX the numbers of stripped directories (in our case new) can be defined. + +With the argument -R a patch can be 'reverse applied' aka removed. The result +will be the original source tree. + +Don't apply or remove the same patch more then once. If you have more than one +patch, apply and revert the patches in the right order. Else the resulting +source tree will be undefined. + +If the original source differs from the one, the patch was created. The patch +may apply with 'HUNKS'. This means, the changes can be applied, but the line +numbers, given after the @@@ tag don't fit exactly. + +If the original source differs from the one, the patch was created. It is +possible, that the patch won't apply anymore. Then all rejects are saved in a +file called .rej + +\subsubsection{quilt} + +diff and patch work fine for one patch. But if you have to handle a queuqe of +patches it will be hard to keep the order of the patches, update a single patch,etc. quilt is a tool, for managing patch queques. + +The above example, using quilt: + +orig/hello.c + +\begin{lstlisting} +int main (int argc, char **argv) +{ + return 0; +} +\end{lstlisting} + +create a new patch: + +\begin{lstlisting} +cd orig +quilt new hello.patch +quilt edit hello.c +\end{lstlisting} + +your default editor will be opened, make your changes to the source: + +\begin{lstlisting} +#include + +int main (int argc, char **argv) +{ + printf ("Huhu World\n"); + return 0; +} +\end{lstlisting} + +write the changes into the patch file: + +\begin{lstlisting} +quilt refresh +\end{lstlisting} + +two files will be generated: + +\begin{lstlisting} +ls patches/ +hello.patch series +\end{lstlisting} + +hello.patch is our well-known patch. series contains the name of our patch. + +The patch can be applied + +\begin{lstlisting} +quilt push +File series fully applied, ends at patch patches/hello.patch +\end{lstlisting} + +Then we create a new patch on top of our current queque: + +\begin{lstlisting} +quilt new seperate-print-in-own-function.patch +quilt edit hello.c +\end{lstlisting} + +\begin{lstlisting} +#include + +void print () +{ + printf ("Huhu World\n"); +} + +int main (int argc, char **argv) +{ + print (); + return 0; +} +\end{lstlisting} + +both patches are now listed in the series file: + +\begin{lstlisting} +cat patches/series +hello.patch +seperate-print-in-own-function.patch +\end{lstlisting} + +All patches can be reverted at once: + +\begin{lstlisting} +quilt pop -a +Removing patch patches/seperate-print-in-own-function.patch +Restoring hello.c + +Removing patch patches/hello.patch +Restoring hello.c + +No patches applied +\end{lstlisting} + +You can zip the quilt queque and share it with other programmers. + +\subsubsection{git} + +But if they modify the quilt queque at the same time, as you. Merging the +queques by hand may be hard. In projects like the linux kernel, it is a no go. + +Currently Linus' (and many others) Kernel trees are managed by git. Git is a +very powerful version control system. The most important difference to other +systems, like subversion, is that the hole history of a project is held local. +Nobody should commit into your git tree. In git you pull the changes from other +people into your tree. + +Let's have a look at git: + +orig/hello.c + +\begin{lstlisting} +int main (int argc, char **argv) +{ + return 0; +} +\end{lstlisting} + +init git: + +\begin{lstlisting} +$cd orig +$git init . +Initialized empty Git repository in /home/manut/vorlesung.git/orig/.git/ +$git config user.email "manut@mecka.net" +$git config user.name "Manuel Traut" +\end{lstlisting} + +The configuration is saved at .git/config +If git config --global is used the configuration will be used by all +repositories which don't have a own configuration. Then it is saved at +~/.gitconfig + +Now add the files to version control and commit your initial code. + +\begin{lstlisting} +$git add hello.c +$git commit -sa +\end{lstlisting} + +The default editor will be opened, to enter a commit message: + +\begin{lstlisting} +initial import of the hello world source + +this projects is aimed to show the use of git. + +Signed-off-by: Manuel Traut + +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit. +# On branch master +# +# Initial commit +# +# Changes to be committed: +# (use "git rm --cached ..." to unstage) +# +# new file: hello.c +# + +[master (root-commit) 473cf10] initial import of the hello world source + 1 files changed, 4 insertions(+), 0 deletions(-) + create mode 100644 hello.c + +\end{lstlisting} + +Now edit the source tree and generate commit your changes: + +\begin{lstlisting} +$patch -p1 < ../hello.patch +$git commit -sa + +add stdio include, print hello world + +prints 'Huhu World' to stdout + +Signed-off-by: Manuel Traut + +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit. +# On branch master +# Changes to be committed: +# (use "git reset HEAD ..." to unstage) +# +# modified: hello.c + +[master 6ea27e6] add stdio include, print hello world + 1 files changed, 3 insertions(+), 0 deletions(-) + +\end{lstlisting} + +A hash will be generated that can be used to identify each patch. A history +and a single patch can be displayed with these commands: + +\begin{lstlisting} +$git log +commit 6ea27e6199aeac63055d845ef40fecd4b594f1d7 +Author: Manuel Traut +Date: Tue Mar 22 23:37:13 2011 +0100 + + add stdio include, print hello world + + prints 'Huhu World' to stdout + + Signed-off-by: Manuel Traut + +commit 473cf10e95778c54d49fc6ea368e196f1347ac8a +Author: Manuel Traut +Date: Tue Mar 22 23:31:50 2011 +0100 + + initial import of the hello world source + + this projects is aimed to show the use of git. + + Signed-off-by: Manuel Traut + + +$git shortlog +Manuel Traut (2): + initial import of the hello world source + add stdio include, print hello world + +$git show 473cf10e95778c54d49fc6ea368e196f1347ac8a +commit 473cf10e95778c54d49fc6ea368e196f1347ac8a +Author: Manuel Traut +Date: Tue Mar 22 23:31:50 2011 +0100 + + initial import of the hello world source + + this projects is aimed to show the use of git. + + Signed-off-by: Manuel Traut + +diff --git a/hello.c b/hello.c +new file mode 100644 +index 0000000..b891504 +--- /dev/null ++++ b/hello.c +@@ -0,0 +1,4 @@ ++int main (int argc, char **argv) ++{ ++ return 0; ++} + +\end{lstlisting} + +To add some new functionality it's a good idea to temporarily create a new +branch: + +\begin{lstlisting} +$git branch fancy-new-stuff +$git checkout fancy-new-stuff +Switched to branch 'fance-new-stuff' +\end{lstlisting} + +It's possible to go back in history: + +\begin{lstlisting} +git reset --hard 473cf10e95778c54d49fc6ea368e196f1347ac8a +HEAD is now at 473cf10 initial import of the hello world source +\end{lstlisting} + +Make changes: + +\begin{lstlisting} +#include + +int main (int argc, char **argv) +{ + printf ("Hello World\n"); + return 0; +} +\end{lstlisting} + +and commit them: + +\begin{lstlisting} +$git commit -sa + +HELLO world + +..not huhu world + +Signed-off-by: Manuel Traut + +[fance-new-stuff 72e3346] HELLO world + 1 files changed, 3 insertions(+), 0 deletions(-) + +\end{lstlisting} + +You like the new version and want to merge it into your master tree: + +\begin{lstlisting} +$git checkout master +Switched to branch 'master' +$git merge fancy-new-stuff +Auto-merging hello.c +CONFLICT (content): Merge conflict in hello.c +Automatic merge failed; fix conflicts and then commit the result. +\end{lstlisting} + +Git reports an CONFLICT because an automatic merge is not possible. The same +line (printf) has different content in master and fancy-new-stuff. So the merge +conflict has to be resolved by hand. + +hello.c + +\begin{lstlisting} +#include + +int main (int argc, char **argv) +{ +<<<<<<< HEAD + printf ("Huhu World\n"); +======= + printf ("Hello World\n"); +>>>>>>> fancy-new-stuff + return 0; +} +\end{lstlisting} + +All lines which shouldn't be there can be removed by hand. This result needs +to be commited: + +\begin{lstlisting} +$git commit -sa + +Merge branch 'fance-new-stuff' + +Conflicts: + hello.c + +Signed-off-by: Manuel Traut +# +# It looks like you may be committing a MERGE. +# If this is not correct, please remove the file +# .git/MERGE_HEAD +# and try again. +# + +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit. +# On branch master +# Changes to be committed: +# +# modified: hello.c +# + +[master 1815151] Merge branch 'fance-new-stuff' + +$git log + +commit 1815151a08537bd2403605f8adb22852cfdb2d23 +Merge: 6ea27e6 72e3346 +Author: Manuel Traut +Date: Tue Mar 22 23:57:19 2011 +0100 + + Merge branch 'fance-new-stuff' + + Conflicts: + hello.c + + Signed-off-by: Manuel Traut + +commit 72e3346872ec9298f2b582e2859b1dbf1304f77e +Author: Manuel Traut +Date: Tue Mar 22 23:49:58 2011 +0100 + + HELLO world + + ..not huhu world + + Signed-off-by: Manuel Traut + +... +\end{lstlisting} + +Further exercises: + +\begin{itemize} +\item pull from another repository +\item track a repository +\item what is a bare repository? +\item find bugs with git bisect +\item extract a patch queque from your git branch +\item send mails with git +\item build a svn - git bridge +\end{itemize} + +\input{tailhandout} -- cgit v1.2.3