1 points par GN⁺ 2025-01-20 | 1 commentaires | Partager sur WhatsApp
  • Avec help.autocorrect=1, Git ne patiente que 0,1 seconde après avoir corrigé une commande mal saisie avant de l’exécuter : en pratique, c’est presque instantané, trop rapide pour que l’utilisateur puisse confirmer ou annuler
  • Ce comportement n’est pas la valeur par défaut de Git : par défaut, Git n’exécute pas une commande inconnue, il affiche seulement des commandes similaires, puis quitte
  • Lors d’une discussion en 2008, help.autocorrect est passé d’un booléen à un temps d’attente en décisecondes, si bien que 1 est interprété non pas comme true, mais comme une attente de 0,1 seconde
  • Aujourd’hui, help.autocorrect prend en charge 0, les valeurs positives, immediate, prompt et never ; pour exécuter après confirmation, prompt est un choix plus sûr
  • La suggestion de commandes par Git repose sur une distance de Levenshtein modifiée, et Scott Chacon a proposé un patch pour traiter 1 et les chaînes booléennes de façon plus naturelle

Comment git pushy finit exécuté comme git push

  • Quand @dhh a saisi git pushy, Git l’a interprété comme git push et n’a attendu que 0,1 seconde avant l’exécution
  • 0,1 seconde est un délai trop court pour qu’un utilisateur lise la commande, juge si elle est correcte et l’annule
  • Ce comportement n’est pas le comportement par défaut de Git : il apparaît lorsque le réglage help.autocorrect est activé

Le comportement par défaut et la naissance de help.autocorrect

  • La réaction par défaut de Git consiste à ne pas exécuter une commande inconnue, mais à afficher les commandes possibles selon leur similarité avec la chaîne saisie, puis à quitter
    • Exemple : pour git pushy, il peut indiquer que push est la commande la plus similaire
  • À l’origine, Git répondait simplement qu’il ne s’agissait pas d’une « commande Git » lorsqu’une commande était inconnue
  • En 2008, Johannes Schindelin a proposé un petit patch qui parcourait les commandes connues pour trouver la plus proche, puis l’exécutait s’il n’y avait qu’un seul candidat proche
  • Alex Riesen a soumis un patch permettant de contrôler ce comportement via le réglage help.autocorrect ; au départ, ce réglage était booléen
    • Dans la configuration Git, les valeurs booléennes peuvent interpréter 1 comme true
    • Dans ce contexte initial, help.autocorrect=1 pouvait donc sembler être une valeur activant l’autocorrection

Pourquoi 1 est devenu 0,1 seconde

  • Junio Hamano a proposé que help.autocorrect ne soit pas un simple booléen, mais le nombre de décisecondes à attendre avant l’exécution
    • Une déciseconde correspond à 0,1 seconde
    • L’objectif était de laisser à l’utilisateur une occasion d’appuyer sur ^C
  • Dans le patch accepté par la suite, la valeur de configuration est devenue un temps d’attente
  • Résultat : help.autocorrect=1 ne signifie pas « activer la fonctionnalité », mais « attendre 1 déciseconde, soit 0,1 seconde, puis exécuter »
  • La discussion ne précise pas pourquoi la déciseconde a été choisie comme unité de temps appropriée

Les valeurs configurables aujourd’hui

  • D’après la documentation de Git, help.autocorrect prend en charge les valeurs suivantes
    • 0 : valeur par défaut, affiche uniquement la commande suggérée
    • Valeur positive : exécute la commande suggérée après le nombre indiqué de décisecondes
    • immediate : exécute immédiatement la commande suggérée
    • prompt : affiche la suggestion et demande confirmation avant exécution
    • never : n’exécute pas et n’affiche pas la commande suggérée
  • Si l’on souhaite une exécution après confirmation, prompt est plus raisonnable pour la plupart des utilisateurs
  • Exemple de configuration :
git config --global help.autocorrect prompt
  • Ensuite, si vous saisissez une commande comme git pushy, Git demande avec [y/N] s’il faut exécuter push

Comment Git choisit une commande similaire

  • Git ne devine pas les commandes au hasard : à partir d’un certain point, il considère qu’une commande est trop éloignée et ne propose pas de candidat
  • Exemples de comportement :
    • git bass est suffisamment proche de rebase pour afficher une confirmation d’exécution
    • git bassa est jugé trop éloigné de rebase, et aucun candidat n’est exécuté
    • git dm affiche à la fois am et rm comme commandes similaires
    • git dma ne correspond plus qu’à am
  • Cette logique repose sur un algorithme de distance de Levenshtein modifié
    • Il calcule le coût des modifications de caractères nécessaires pour transformer une chaîne en une autre
    • Certaines opérations sont considérées comme plus coûteuses que d’autres
  • Git possède un seuil hardcodé : si le coût par rapport aux commandes connues est trop élevé, il considère que la saisie de l’utilisateur est très erronée et ne tente pas de suggestion

Un patch pour changer l’interprétation de 1

  • Comme help.autocorrect=1 équivaut en pratique à immediate du point de vue humain, Scott Chacon a écrit un petit patch pour interpréter 1 non pas comme une attente de 0,1 seconde, mais comme une exécution immédiate
  • Junio Hamano a demandé de ne pas traiter seulement "1" comme un cas spécial, mais aussi d’interpréter correctement les chaînes booléennes comme yes, no, true ou off
  • La deuxième version du patch est en cours dans ce sens, avec la prise en charge de ces chaînes booléennes
  • Si le patch est intégré, la confusion autour de help.autocorrect pourrait diminuer dans les futures versions de Git

1 commentaires

 
GN⁺ 2025-01-20
Commentaires sur Hacker News
  • Dans les années 70, Hal Finney faisait tenir un interpréteur BASIC pour la Mattel Intellivision dans une ROM de 2 Ko, et chaque octet comptait
    Pour afficher les erreurs de syntaxe, il avait réduit tous les messages d’erreur à EH?, et ça me fait encore rire qu’il en ait été assez fier

    • EH? irait aussi très bien comme réponse du parseur de texte dans un vieux jeu de fiction interactive
      Dans un registre un peu lié, certaines anciennes variantes de BASIC permettaient d’écrire l’instruction PRINT sous la forme ?, mais j’ai l’impression que c’était davantage pour réduire le temps de saisie dans le REPL que pour économiser de la mémoire
    • Quel gaspillage. ed n’utilise qu’un seul ? pour toutes les erreurs, donc 3 fois plus d’économies
    • Le premier exemple que j’aie vu d’un interpréteur répondant Eh? vient de JOSS de RAND
      [https://en.wikipedia.org/wiki/JOSS#/media/File:JOSS_Session....](https://en.wikipedia.org/wiki/JOSS#/media/File:JOSS_Session.jpg)
      https://en.wikipedia.org/wiki/JOSS
      La mémoire était d’environ 5 Ko, mais par rapport à l’Intellivision, la machine pesait environ 5 000 livres
    • Plutôt classe. Je ne savais pas que Hal était un hacker d’ordinateur personnel à cette époque ; quand j’entends parler de Hal, je pense toujours à Bitcoin
    • Je gère xordle, un dérivé de Wordle où il y a deux grilles Wordle sur un seul plateau
      Du coup, on peut proposer un mot dont les 5 lettres deviennent toutes vertes sans que ce soit l’une des deux réponses. Dans ce cas, j’ai simplement fait afficher Huh? à droite, et les gens aiment bien ce détail
  • La cause profonde, c’est que le nom du réglage est mal choisi
    Si le réglage d’origine avait eu un nom de booléen, comme help.autocorrect_enabled, une demande visant à accepter une valeur entière et à l’interpréter en unités de 0,1 seconde n’aurait eu aucun sens. Il aurait plutôt fallu un autre réglage, du genre help.autocorrect_accept_after_dsec, et dsec est tellement peu courant que quiconque l’utiliserait serait forcé de vérifier ce que ça veut dire
    En revue de code, je demande toujours ce genre de chose. Si une ambiguïté est possible, le nom de variable doit contenir l’unité. Par exemple, int timeout devrait devenir int timeout_msec
    Pour les noms de réglages, c’est 100 fois plus important. Les réglages font partie de l’interface publique, donc on ne peut pas les changer plus tard

    • Je suis du même avis. Cela dit, quand ça se déplace vers le système de types, je continue à me poser la question
      Dans le contexte C++, ma règle approximative est que void FooBar(std::chrono::milliseconds timeout); est acceptable. Comme c’est une signature de fonction, on voit aussi le type au moment de la lire
      Mais pour une variable, timeout ne va pas. Dans 99 % des cas, l’usage réel se présentera comme auto timeout = gl_timeout; ou FooBar(timeout);
      Comme auto est couramment utilisé en C++, suivre le type exact quand c’est important devient assez pénible
      Quand je travaille en C++, j’utilise un IDE ou un éditeur avec serveur de langage, mais je n’ai pas le temps de survoler quelque chose à la souris toutes les 5 secondes pour vérifier son type
    • Exact, et le fait d’avoir utilisé une unité de temps que je n’ai littéralement jamais utilisée de ma vie, le dixième de seconde (decisecond), aggrave encore la situation
      Si le message avait dit « exécution dans 1 ms », j’aurais immédiatement vérifié le réglage
    • À ce rythme, on finit comme systemd, où l’on peut écrire à la fois TimoutSec=60 et TimeoutSec=1min
      Je pense qu’il aurait mieux valu ne pas mettre l’unité dans le nom. Mais à part ce cas particulier, je suis entièrement d’accord
    • C’est ce que je fais, mais j’ai du mal à me défaire de l’impression que ça sent la notation hongroise
      La meilleure alternative que j’aie trouvée jusqu’ici est d’accepter l’unité dans la valeur. Par exemple, autoriser 5 seconds ou 5s, et traiter simplement 1 comme une valeur invalide
    • En revue de code, je signale ce genre d’usage de int et je recommande plutôt une classe de valeur qui transporte correctement l’unité
      Par exemple Second(2) ou Millisecond(2000)
      Évidemment, cela dépend des fonctionnalités et des conventions du langage
  • xmobar utilise aussi des unités de 0,1 seconde, mais à un endroit encore plus problématique. C’est le réglage qui déclare à quelle fréquence chaque section doit être rafraîchie
    Les nombres de la configuration d’exemple sont trop petits pour que ce soient vraisemblablement des millisecondes, ce qui pousse donc raisonnablement à supposer qu’il s’agit de secondes, et finit par exécuter les commandes 10 fois plus souvent que prévu
    J’ai vu plusieurs pics de charge accidentels causés par ce problème

  • Ça ressemble à une conception assez mauvaise
    Cela dit, le point 1 venait d’une mauvaise lecture de l’article, et la « valeur précédente » n’a jamais existé dans git

    1. Il faut presque toujours éviter les changements qui réinterprètent silencieusement une valeur de configuration existante avec un autre sens, par exemple transformer 1=true en 1=délai de confirmation de 0,100 ms. S’il y avait eu une valeur existante, on aurait envie de la supprimer, mais il aurait aussi fallu renommer le réglage
    2. Le fait que l’argument de configuration de help.autocorrect soit une durée, mesurée dans une unité non standard pour la plupart des utilisateurs, est tout simplement mauvais. L’activation devrait être un booléen, et le délai de confirmation devrait pouvoir être réglé avec une valeur décimale
    • Pour le point 1, je crois que tu as mal compris la chronologie
      Ce changement a eu lieu en 2008, pendant la revue de code du patch initial qui ajoutait cette option comme booléen, avant qu’il ne soit intégré dans l’arbre principal de git
    • Quand on dit « conception », on pense à un plan intentionnel et d’ensemble
      Ici, c’est moins une conception qu’une branche latérale qui a poussé organiquement
  • Je vois ça comme un bon exemple de fonctionnalite aiguë rampante (creeping featurism)
    Dans le meilleur des cas, ça introduit une complexité inutile ; dans le pire, ça pousse les gens qui s’en servent à faire moins attention à ce qu’ils font

    • git, c’est exactement ça. Plusieurs couches de déchets inutiles accumulées au fil des ans par-dessus une structure de données élégante
    • Je ne comprends pas pourquoi on voudrait autoriser l’exécution automatique
      Est-ce si difficile d’appuyer sur la flèche du haut et de corriger l’erreur ? Exécuter automatiquement quelque chose « à peu près correct » est la recette idéale pour faire quelque chose qu’on ne voulait pas faire
  • C’est là que se trouvait l’erreur. Il ne fallait pas réutiliser un réglage existant avec un autre sens, mais ajouter un nouveau réglage
    help.autocorrect aurait dû servir à activer/désactiver la fonction, et help.autocorrect.milliseconds à définir combien de temps attendre
    On retrouve des erreurs similaires dans d’autres systèmes. Par exemple, dans MySQL, innodb_flush_log_at_trx_commit vaut 0 pour désactivé, 1 pour activé, et 2 a été ajouté plus tard avec une signification spéciale

    • Le vrai problème, c’est un langage de configuration non typé qui essaie de deviner ce que signifie 1
      Désormais, on garde 1 comme booléen vrai tout en faisant des autres entiers des unités de 0,1 seconde, ce qui enfonce encore plus le clou
      C’est la même logique douteuse que le fameux no == false de YAML
    • Je ne sais pas où ce serait le plus pertinent, mais 0,1 seconde n’est pas non plus une valeur absurde
      Le temps de réaction aléatoire le plus rapide enregistré est d’environ 1,5 ds, et, par coïncidence, le temps de réaction moyen des gamers est à peu près dans ces eaux-là, mais les réactions non aléatoires peuvent être bien plus rapides. Par exemple quand on réagit en rythme
      Si l’on veut aller aussi vite, c’est possible, et la vitesse d’appel devrait aussi être relativement stable. De l’ordre de quelques millisecondes, grosso modo
  • Il y a un an, j’ai activé l’autocorrection et l’ai réglée sur 3 secondes, et j’ai constaté deux choses

    1. Elle ne distingue pas les actions dangereuses des actions sûres
    2. Elle pollue l’historique du shell avec la commande mal saisie
      Après avoir lu cet article, ça m’a donné une raison suffisante pour la désactiver au bout d’un an
    • Autant créer des alias pour les fautes de frappe fréquentes
      Même si, bien sûr, ça « pollue » aussi l’historique du shell
    • À propos du point 2, le vrai pollueur, c’est soi-même
      C’est pareil si l’on remonte dans l’historique et qu’on réutilise telle quelle la dernière commande erronée sous prétexte qu’elle fonctionne de toute façon
  • Les unités de 0,1 seconde sont vraiment un choix étrange
    Il vaut mieux exprimer les délais en millisecondes ou en secondes, deux unités bien plus courantes en informatique

    • J’ai été assez perplexe un instant. J’ai cru que deciseconds était une unité propre à git, des decision-seconds, du genre « secondes nécessaires pour prendre une décision » xD
      Pour info, l’anglais n’est pas ma langue maternelle, mais je viens d’une région civilisée qui utilise le système métrique
    • Pour le temps de réaction humain, ça se tient, mais c’est une unité peu courante
      La différence entre 0 seconde et 1 seconde est nettement perceptible quand on attend quelque chose, alors que la différence entre n millisecondes et n+1 millisecondes est trop infime pour être utile
  • Le temps de réaction varie selon le type de stimulus ; l’auditif est légèrement plus rapide que le visuel, et le tactile encore un peu plus, autour de 90 à 180 ms
    Donc si git vous mettait une claque au lieu d’afficher un message d’erreur, vous auriez peut-être tout juste le temps de réagir

    • Pour que le dispositif qui frappe donne vraiment l’impression de frapper, il faut créer de l’inertie
      10 ms suffiraient-ils pour ça ?
  • En lisant cet article, j’ai pensé à l’archéologie logicielle et à l’expression « archéologue programmeur »
    Pour cette dernière notion, il faut remercier Vernor Vinge

    • C’est un point qui m’agace vraiment. Des hackers ont tellement présenté ce livre comme celui qui introduisait le concept d’« archéologie logicielle » que j’avais très hâte de lire 『A Fire Upon The Deep』
      Mais ce concept n’est qu’esquissé brièvement dans le prologue, puis plus rien. Les effets de l’archéologie ont un rapport avec l’intrigue, mais l’« archéologue logiciel » n’était pas un personnage significatif dans le récit
      J’ai eu l’impression de m’être fait avoir
    • On dit souvent que le danger de l’archéologie logicielle, c’est qu’on finit par découvrir des coprolithes
    • Je n’arrive pas à me défaire de l’impression qu’on est en train de me traiter de « vieux »