Deux textes qui semblent identiques le sont rarement, et trouver la différence à l'œil est une tâche où les humains sont spectaculairement mauvais. Cet outil compare ligne par ligne et marque ce qui a été ajouté et retiré. L'intéressant, c'est que « qu'est-ce qui a changé » est une question à plus d'une bonne réponse.
La différence invisible qui fait paraître tout changé
Si un diff annonce que chaque ligne a changé alors que le texte manifestement non, la réponse tient presque toujours aux fins de ligne. Windows termine les lignes par un retour chariot et un saut de ligne ; Unix, Linux et macOS n'utilisent que le saut. Les deux sont parfaitement invisibles à l'écran.
L'effet est total. Découpez « uno\ndue\ntre » et « uno\r\ndue\r\ntre » en lignes et vous obtenez ["uno","due","tre"] contre ["uno\r","due\r","tre\r"] — chaque ligne transporte désormais un passager invisible, et seule la dernière, sans saut final, correspond. Une ligne sur trois. Les textes sont les mêmes ; les octets non.
C'est pourquoi git possède des réglages autocrlf, et pourquoi les équipes s'y disputent. Si vous comparez le fichier d'un collègue sous Windows au vôtre sur un Mac, normalisez les fins de ligne avant de chercher du sens dans le résultat.
Il n'existe pas un diff correct unique
Cela surprend qui suppose qu'un diff est un fait. Ce n'en est pas un — c'est une réponse parmi plusieurs également minimales. Si une ligne est supprimée d'une série de lignes identiques, rien dans le texte ne dit laquelle a disparu. L'algorithme choisit, et des algorithmes différents choisissent différemment.
Ajoutez une fonction à un fichier source et le diff montrera peut-être votre nouvelle fonction comme ajoutée, ou bien votre accolade fermante comme ajoutée et celle de la fonction suivante comme retirée — les deux sont minimaux, un seul est compréhensible. C'est exactement pour cela que git propose plusieurs algorithmes : le Myers par défaut est rapide, tandis que patience et histogram produisent des diffs qui collent mieux à la façon dont un humain voit le changement. Aucun n'est plus correct. Ils optimisent des définitions différentes d'une bonne réponse.
Pourquoi les grandes comparaisons se heurtent à un mur
L'algorithme classique construit une table de chaque ligne de A contre chaque ligne de B, ce qui coûte du temps et de la mémoire proportionnels au produit des deux longueurs. Deux fichiers de 12 000 lignes réclament une table de 144 millions de cellules : plus d'un gigaoctet de mémoire et près de deux secondes de travail. Sur un téléphone, c'est un onglet mort.
Le salut, c'est que les vraies comparaisons sont rarement aléatoires. Deux versions d'un document partagent généralement une longue tête et une longue queue identiques, et ces lignes n'ont besoin d'aucune table — elles sont égales à vue d'œil. Les retirer d'abord est le premier geste de toute implémentation sérieuse de diff, et sur deux fichiers de 12 000 lignes qui diffèrent en un point, cela fait passer la table de 144 millions de cellules à une poignée.
Cela couvre le cas normal. Cela n'aide pas quand deux grands textes sont réellement différents de bout en bout, car il n'y a alors ni tête ni queue commune à retirer. Cet outil trace là une limite et vous le dit, plutôt que d'essayer et de mourir : si après élagage la comparaison est trop grande, vous recevez un message. C'est un choix délibéré — un outil qui gèle votre navigateur est pire qu'un outil qui admet ses limites.
La ligne est la mauvaise granularité pour la prose
Cet outil compare des lignes entières, ce qui convient au code, à la configuration et à tout ce où une ligne est une unité de sens. Cela convient mal à la prose. Changez un mot dans un paragraphe qui tient sur une seule ligne et le diff marquera le paragraphe entier comme retiré puis rajouté — techniquement vrai et pratiquement inutile.
Le remède dans ce cas est de travailler avec un texte d'une phrase par ligne, ou de recourir à un diff au niveau du mot. Il vaut la peine de savoir lequel vous regardez : un diff de lignes sur un document au retour automatique vous dit qu'un paragraphe a changé, et rien sur ce qui a changé dedans.
Questions fréquentes
Mon texte est-il envoyé à un serveur ?
Non. Cet outil porte la mention « client » : les deux textes sont comparés dans votre onglet et aucun ne quitte votre machine. Cela compte plus que d'habitude ici, car comparer deux versions de quelque chose signifie que vous en avez deux versions — contrats, brouillons, fichiers de configuration contenant des identifiants.
Pourquoi dit-il que chaque ligne a changé alors qu'elles semblent identiques ?
Les fins de ligne, presque certainement — voir plus haut. L'autre candidat, ce sont les espaces en fin de ligne, tout aussi invisibles et tout aussi fatals à une comparaison. Si votre éditeur sait afficher les caractères invisibles, activez-le et regardez la fin des lignes.
Pourquoi y a-t-il une ligne vide en trop à la fin ?
Parce que le texte se termine par un saut de ligne. Découper « a\nb\n » aux sauts donne trois morceaux — « a », « b » et une chaîne vide après le dernier saut. Ce n'est pas un bug du diff ; c'est ce que signifie un saut final. La convention Unix veut que les fichiers texte se terminent par un : c'est donc très courant et généralement sans intérêt à poursuivre.
Peut-il comparer deux fichiers plutôt que du texte collé ?
Pas ici — c'est un outil de collage. Pour des fichiers, et surtout pour tout ce qui est sous gestion de versions, utilisez git diff : il gère les fins de ligne, propose les meilleurs algorithmes évoqués plus haut, et sait montrer les changements au niveau du mot à l'intérieur d'une ligne. Cet outil sert à la comparaison rapide, quand ouvrir un terminal demande plus d'effort que la question n'en mérite.
Ignore-t-il les espaces ?
Non. Chaque caractère compte, y compris les espaces en fin de ligne et l'indentation. C'est le bon comportement par défaut pour un outil généraliste — parfois les espaces sont exactement le changement que vous traquez — mais cela signifie qu'un fichier réindenté apparaîtra entièrement réécrit. Si c'est votre cas, git diff -w ignore les espaces et vous montrera ce qui a réellement bougé.