« Utiliser diff et patch » : différence entre les versions
Aucun résumé des modifications |
m (Mise en forme) |
||
Ligne 1 : | Ligne 1 : | ||
Qui n'a jamais eu besoin de | Qui n'a jamais eu besoin de trouver, ou bien de mémoriser ''uniquement'' les modifications apportées à un fichier pour pouvoir ensuite les réappliquer à volonté ? | ||
Heureusement, Linux dispose comme très souvent d'outils tous prêts pour régler ce souci : '''diff''' et '''patch''' | |||
Bien que ces outils soient le plus souvent associés à la programmation (pour gérer les fameux « patches » sur le code source), avec un tout petit peu d'imagination ils peuvent également être mis à profit pour simplifier l'utilisation quotidienne de votre machine. | |||
Un exemple serait de conserver des modifications apportées à un fichier de configuration ('''diff'''), pour pouvoir les réappliquer à la nouvelle version de ce fichier après une mise à jour ('''patch''').<br /> | |||
Ou tout simplement, comparer deux fichiers ('''diff''' uniquement). | |||
= Installer les paquets nécessaires = | |||
Les deux paquets à installer sont '''[[Paquet::diffutils]]''' et '''[[Paquet::patch]]''' : | |||
<pre> | |||
Les deux paquets à installer sont '''[[Paquet::diffutils]]''' et '''[[Paquet::patch]]''' | # aptitude install diffutils patch | ||
<pre># aptitude install diffutils patch | |||
</pre> | </pre> | ||
= Comparer deux fichiers avec diff | = Comparer deux fichiers avec diff = | ||
La commande '''[[Commande::diff]]''', comme son nom l'indique, permet d'afficher les différences entre deux fichiers semblables (généralement entre deux versions d'un même fichier). | La commande '''[[Commande::diff]]''', comme son nom l'indique, permet d'afficher les différences entre deux fichiers semblables (généralement entre deux versions d'un même fichier). | ||
Comme exemple, nous prendrons les deux fichiers suivants | Comme exemple, nous prendrons les deux fichiers suivants : | ||
<pre>$ cat ancien-fichier | <pre> | ||
$ cat ancien-fichier | |||
ceci | ceci | ||
n'est | n'est | ||
Ligne 28 : | Ligne 29 : | ||
grand | grand | ||
intérêt | intérêt | ||
</pre> | |||
<pre> | |||
$ cat nouveau-fichier | $ cat nouveau-fichier | ||
ceci | ceci | ||
Ligne 39 : | Ligne 41 : | ||
intérêt | intérêt | ||
</pre> | </pre> | ||
Et la comparaison ('''diff''') des deux, | Et la comparaison ('''diff''') des deux, qui permet de visualiser très rapidement et de manière extrêmement claire les différences :<br /> | ||
<pre>$ diff -u ancien-fichier nouveau-fichier | <pre> | ||
$ diff -u ancien-fichier nouveau-fichier | |||
--- ancien-fichier 2010-04-27 23:53:41.948385552 +0200 | --- ancien-fichier 2010-04-27 23:53:41.948385552 +0200 | ||
+++ nouveau-fichier 2010-04-27 23:54:12.552109974 +0200 | +++ nouveau-fichier 2010-04-27 23:54:12.552109974 +0200 | ||
Ligne 56 : | Ligne 59 : | ||
intérêt | intérêt | ||
</pre> | </pre> | ||
L'option '''-u''' permet d'obtenir ce qu'on appelle un ''diff unifié'', le format le plus couramment utilisé. | L'option '''-u''' permet d'obtenir ce qu'on appelle un ''diff unifié'', le format le plus couramment utilisé. | ||
Ce qui saute immédiatement aux yeux, | Ce qui saute immédiatement aux yeux, ce sont les signes + et - (ou leur absence) en début de lignes. | ||
Votre intuition ne vous trompe pas : les signes - marquent les lignes ayant été supprimées lors du passage de '''ancien-fichier''' à '''nouveau-fichier''', et les signes + les lignes ayant été rajoutées. Les lignes commençant par un espace n'ont tout simplement pas été modifiées, et sont incluses pour fournir un minimum de contexte aussi bien aux humains qui liraient ce résultat, qu'à la commande '''patch''' chargée d'appliquer automatiquement ces modifications à un troisième fichier, même s'il est légèrement différent des deux autres (dans une certaine limite, bien sûr). | |||
Deuxième point remarquable : les lignes commençant par '''@@''' indiquent les numéros de lignes correspondant au bloc de modifications qui se trouve à la suite, pour aider la commande '''patch''' à s'y retrouver.<br /> | |||
Leur format n'a pas grande importance pour un être humain, tout ce qu'il y a à savoir c'est que le premier chiffre (dans cet exemple, -1) identifie dans '''ancien-fichier''' la ligne précédant immédiatement la première ligne de contexte (ici, « ''ceci'' » qui se trouve être la première ligne du fichier, c'est à dire la ligne n° 0). | |||
Dernière chose, un ''diff unifié'' commence toujours par les deux lignes --- et +++ qui indiquent le nom et l'heure de modification des deux fichiers comparés. | |||
La commande diff affiche par défaut son résultat dans la console. Si l'on veut sauvegarder ce résultat sur le disque dur, il suffit donc de rediriger la sortie vers un fichier | = Sauvegarder des modifications pour usage ultérieur (créer un « patch ») = | ||
<pre>$ diff -u ancien-fichier nouveau-fichier > fichier.diff | |||
La commande diff affiche par défaut son résultat dans la console.<br /> | |||
Si l'on veut sauvegarder ce résultat sur le disque dur, il suffit donc de rediriger la sortie vers un fichier : | |||
<pre> | |||
$ diff -u ancien-fichier nouveau-fichier > fichier.diff | |||
</pre> | </pre> | ||
À quoi sert de sauvegarder un jeu de modifications si on ne le réutilise pas après | = Appliquer des modifications (un « patch ») à un fichier = | ||
<pre>$ patch -i fichier.diff troisieme-fichier | |||
À quoi sert de sauvegarder un jeu de modifications si on ne le réutilise pas après ?… | |||
<pre> | |||
$ patch -i fichier.diff troisieme-fichier | |||
</pre> | </pre> | ||
ou bien, en utilisant les redirections du shell (exemple simplifié avec '''cat''', uniquement pour montrer la syntaxe '''patch''' correspondante) | ou bien, en utilisant les redirections du shell (exemple simplifié avec '''cat''', uniquement pour montrer la syntaxe '''patch''' correspondante) : | ||
<pre>$ cat fichier.diff | patch troisieme-fichier | <pre> | ||
$ cat fichier.diff | patch troisieme-fichier | |||
</pre> | </pre> | ||
Ceci va tout simplement appliquer les modifications contenues dans '''fichier.diff''' au fichier '''troisieme-fichier'''. Si, comme on est en droit de s'y attendre dans le monde réel, '''troisieme-fichier''' a subi des modifications par rapport à '''ancien-fichier''', la commande '''patch''' dispose d'un algorithme pour résoudre, dans la mesure du possible, les ''conflits'' entre les différentes versions. | Ceci va tout simplement appliquer les modifications contenues dans '''fichier.diff''' au fichier '''troisieme-fichier'''.<br /> | ||
Si, comme on est en droit de s'y attendre dans le monde réel, '''troisieme-fichier''' a subi des modifications par rapport à '''ancien-fichier''', la commande '''patch''' dispose d'un algorithme pour résoudre, dans la mesure du possible, les ''conflits'' entre les différentes versions. | |||
Si par malheur '''patch''' n'arrive pas à ''réconcilier'' les différentes versions, il : | |||
*vous en préviendra<br /> | |||
*créera un fichier '''troisieme-fichier.orig''' contenant l'original de '''troisieme-fichier''' avant toute modification<br /> | |||
*appliquera tout de même le maximum de modifications possible<br /> | |||
*créera un fichier '''troisieme-fichier.rej''' contenant le ''diff unifié'' des modifications ayant été ''rejetées'' pour cause de ''conflit'' | |||
À partir de là, charge à vous de revenir à la bonne vieille méthode consistant à comparer et corriger les différences « manuellement », avec tout de même l'avantage de disposer du '''.diff''' (en l'occurrence, le '''.rej''' est plus utile) pour vous guider dans vos recherches. | |||
= Annuler les modifications contenues dans un « patch » = | |||
Si pour une raison quelconque vous souhaitez faire le chemin inverse (obtenir '''ancien-fichier''' alors que vous n'avez plus que '''nouveau-fichier''' et '''fichier.diff''') il suffit d'inverser le patch à l'aide de l'option '''-R''' : | |||
<pre> | |||
Si pour une raison quelconque vous souhaitez faire le chemin inverse (obtenir '''ancien-fichier''' alors que vous n'avez plus que '''nouveau-fichier''' et '''fichier.diff''') il suffit d'inverser le patch à l'aide de l'option '''-R''' | $ cp nouveau-fichier ancien-fichier | ||
<pre>$ cp nouveau-fichier ancien-fichier | |||
$ patch -R -i fichier.diff ancien-fichier | $ patch -R -i fichier.diff ancien-fichier | ||
</pre> | </pre> | ||
= Plus d'options = | = Plus d'options = | ||
'''diff''' et '''patch''' proposent une flopée d'options supplémentaires permettant de contrôler de nombreux aspects des algorithmes de comparaison ('''diff''') et de fusion ('''patch'''). Pour tout savoir | '''diff''' et '''patch''' proposent une flopée d'options supplémentaires permettant de contrôler de nombreux aspects des algorithmes de comparaison ('''diff''') et de fusion ('''patch''').<br /> | ||
<pre>$ man diff | Pour tout savoir : | ||
<pre> | |||
$ man diff | |||
$ man patch | $ man patch | ||
</pre> | </pre> | ||
Je viens d'installer le paquet '''foobar''' qui fournit le fichier de configuration '''/etc/foobar'''. Et bien entendu j'ai besoin de personnaliser ce dernier. | = Exemple pratique (scénario de gestion des fichiers de configuration) = | ||
Je viens d'installer le paquet '''foobar''' qui fournit le fichier de configuration '''/etc/foobar'''. Et bien entendu j'ai besoin de personnaliser ce dernier. | |||
Première étape, en faire une copie de sauvegarde | Première étape, en faire une copie de sauvegarde : | ||
<pre># cd /etc/ | <pre> | ||
# cd /etc/ | |||
# cp foobar foobar~backup</pre> | # cp foobar foobar~backup | ||
J'édite '''/etc/foobar''' à ma convenance, et une fois la configuration validée je crée le patch pour conserver soigneusement ces modifications (et ''uniquement'' ces modifications) | </pre> | ||
<pre># diff -u foobar~backup foobar > foobar.diff | J'édite '''/etc/foobar''' à ma convenance, et une fois la configuration validée je crée le patch pour conserver soigneusement ces modifications (et ''uniquement'' ces modifications) : | ||
<pre> | |||
# diff -u foobar~backup foobar > foobar.diff | |||
</pre> | </pre> | ||
À ce stade, la copie de sauvegarde n'est plus nécessaire, on peut la supprimer | À ce stade, la copie de sauvegarde n'est plus nécessaire, on peut la supprimer : | ||
<pre># rm foobar~backup | <pre> | ||
# rm foobar~backup | |||
</pre> | </pre> | ||
<br> | Le temps passe, et vient le moment où le paquet '''foobar''' est mis à jour et où '''apt''' me demande quoi faire à propos du fichier de configuration modifié (conserver / écraser / examiner la situation en shell).<br /> | ||
Afin de m'assurer de conserver mes modifications tout en bénéficiant également des nouvelles modifications distribuées avec la mise à jour, je vais aller examiner la situation en shell et faire la fusion avec mes petites mains à moi. | |||
Pour vérifier les différences entre ma version et la nouvelle version, vous l'aurez deviné | Pour vérifier les différences entre ma version et la nouvelle version, vous l'aurez deviné : | ||
<pre># cd /etc/ | <pre> | ||
# cd /etc/ | |||
# diff -u foobar foobar.dpkg-new | # diff -u foobar foobar.dpkg-new | ||
</pre> | </pre> | ||
Pour appliquer mes modifications personnelles à la nouvelle version (toujours en faisant une copie de sauvegarde avant...) | Pour appliquer mes modifications personnelles à la nouvelle version (toujours en faisant une copie de sauvegarde avant...) : | ||
<pre># cp foobar foobar~backup.working | <pre> | ||
# cp foobar foobar~backup.working | |||
# cp foobar.dpkg-new foobar | # cp foobar.dpkg-new foobar | ||
Ligne 134 : | Ligne 155 : | ||
# patch -i foobar.diff foobar | # patch -i foobar.diff foobar | ||
</pre> | </pre> | ||
Sortir ensuite du shell ('''exit''') puis sélectionner l'option '''apt''' « | Sortir ensuite du shell ('''exit''') puis sélectionner l'option '''apt''' « conserver mon fichier de configuration et ignorer celui du paquet ». | ||
[[Utilisateur:Syam]] | [[Utilisateur:Syam]] |
Version du 16 octobre 2016 à 13:17
Qui n'a jamais eu besoin de trouver, ou bien de mémoriser uniquement les modifications apportées à un fichier pour pouvoir ensuite les réappliquer à volonté ?
Heureusement, Linux dispose comme très souvent d'outils tous prêts pour régler ce souci : diff et patch
Bien que ces outils soient le plus souvent associés à la programmation (pour gérer les fameux « patches » sur le code source), avec un tout petit peu d'imagination ils peuvent également être mis à profit pour simplifier l'utilisation quotidienne de votre machine.
Un exemple serait de conserver des modifications apportées à un fichier de configuration (diff), pour pouvoir les réappliquer à la nouvelle version de ce fichier après une mise à jour (patch).
Ou tout simplement, comparer deux fichiers (diff uniquement).
Installer les paquets nécessaires
Les deux paquets à installer sont diffutils et patch :
# aptitude install diffutils patch
Comparer deux fichiers avec diff
La commande diff, comme son nom l'indique, permet d'afficher les différences entre deux fichiers semblables (généralement entre deux versions d'un même fichier).
Comme exemple, nous prendrons les deux fichiers suivants :
$ cat ancien-fichier ceci n'est qu'un exemple sans grand intérêt
$ cat nouveau-fichier ceci est un exemple ayant un grand intérêt
Et la comparaison (diff) des deux, qui permet de visualiser très rapidement et de manière extrêmement claire les différences :
$ diff -u ancien-fichier nouveau-fichier --- ancien-fichier 2010-04-27 23:53:41.948385552 +0200 +++ nouveau-fichier 2010-04-27 23:54:12.552109974 +0200 @@ -1,7 +1,8 @@ ceci -n'est -qu'un +est +un exemple -sans +ayant +un grand intérêt
L'option -u permet d'obtenir ce qu'on appelle un diff unifié, le format le plus couramment utilisé.
Ce qui saute immédiatement aux yeux, ce sont les signes + et - (ou leur absence) en début de lignes.
Votre intuition ne vous trompe pas : les signes - marquent les lignes ayant été supprimées lors du passage de ancien-fichier à nouveau-fichier, et les signes + les lignes ayant été rajoutées. Les lignes commençant par un espace n'ont tout simplement pas été modifiées, et sont incluses pour fournir un minimum de contexte aussi bien aux humains qui liraient ce résultat, qu'à la commande patch chargée d'appliquer automatiquement ces modifications à un troisième fichier, même s'il est légèrement différent des deux autres (dans une certaine limite, bien sûr).
Deuxième point remarquable : les lignes commençant par @@ indiquent les numéros de lignes correspondant au bloc de modifications qui se trouve à la suite, pour aider la commande patch à s'y retrouver.
Leur format n'a pas grande importance pour un être humain, tout ce qu'il y a à savoir c'est que le premier chiffre (dans cet exemple, -1) identifie dans ancien-fichier la ligne précédant immédiatement la première ligne de contexte (ici, « ceci » qui se trouve être la première ligne du fichier, c'est à dire la ligne n° 0).
Dernière chose, un diff unifié commence toujours par les deux lignes --- et +++ qui indiquent le nom et l'heure de modification des deux fichiers comparés.
Sauvegarder des modifications pour usage ultérieur (créer un « patch »)
La commande diff affiche par défaut son résultat dans la console.
Si l'on veut sauvegarder ce résultat sur le disque dur, il suffit donc de rediriger la sortie vers un fichier :
$ diff -u ancien-fichier nouveau-fichier > fichier.diff
Appliquer des modifications (un « patch ») à un fichier
À quoi sert de sauvegarder un jeu de modifications si on ne le réutilise pas après ?…
$ patch -i fichier.diff troisieme-fichier
ou bien, en utilisant les redirections du shell (exemple simplifié avec cat, uniquement pour montrer la syntaxe patch correspondante) :
$ cat fichier.diff | patch troisieme-fichier
Ceci va tout simplement appliquer les modifications contenues dans fichier.diff au fichier troisieme-fichier.
Si, comme on est en droit de s'y attendre dans le monde réel, troisieme-fichier a subi des modifications par rapport à ancien-fichier, la commande patch dispose d'un algorithme pour résoudre, dans la mesure du possible, les conflits entre les différentes versions.
Si par malheur patch n'arrive pas à réconcilier les différentes versions, il :
- vous en préviendra
- créera un fichier troisieme-fichier.orig contenant l'original de troisieme-fichier avant toute modification
- appliquera tout de même le maximum de modifications possible
- créera un fichier troisieme-fichier.rej contenant le diff unifié des modifications ayant été rejetées pour cause de conflit
À partir de là, charge à vous de revenir à la bonne vieille méthode consistant à comparer et corriger les différences « manuellement », avec tout de même l'avantage de disposer du .diff (en l'occurrence, le .rej est plus utile) pour vous guider dans vos recherches.
Annuler les modifications contenues dans un « patch »
Si pour une raison quelconque vous souhaitez faire le chemin inverse (obtenir ancien-fichier alors que vous n'avez plus que nouveau-fichier et fichier.diff) il suffit d'inverser le patch à l'aide de l'option -R :
$ cp nouveau-fichier ancien-fichier $ patch -R -i fichier.diff ancien-fichier
Plus d'options
diff et patch proposent une flopée d'options supplémentaires permettant de contrôler de nombreux aspects des algorithmes de comparaison (diff) et de fusion (patch).
Pour tout savoir :
$ man diff $ man patch
Exemple pratique (scénario de gestion des fichiers de configuration)
Je viens d'installer le paquet foobar qui fournit le fichier de configuration /etc/foobar. Et bien entendu j'ai besoin de personnaliser ce dernier.
Première étape, en faire une copie de sauvegarde :
# cd /etc/ # cp foobar foobar~backup
J'édite /etc/foobar à ma convenance, et une fois la configuration validée je crée le patch pour conserver soigneusement ces modifications (et uniquement ces modifications) :
# diff -u foobar~backup foobar > foobar.diff
À ce stade, la copie de sauvegarde n'est plus nécessaire, on peut la supprimer :
# rm foobar~backup
Le temps passe, et vient le moment où le paquet foobar est mis à jour et où apt me demande quoi faire à propos du fichier de configuration modifié (conserver / écraser / examiner la situation en shell).
Afin de m'assurer de conserver mes modifications tout en bénéficiant également des nouvelles modifications distribuées avec la mise à jour, je vais aller examiner la situation en shell et faire la fusion avec mes petites mains à moi.
Pour vérifier les différences entre ma version et la nouvelle version, vous l'aurez deviné :
# cd /etc/ # diff -u foobar foobar.dpkg-new
Pour appliquer mes modifications personnelles à la nouvelle version (toujours en faisant une copie de sauvegarde avant...) :
# cp foobar foobar~backup.working # cp foobar.dpkg-new foobar # patch -i foobar.diff foobar
Sortir ensuite du shell (exit) puis sélectionner l'option apt « conserver mon fichier de configuration et ignorer celui du paquet ».
Utilisateur:Syam
Ce tutoriel a un niveau de difficulté : Expert