[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Les commandes diff et patch (Was: Patch)



MILIN Jacques wrote:

> j'ai un pb lorque j'essaie d'ajouter un patch à un fichier source. je
> tape les commandes suivantes:
> 
> %patch < /"nom du fichier"
> Le systeme repond : "The next patch would create the file
> 'Makefile.in',which already exists! Assumes -R? [n].
> 
> Je reponds y mais il ne prend pas en compte le patch ... alors si
> quelqu'un peut me sortir de cette me..

Il faudrait regarder le source du patch pour pouvoir répondre à ton
problème de manière spécifique.  Comme je ne l'ai pas, je vais te
détailler le mécanisme usuel de la combinaison diff/patch.


Un patch est généré à partir de la commande `diff' entre la version
originale et la version corrigée.  Généralement, le diff est généré à
partir de deux arboressences, c'est un diff récursif (diff -r).

Pour être exploité efficassement, le fichier diff doit contenir, en plus
des lignes modifiées, le contexte de chaque modification.  Celà permet
au programme patch de se resynchroniser si un fichier est déja modifié
localement.  Pour générer un patch au format ``context diff'' il faut
utiliser l'option -c, mais il est préférable d'utiliser le format
``unified'' avec option -u, qui est tout aussi informatif mais plus
condensé et plus façilement lisible par un humain.

Si tu as supprimé ou ajouté un fichier entre les deux versions, il
faudra que tu ajoutes l'option -N pour les prendre en compte.  Sans
cette option tu n'auras que `Only foo in directory bar', qui ne
permettra de supprimer ou de créer ces fichiers.


Voici un exemple partiel d'un diff -ru que je vais utilisé dans la suite
de mes explications:

    diff -ru id-utils-3.2d/libidu/id-lang.map id-utils-3.2d-egp2/libidu/id-lang.map
    --- id-utils-3.2d/libidu/id-lang.map	Fri Apr 18 08:43:30 1997
    +++ id-utils-3.2d-egp2/libidu/id-lang.map	Fri Jan 28 10:14:03 2000
    @@ -52,6 +52,8 @@
     *.cpp			C++
     *.cxx			C++
     
    +*.java			Java
    +
     ChangeLog*		Cdoc
     
     *.[sS]			asm --comment=;
    @@ -71,7 +73,10 @@
     # portable object (i18n)
     *.po			po
     
    -*.el			elisp
    +*.el			lisp
    +*.elc			lisp
    +*.lisp			lisp
    +*.scm			lisp
     
     *.am			make
     Makefile		make

La première ligne (qui n'est pas obligatoire, elle est d'ailleur
supprimée par dpkg-source -b) reprend les options passées à la commande
diff, ici `-ru'.  Les lignes suivantes (--- et +++) indiquent le fichier
d'origine et le fichier corrigé.  Vient ensuite une définition de
paragraphe @@ -52,6 +52,8 @@ suivie par les modifications à appliquer et
une deuxième définition de paragraphe @@ -71,7 +73,10 @@ et ses
modifications.

En claire, le second paragraphe commence à la ligne 71 dans le fichier
original (---) et porte sur 7 lignes.  Dans le nouveau fichier (+++), il
commence à la ligne 73 et porte sur 10 lignes.  Ce paragraphe contient
des lignes non modifiées (le premier caractère de ces lignes est un
espace) elles servent de contexte, une ligne supprimée (commence par -)
et quatres lignes ajoutées (introduites par +).  Ces informations sont
utiles pour résoudre à la main un rejet.


Si j'applique simplement ce patch par `patch < exemple.diff' dans le
répertoire id-utils-3.2d, je vais avoir ce résulta:

    can't find file to patch at input line 1
    Perhaps you should have used the -p or --strip option?
    The text leading up to this was:
    --------------------------
    |diff -ru id-utils-3.2d/libidu/id-lang.map id-utils-3.2d-egp2/libidu/id-lang.map
    |--- id-utils-3.2d/libidu/id-lang.map   Fri Apr 18 08:43:30 1997
    |+++ id-utils-3.2d-egp2/libidu/id-lang.map      Fri Jan 28 10:14:03 2000
    --------------------------
    File to patch: 

Mais si je me place dans le répertoire libidu, le patch sera appliqué
correctement.  En fait, il faut indiqué le niveau de répertoire à
ignorer avec l'option -p num.  Sans cette option, le fichier id-lang.map
est sensé se trouver dans le répertoire courrant.  Ici, en me placant
dans le répertoire id-utils-3.2d, j'aurai dû utiliser `patch -p1'.

Passons maintenant à un patch contenant des modifications pour les
fichiers pkg/Makefile.in, pkg/foo/Makefile.in et pkg/bar/Makefile.in.
Sans l'option -p1, c'est le _même_ fichier Makefile.in du répertoire
courrant qui sera modifié, je pense que c'est ce qui t'es arrivé.


En conclusion, pour créer mes fichiers patch, j'utilise `diff -ru' (ou
`diff -ruN' lorsque j'ai ajouté ou supprimé un fichier).

Et voici _la_ commande patch que j'utilise 99% du temps:

    $ patch -p1 -s -N -E < le-fichier-patch

J'utilise l'option -R en plus pour le 1% restant lorsque je souhaite
annuler un patch, ou pour appliquer un patch fait à l'envers.

Mais attention, il faut _toujours_ regarder le source du patch pour
choisir le bon niveau de répertoire à ignorer.


En fait, comme je suis faignant, je me suis écrit le script zpatch
suivant:

    #!/bin/sh
    patchfile="$1"; shift
    case "$patchfile" in
	*.gz) uncomp="gzip -dc";;
	*.bz2) uncomp="bzip2 -dc";;
	*) uncomp="cat";;
    esac
    $uncomp "$patchfile" | patch -p1 -s -N -E "$@"

Que j'utilise simplement par

    $ zpatch le-fichier-patch

ou par

    $ zpatch le-fichier-patch -p2


Voila, bon patch :-)
-- 
Edouard G. Parmelan
http://egp.free.fr



Reply to: