1 pontos por GN⁺ 2025-01-20 | 1 comentários | Compartilhar no WhatsApp
  • No Git, help.autocorrect=1 corrige um comando digitado errado e o executa após esperar apenas 0,1 segundo, o que na prática fica muito próximo de uma execução imediata para o usuário confirmar ou cancelar
  • Esse comportamento não é o padrão do Git; na configuração padrão, ele não executa um comando desconhecido e apenas mostra comandos semelhantes antes de encerrar
  • Em uma discussão de 2008, help.autocorrect deixou de ser booleano e passou a representar um tempo de espera em decissegundos, fazendo com que 1 seja interpretado não como true, mas como uma espera de 0,1 segundo
  • Atualmente, help.autocorrect aceita 0, valores positivos, immediate, prompt e never, e prompt é a opção mais segura para quem quer executar após confirmação
  • A estimativa de comandos do Git é baseada em uma distância de Levenshtein modificada, e Scott Chacon propôs um patch para tratar 1 e strings booleanas de forma mais natural

Como git pushy acaba virando git push

  • Quando @dhh digitou git pushy, o Git inferiu que se tratava de git push e esperou apenas 0,1 segundo antes de executar
  • 0,1 segundo é pouco demais para o usuário ler o comando, decidir se está correto e cancelá-lo
  • Esse comportamento não é o padrão do Git; ele aparece quando a configuração help.autocorrect está ativada

O comportamento padrão e o surgimento de help.autocorrect

  • A reação padrão do Git é não executar um comando desconhecido e, em vez disso, mostrar possíveis comandos com base na similaridade entre strings antes de encerrar
    • Exemplo: git pushy pode indicar que push é o comando mais parecido
  • Originalmente, o Git apenas respondia que aquilo “não é um comando Git” para comandos desconhecidos
  • Em 2008, Johannes Schindelin propôs um pequeno patch para percorrer os comandos conhecidos, encontrar o mais parecido e executá-lo se houvesse apenas um candidato suficientemente próximo
  • Alex Riesen enviou um patch para controlar isso pela configuração help.autocorrect, que no início era booleana
    • Em configurações do Git, valores booleanos podem interpretar 1 como true
    • Por isso, no contexto original, help.autocorrect=1 podia parecer um valor para ativar a autocorreção

Por que 1 virou 0,1 segundo

  • Junio Hamano sugeriu que help.autocorrect não fosse apenas um booleano, mas o número de decissegundos a esperar antes da execução
    • Decissegundo é uma unidade de 0,1 segundo
    • A intenção era dar ao usuário uma chance de apertar ^C
  • No patch que acabou sendo aceito, o valor da configuração passou a representar o tempo de espera
  • Como resultado, help.autocorrect=1 deixou de significar “ativar o recurso” e passou a significar “esperar 1 decissegundo, isto é, 0,1 segundo, e então executar”
  • O motivo de o decissegundo ter sido escolhido como unidade de tempo adequada não ficou registrado na discussão

Valores de configuração disponíveis hoje

  • Segundo a documentação do Git, help.autocorrect aceita os seguintes valores
    • 0: valor padrão; apenas mostra comandos sugeridos
    • valores positivos: executa o comando sugerido após o número especificado de decissegundos
    • immediate: executa o comando sugerido imediatamente
    • prompt: mostra a sugestão e pergunta se deve executar
    • never: não executa nem mostra o comando sugerido
  • Se você quer confirmar antes de executar, prompt é a opção mais sensata para a maioria dos usuários
  • Um exemplo de configuração é o seguinte
git config --global help.autocorrect prompt
  • Depois disso, ao digitar algo como git pushy, ele perguntará em [y/N] se deve executar push

Como o Git escolhe comandos parecidos

  • O Git não tenta adivinhar comandos de forma irrestrita; a partir de certo ponto, ele considera que a distância é grande demais e deixa de sugerir candidatos
  • O comportamento nos exemplos é o seguinte
    • git bass é considerado próximo o bastante de rebase para pedir confirmação antes de executar
    • git bassa já é considerado distante demais para ser tratado como rebase, então o candidato não é executado
    • git dm mostra tanto am quanto rm como comandos parecidos
    • git dma passa a corresponder apenas a am
  • Essa lógica é baseada em um algoritmo de distância de Levenshtein modificado
    • Ele calcula o custo de edição de caracteres necessário para transformar uma string em outra
    • Algumas operações são tratadas como mais caras do que outras
  • O Git tem um cutoff fixo em código; se o custo em relação a um comando conhecido for alto demais, ele entende que o usuário digitou algo muito diferente e não faz inferência

O patch que tenta mudar a interpretação de 1

  • Como help.autocorrect=1 é, do ponto de vista humano, praticamente igual a immediate, Scott Chacon escreveu um pequeno patch para interpretar 1 não como espera de 0,1 segundo, mas como execução imediata
  • Junio Hamano pediu que não fosse feito tratamento especial apenas para "1", mas que também fossem interpretadas corretamente strings booleanas como yes, no, true e off
  • A segunda versão do patch está avançando de forma a incluir também esse tratamento de strings booleanas
  • Se o patch for incorporado, versões futuras do Git poderão reduzir a confusão em torno de help.autocorrect

1 comentários

 
GN⁺ 2025-01-20
Comentários no Hacker News
  • Nos anos 70, Hal Finney estava fazendo um interpretador BASIC para o Mattel Intellivision caber em uma ROM de 2 KB, e cada byte era precioso.
    Para indicar erro de sintaxe, ele reduziu todas as mensagens de erro para EH?, e ainda acho engraçado que ele tinha bastante orgulho disso.

    • EH? também pareceria uma boa resposta de parser de texto em jogos antigos de ficção interativa.
      Meio relacionado: em algumas variantes antigas de BASIC, dava para escrever a instrução PRINT como ?, mas acho que isso tinha mais a ver com reduzir o tempo de digitação no REPL do que com economizar memória.
    • Que desperdício. O ed usa só um ? para todos os erros, então há uma economia 3 vezes maior.
    • O caso mais antigo que vi de um interpretador respondendo com Eh? foi no JOSS, da 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
      A memória era de cerca de 5 KB, mas, comparada ao Intellivision, a máquina pesava cerca de 5.000 libras.
    • Bem legal. Eu não sabia que Hal era um hacker de computadores pessoais naquela época; quando ouço falar dele, sempre penso em Bitcoin.
    • Eu mantenho o xordle, um derivado do Wordle, em que há dois puzzles de Wordle em um único tabuleiro.
      Então você pode chutar uma palavra, ficar com as 5 letras todas verdes, e ainda assim ela não ser nenhuma das duas respostas. Nesses casos, fiz aparecer apenas Huh? à direita, e as pessoas gostam dessa parte.
  • A causa raiz é que o nome da configuração foi mal escolhido.
    Se a configuração original tivesse sido nomeada de forma booleana, como help.autocorrect_enabled, a solicitação de aceitar um valor inteiro e interpretá-lo em unidades de 0,1 segundo não teria feito sentido. Em vez disso, teria sido necessária outra configuração, como help.autocorrect_accept_after_dsec, e dsec é tão incomum que quem fosse usar teria que pesquisar.
    Em revisão de código, sempre exijo isso: se puder haver ambiguidade, o nome da variável precisa incluir a unidade. Por exemplo, int timeout deve virar int timeout_msec.
    Em nomes de configuração, isso é 100 vezes mais importante, porque configurações são parte da interface pública e não dá para mudá-las depois.

    • Penso o mesmo. Só que ainda fico em dúvida quando isso é empurrado para dentro do sistema de tipos.
      No contexto de C++, minha regra geral é que void FooBar(std::chrono::milliseconds timeout); está ok. Como é uma assinatura de função, você vê o tipo junto.
      Mas, em uma variável, timeout não está ok. Em 99% dos casos, o uso real aparece como auto timeout = gl_timeout; ou FooBar(timeout);.
      Como auto é muito usado em C++, fica bem trabalhoso rastrear o tipo exato quando isso importa.
      Quando trabalho com C++, uso uma IDE ou um editor com servidor de linguagem, mas não tenho tempo de passar o mouse a cada 5 segundos para conferir o tipo.
    • Sim, e o fato de terem usado décimos de segundo (deciseconds), uma unidade de tempo que literalmente nunca usei na vida, piorou ainda mais a situação.
      Se a mensagem dissesse “executando em 1 ms”, eu teria verificado a configuração na hora.
    • Aí você acaba em uma situação como a do systemd, em que dá para usar tanto TimoutSec=60 quanto TimeoutSec=1min.
      Acho que teria sido melhor não colocar a unidade no nome. Mas, tirando esse caso peculiar, concordo totalmente.
    • Eu faço isso, mas é difícil afastar a sensação de que tem cheiro de notação húngara.
      A melhor alternativa que encontrei até agora é fazer o valor receber a unidade. Por exemplo, aceitar 5 seconds ou 5s, e tratar simplesmente 1 como um valor inválido.
    • Em revisão de código, eu sinalizaria o uso desse int em si e recomendaria, em vez disso, uma classe de valor que carregue a unidade corretamente.
      Por exemplo, algo como Second(2) ou Millisecond(2000).
      Claro que isso depende dos recursos e das convenções da linguagem.
  • O xmobar também usa décimos de segundo, mas em um lugar ainda mais problemático: a configuração que declara com que frequência cada seção deve ser atualizada.
    Os números da configuração de exemplo são pequenos demais para parecerem milissegundos, então levam a supor, razoavelmente, que sejam segundos; com isso, o comando acaba sendo executado 10 vezes mais frequentemente do que o pretendido.
    Já vi várias explosões acidentais de carga decorrentes desse problema.

  • Parece um design bem ruim.
    Mas o item 1 foi resultado de uma leitura equivocada do texto; o “valor anterior” nunca existiu no git.

    1. Uma mudança que reinterpreta silenciosamente um valor de configuração existente com outro significado, por exemplo trocar 1=true por 1=atraso de confirmação de 0,100 ms, quase sempre deve ser evitada. Se houvesse um valor existente, eu até entenderia querer removê-lo, mas o certo seria também mudar o nome da configuração.
    2. O argumento de configuração de help.autocorrect ser um tempo, medido em uma unidade que não é padrão para a maioria dos usuários, é simplesmente ruim. A ativação deveria ser booleana, e o tempo de confirmação deveria poder ser ajustado com um valor decimal.
    • Sobre o item 1, acho que você entendeu mal a ordem cronológica.
      Essa mudança aconteceu em 2008, durante a revisão de código do patch inicial que adicionaria a opção como booleana, antes de ser commitada na árvore principal do git.
    • Quando se fala em “design”, penso em um planejamento intencional, em um contexto amplo.
      Isto está mais para um ramo lateral que cresceu organicamente do que para design.
  • Vejo isso como um bom exemplo de excesso incremental de recursos (creeping featurism).
    Na melhor das hipóteses, introduz complexidade desnecessária; na pior, faz as pessoas que dependem disso prestarem menos atenção ao que estão fazendo.

    • O git é exatamente assim: por cima de uma estrutura de dados elegante, há várias camadas de lixo desnecessário acumuladas ao longo dos anos.
    • Não entendo por que alguém iria querer permitir execução automática.
      É tão difícil assim apertar a seta para cima e corrigir o erro? Executar automaticamente algo “mais ou menos certo” é uma receita para fazer coisas não intencionais.
  • O erro foi aqui. Em vez de reaproveitar a configuração existente com outro significado, deveriam ter adicionado uma nova configuração
    help.autocorrect deveria ter ficado para ligar/desligar, e help.autocorrect.milliseconds para definir quanto tempo esperar
    Há erros parecidos em outros sistemas. Por exemplo, no MySQL, innodb_flush_log_at_trx_commit é desativado quando vale 0, ativado quando vale 1, e o 2 foi adicionado depois com um significado especial

    • O problema real é uma linguagem de configuração sem tipos que tenta adivinhar o que 1 significa
      Agora 1 continua sendo booleano verdadeiro, enquanto outros inteiros viram unidades de 0,1 segundo, afundando ainda mais no problema
      É uma lógica suspeita, como o famoso no == false do YAML
    • Não sei onde seria melhor usar, mas 0,1 segundo também não é um valor sem sentido
      O tempo de reação aleatória mais rápido registrado é de cerca de 1,5 ds e, por coincidência, o tempo médio de reação de gamers também fica por aí, mas reações não aleatórias podem ser muito mais rápidas. Por exemplo, ao reagir no ritmo de uma batida
      Se quiser ir tão rápido assim, é possível, e a velocidade de invocação também deve ser relativamente estável. Deve ficar na ordem de alguns milissegundos
  • Há um ano ativei a correção automática e configurei para 3 segundos, e percebi duas coisas

    1. Ela não distingue ações perigosas de ações seguras
    2. Ela polui o histórico do shell com comandos digitados errado
      Depois de ler este texto, tive finalmente o impulso para desativá-la após um ano
    • Para erros de digitação frequentes, é melhor simplesmente criar um alias
      Claro, isso também “polui” o histórico do shell
    • Sobre o item 2, o verdadeiro poluidor é você mesmo
      Dá no mesmo se você voltar no histórico e reutilizar o último comando errado só porque ele funciona de qualquer jeito
  • Unidades de 0,1 segundo são uma escolha realmente peculiar
    Seria melhor especificar atrasos em milissegundos ou segundos, e ambos são muito mais comuns em computação

    • Fiquei bem confuso por um momento. Achei que deciseconds fosse uma unidade específica do git, significando algo como decision-seconds, “segundos necessários para tomar uma decisão” xD
      Para constar, inglês não é minha língua nativa, mas venho de uma região civilizada que usa o sistema métrico
    • É uma unidade ok para tempos de reação humanos, mas incomum
      A diferença entre 0 segundo e 1 segundo é perceptivelmente longa quando se está esperando algo, mas a diferença entre n milissegundos e n+1 milissegundos é pequena demais para ser útil
  • O tempo de reação varia conforme o tipo de estímulo; o auditivo é um pouco mais rápido que o visual, e o tátil é um pouco mais rápido ainda, ficando em torno de 90–180 ms
    Então, se o git desse um tapa em vez de mostrar uma mensagem de erro, talvez houvesse tempo de reagir por pouco

    • Para esse dispositivo de tapa realmente dar a sensação de bater, ele teria que gerar inércia
      10 ms seriam suficientes para isso?
  • Ao ler este texto, lembrei de arqueologia de software e do termo “programador arqueólogo”
    Pelo segundo conceito, devemos agradecer a Vernor Vinge

    • Isso é um ponto que realmente me incomoda. Hackers exaltaram aquele livro como se ele tivesse introduzido o conceito de “arqueologia de software”, então eu estava muito ansioso para ler 『A Fire Upon The Deep』
      Mas o conceito só é insinuado rapidamente no prólogo e depois não aparece mais. Os efeitos da arqueologia são relevantes para a trama, mas o “arqueólogo de software” não era um personagem significativo na narrativa
      Fiquei com a sensação de ter sido enganado
    • Costumo dizer que o perigo da arqueologia de software é que, no fim, você acaba encontrando coprólitos
    • Não consigo afastar a sensação de que agora estão me chamando de “velho”