1 puntos por GN⁺ 2025-01-20 | 1 comentarios | Compartir por WhatsApp
  • En Git, help.autocorrect=1 corrige un comando mal escrito y luego lo ejecuta tras esperar solo 0.1 segundos, así que en la práctica se acerca a una ejecución inmediata y no da tiempo real para confirmar o cancelar
  • Este comportamiento no es el predeterminado de Git; con la configuración por defecto, no ejecuta un comando desconocido y solo muestra comandos similares antes de salir
  • En una discusión de 2008, help.autocorrect dejó de ser booleano y pasó a representar un tiempo de espera en decisegundos, por lo que 1 se interpreta no como true, sino como una espera de 0.1 segundos
  • Actualmente, help.autocorrect admite 0, valores positivos, immediate, prompt y never; si quieres ejecutar tras confirmar, prompt es una opción más segura
  • La deducción de comandos en Git se basa en una distancia de Levenshtein modificada, y Scott Chacon propuso un parche para manejar de forma más natural 1 y las cadenas booleanas

Cómo git pushy termina ejecutándose como git push

  • Cuando @dhh escribió git pushy, Git dedujo que quería decir git push y esperó solo 0.1 segundos antes de ejecutarlo
  • 0.1 segundos es demasiado poco para que una persona lea el comando, decida si es correcto y lo cancele
  • Este comportamiento no es el predeterminado de Git, sino que aparece cuando la opción help.autocorrect está activada

El comportamiento predeterminado y el nacimiento de help.autocorrect

  • La respuesta predeterminada de Git es no ejecutar un comando desconocido, sino mostrar posibles comandos según la similitud de cadenas y luego salir
    • Ejemplo: git pushy puede mostrar que push es el comando más parecido
  • Originalmente, Git solo respondía a un comando desconocido con algo como “no es un comando de Git”
  • En 2008, Johannes Schindelin propuso un pequeño parche para recorrer los comandos conocidos, encontrar el más parecido y, si había un solo candidato suficientemente cercano, ejecutarlo
  • Alex Riesen envió un parche para controlar esto con la opción help.autocorrect, que al inicio era booleana
    • En la configuración de Git, un valor booleano puede interpretar 1 como true
    • Por eso, en su contexto original, help.autocorrect=1 podía parecer una forma de activar la autocorrección

Por qué 1 terminó significando 0.1 segundos

  • Junio Hamano propuso que help.autocorrect no fuera un simple booleano, sino la cantidad de decisegundos a esperar antes de ejecutar
    • Un decisegundo equivale a 0.1 segundos
    • La intención era darle al usuario la oportunidad de presionar ^C
  • En el parche que finalmente se aceptó, el valor de la opción pasó a representar un tiempo de espera
  • Como resultado, help.autocorrect=1 ya no significa “activar la función”, sino “esperar 1 decisegundo, es decir, 0.1 segundos, y luego ejecutar”
  • No quedó registrado en la discusión por qué se eligió el decisegundo como unidad de tiempo adecuada

Qué valores de configuración se pueden elegir hoy

  • Según la documentación de Git, help.autocorrect admite los siguientes valores
    • 0: valor predeterminado; solo muestra el comando sugerido
    • valores positivos: ejecuta el comando sugerido tras el número indicado de decisegundos
    • immediate: ejecuta el comando sugerido de inmediato
    • prompt: muestra la sugerencia y pregunta si debe ejecutarla
    • never: ni ejecuta ni muestra el comando sugerido
  • Si quieres ejecutar solo después de confirmar, prompt suele ser una opción más razonable para la mayoría de usuarios
  • Un ejemplo de configuración sería el siguiente
git config --global help.autocorrect prompt
  • Después, si escribes algo como git pushy, te preguntará con [y/N] si quieres ejecutar push

Cómo elige Git los comandos parecidos

  • Git no intenta adivinar comandos sin límite; llega un punto en que considera que la distancia es demasiado grande y ya no propone candidatos
  • Algunos ejemplos de comportamiento
    • git bass está lo bastante cerca de rebase como para mostrar la confirmación de ejecución
    • git bassa ya se considera demasiado lejos como para tratarlo como rebase
    • git dm muestra tanto am como rm como comandos similares
    • git dma se empareja solo con am
  • Esta lógica se basa en un algoritmo de distancia de Levenshtein modificado
    • Calcula el costo de edición de caracteres necesario para convertir una cadena en otra
    • Algunas operaciones se consideran más costosas que otras
  • Git tiene un cutoff codificado de forma fija; si el costo respecto a un comando conocido es demasiado alto, asume que el usuario escribió algo muy distinto y no hace una deducción

El parche para cambiar cómo se interpreta 1

  • Como help.autocorrect=1 en términos humanos es prácticamente lo mismo que immediate, Scott Chacon escribió un pequeño parche para interpretar 1 no como una espera de 0.1 segundos, sino como ejecución inmediata
  • Junio Hamano pidió no tratar solo "1" como caso especial, sino interpretar correctamente también cadenas booleanas como yes, no, true y off
  • La segunda versión del parche avanza en esa dirección e incluye el manejo de estas cadenas booleanas
  • Si el parche se integra, en futuras versiones de Git podría reducirse la confusión en torno a help.autocorrect

1 comentarios

 
GN⁺ 2025-01-20
Comentarios de Hacker News
  • En los años 70, Hal Finney estaba haciendo que un intérprete BASIC para Mattel Intellivision cupiera en una ROM de 2 KB, y cada byte era valioso.
    Todavía me da risa que, para mostrar errores de sintaxis, redujo todos los mensajes de error a EH?, y que él estaba bastante orgulloso de eso.

    • EH? también quedaría muy bien como respuesta del parser de texto en un viejo juego de ficción interactiva.
      Algo relacionado: en algunas variantes antiguas de BASIC se podía escribir la sentencia PRINT como ?, aunque creo que eso tenía más que ver con ahorrar tiempo al teclear en el REPL que con ahorrar memoria.
    • Qué desperdicio. ed usa solo un ? para todos los errores, así que ahorra 3 veces más.
    • El caso más temprano que vi de usar Eh? como respuesta de un intérprete fue en 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
      Tenía unos 5 KB de memoria, pero, comparado con la Intellivision, la máquina pesaba unas 5,000 libras.
    • Bastante genial. No sabía que Hal había sido un hacker de computadoras personales en esa época; cuando escucho hablar de Hal siempre pienso en Bitcoin.
    • Opero xordle, un juego derivado de Wordle, que tiene dos puzzles de Wordle en un mismo tablero.
      Así que puedes adivinar una palabra y que las 5 letras queden todas en verde, pero aun así no sea ninguna de las dos respuestas. Cuando pasa eso, a la derecha simplemente hice que aparezca Huh?, y a la gente le gusta esa parte.
  • La causa de fondo es que el nombre de la configuración está mal elegido.
    Si la configuración original se hubiera llamado algo con pinta de booleano, como help.autocorrect_enabled, habría sido absurdo pedir que aceptara un valor entero e interpretarlo en unidades de 0.1 segundos. En cambio, habría hecho falta otra configuración como help.autocorrect_accept_after_dsec, y como dsec es tan poco común, cualquiera que la usara no tendría más remedio que buscar qué significa.
    En las revisiones de código siempre pido este tipo de cosas. Si puede ser ambiguo, el nombre de la variable debe incluir la unidad. Por ejemplo, int timeout debería ser int timeout_msec.
    En los nombres de configuración esto es 100 veces más importante. Las configuraciones son parte de la interfaz pública, así que no se pueden cambiar después.

    • Pienso lo mismo. Aunque cuando esto se empuja hacia el sistema de tipos, todavía me genera dudas.
      En el contexto de C++, una regla aproximada sería que void FooBar(std::chrono::milliseconds timeout); está bien, porque es una firma de función y al verla también se ve el tipo.
      Pero en una variable, timeout no está bien. En el 99% de los casos, el uso real se ve como auto timeout = gl_timeout; o FooBar(timeout);.
      Como en C++ se usa mucho auto, seguir el tipo exacto cuando importa se vuelve bastante molesto.
      Cuando trabajo en C++ uso un IDE o un editor con servidor de lenguaje, pero no tengo tiempo de pasar el mouse cada 5 segundos para comprobar el tipo.
    • Sí, y además empeora la situación que hayan usado una unidad de tiempo que literalmente nunca había usado en toda mi vida: unidades de 0.1 segundos (decisegundos).
      Si hubiera visto un mensaje que dijera “se ejecutará después de 1 ms”, habría revisado la configuración de inmediato.
    • Así se termina como systemd, donde se puede usar tanto TimoutSec=60 como TimeoutSec=1min.
      Creo que habría sido mejor no poner la unidad en el nombre. Aunque, salvo por ese caso particular, estoy totalmente de acuerdo.
    • Lo hago así, pero me cuesta sacarme de la cabeza que huele a notación húngara.
      La mejor alternativa que encontré hasta ahora es hacer que el valor reciba una unidad. Por ejemplo, permitir 5 seconds o 5s, y tratar simplemente 1 como un valor inválido.
    • En la revisión de código marcaría directamente ese uso de int y recomendaría una clase de valor que lleve correctamente la unidad.
      Por ejemplo, algo como Second(2) o Millisecond(2000).
      Claro que esto depende de las características y convenciones del lenguaje.
  • xmobar también usa unidades de 0.1 segundos en un lugar similar, pero más problemático. Es la configuración que declara con qué frecuencia se actualiza cada sección.
    Los números de la configuración de ejemplo son demasiado pequeños como para que parezcan milisegundos, así que uno asume razonablemente que son segundos, y como resultado termina ejecutando comandos 10 veces más seguido de lo previsto.
    He visto varias veces picos accidentales de carga originados por este problema.

  • Parece un diseño bastante malo.
    Aunque el punto 1 fue resultado de leer mal el artículo, y el “valor anterior” nunca existió en git.

    1. Casi siempre se debe evitar un cambio que reinterprete silenciosamente un valor de configuración existente con otro significado, por ejemplo cambiar 1=true a 1=retraso de confirmación de 0.100 ms. Si hubiera existido un valor previo, quizá querrías eliminarlo, pero lo correcto sería cambiar también el nombre de la configuración.
    2. Que el argumento de configuración de help.autocorrect sea tiempo y que esté medido en una unidad no estándar para la mayoría de los usuarios simplemente está mal. La activación debería recibirse como booleano, y el tiempo de confirmación debería poder ajustarse con un valor decimal.
    • Sobre el punto 1, creo que estás malinterpretando la cronología.
      Ese cambio ocurrió en 2008, durante la revisión de código del parche inicial que intentaba agregar esa opción como booleano, antes de que se hiciera commit al árbol principal de git.
    • Cuando se habla de “diseño”, uno piensa en un plan intencional y de amplio alcance.
      Esto se parece más a una rama lateral que creció orgánicamente que a un diseño.
  • Creo que este es un buen ejemplo de exceso progresivo de funcionalidades (creeping featurism).
    En el mejor de los casos introduce complejidad innecesaria, y en el peor hace que la gente que depende de eso preste menos atención a lo que está haciendo.

    • git es exactamente eso. Una estructura de datos elegante cubierta por varias capas de basura innecesaria acumulada con los años.
    • No entiendo por qué alguien querría permitir la ejecución automática.
      ¿Tan difícil es presionar la flecha hacia arriba y corregir el error? Ejecutar automáticamente algo “más o menos correcto” es la receta para hacer cosas no intencionales.
  • El error estaba aquí. En vez de reutilizar una configuración existente con otro significado, debieron agregar una configuración nueva
    help.autocorrect debió separarse en activar/desactivar, y help.autocorrect.milliseconds en cuánto esperar
    Hay errores parecidos en otros sistemas. Por ejemplo, en MySQL, innodb_flush_log_at_trx_commit está desactivado si es 0, activado si es 1, y el 2 se agregó después con un significado especial

    • El verdadero problema es un lenguaje de configuración sin tipos que intenta adivinar qué significa 1
      Ahora 1 se mantiene como verdadero booleano, mientras otros enteros se vuelven unidades de 0.1 segundos, hundiéndose aún más
      Es una lógica dudosa, como el infame no == false de YAML
    • No sé cuál sería el mejor uso, pero 0.1 segundos tampoco es un valor absurdo
      El tiempo de reacción aleatorio más rápido registrado ronda los 1.5 ds, y casualmente el tiempo de reacción promedio de un gamer también está por ahí, pero las reacciones no aleatorias pueden ser mucho más rápidas. Por ejemplo, cuando se reacciona siguiendo un ritmo
      Si quieres ir así de rápido, se puede, y la velocidad de invocación también debería ser relativamente estable. Probablemente del orden de unos pocos milisegundos
  • Hace un año activé la autocorrección y la configuré en 3 segundos, y noté dos cosas

    1. No distingue entre acciones peligrosas y seguras
    2. Contamina el historial de la shell con comandos mal escritos
      Después de leer este artículo, tuve motivo suficiente para desactivarla tras un año
    • Mejor crear alias para los errores tipográficos frecuentes
      Aunque, claro, eso también “contamina” el historial de la shell
    • Sobre el punto 2, quien realmente contamina eres tú
      Es lo mismo si retrocedes en el historial y vuelves a usar tal cual el último comando mal escrito solo porque de todos modos funciona
  • Las unidades de 0.1 segundos son una elección realmente peculiar
    Para los retardos conviene más especificar milisegundos o segundos, y ambos son mucho más comunes en computación

    • Por un momento me confundió bastante. Pensé que deciseconds era una unidad propia de git, algo como decision-seconds, es decir, “segundos necesarios para tomar una decisión” xD
      Para que conste, el inglés no es mi lengua materna, pero vengo de una región civilizada que usa el sistema métrico
    • Está bien para tiempos de reacción humanos, pero es una unidad poco común
      La diferencia entre 0 y 1 segundo se nota mucho cuando esperas algo, pero la diferencia entre n milisegundos y n+1 milisegundos es demasiado pequeña para ser útil
  • El tiempo de reacción varía según el tipo de estímulo; el auditivo es un poco más rápido que el visual, y el táctil un poco más rápido todavía, de unos 90~180 ms
    Así que si git te diera un golpe en vez de mostrar un mensaje de error, tal vez apenas tendrías tiempo de reaccionar

    • Para que ese dispositivo de golpes se sienta como un golpe, tendría que generar inercia
      ¿10 ms serían suficientes para eso?
  • Leer este artículo me recordó la arqueología de software y la idea del “programador arqueólogo”
    Por lo segundo hay que darle las gracias a Vernor Vinge

    • Esto es algo que de verdad me molesta. Los hackers promovían que ese libro había introducido el concepto de “arqueología de software”, así que me entusiasmaba mucho leer 『A Fire Upon The Deep』
      Pero el concepto apenas se insinúa en el prólogo y luego no aparece en absoluto. Los efectos de la arqueología sí tienen relación con la trama, pero el “arqueólogo de software” no era un personaje significativo en la narración
      Sentí que me habían engañado
    • Suelo decir que el riesgo de la arqueología de software es que al final terminas encontrando coprolitos
    • No puedo quitarme la sensación de que ahora me están llamando “viejo”