1P by GN⁺ | ★ favorite | 댓글 1개
  • Git의 help.autocorrect=1은 오타 명령을 고친 뒤 0.1초만 기다리고 실행해, 사용자가 확인하거나 취소하기에는 사실상 즉시 실행에 가까움
  • 이 동작은 Git 기본값이 아니며, 기본 설정에서는 알 수 없는 명령을 실행하지 않고 유사한 명령만 보여준 뒤 종료함
  • 2008년 논의에서 help.autocorrect가 불리언이 아니라 decisecond 단위 대기 시간으로 바뀌면서, 1true가 아닌 0.1초 대기로 해석됨
  • 현재 help.autocorrect0, 양수, immediate, prompt, never를 지원하며, 확인 후 실행하려면 prompt 가 더 안전한 선택임
  • Git의 명령 추정은 수정된 Levenshtein distance 기반이며, Scott Chacon은 1과 불리언 문자열을 더 자연스럽게 처리하는 패치를 제안함

git pushygit push로 실행되기까지

  • @dhhgit pushy를 입력했을 때 Git은 이를 git push로 추정하고, 실행 전 0.1초만 기다림
  • 0.1초는 사용자가 명령을 읽고, 맞는지 판단하고, 취소하기에 너무 짧은 시간임
  • 이 동작은 Git의 기본 동작이 아니라 help.autocorrect 설정이 켜져 있을 때 나타남

기본 동작과 help.autocorrect의 탄생

  • Git의 기본 반응은 알 수 없는 명령을 실행하지 않고, 문자열 유사도에 따라 가능한 명령을 보여준 뒤 종료하는 것임
    • 예: git pushypush가 가장 유사한 명령이라고 표시할 수 있음
  • 원래 Git은 알 수 없는 명령에 대해 단순히 “Git 명령이 아님”이라고만 응답했음
  • 2008년 Johannes Schindelin은 알려진 명령을 훑어 가장 비슷한 명령을 찾고, 가까운 후보가 하나뿐이면 실행하는 작은 패치를 제안함
  • Alex Riesen은 이를 help.autocorrect 설정으로 제어하는 패치를 냈고, 초기에는 이 설정이 불리언이었음
    • Git 설정에서 불리언 값은 1true로 해석할 수 있음
    • 그래서 원래 맥락에서는 help.autocorrect=1이 자동 보정을 켜는 값처럼 보일 수 있었음

1이 0.1초가 된 이유

  • Junio Hamano는 help.autocorrect를 단순 불리언이 아니라, 실행 전 기다릴 decisecond 수로 만들자고 제안함
    • decisecond는 0.1초 단위임
    • 사용자가 ^C를 누를 기회를 주려는 의도였음
  • 이후 받아들여진 패치에서 설정값은 대기 시간으로 바뀜
  • 그 결과 help.autocorrect=1은 “기능을 켠다”가 아니라 “1 decisecond, 즉 0.1초 기다린 뒤 실행한다”는 뜻이 됨
  • 왜 decisecond가 적절한 시간 단위로 선택됐는지는 논의에 남아 있지 않음

지금 선택할 수 있는 설정값

  • Git 문서 기준 help.autocorrect는 다음 값을 지원함
    • 0: 기본값이며, 제안 명령만 보여줌
    • 양수: 지정한 decisecond 뒤 제안 명령을 실행함
    • immediate: 제안 명령을 즉시 실행함
    • prompt: 제안을 보여주고 실행 여부를 확인함
    • never: 제안 명령을 실행하지도, 보여주지도 않음
  • 확인 후 실행을 원한다면 prompt가 대부분의 사용자에게 더 합리적임
  • 설정 예시는 다음과 같음
git config --global help.autocorrect prompt
  • 이후 git pushy 같은 명령을 입력하면 push를 실행할지 [y/N]로 확인함

Git이 비슷한 명령을 고르는 방식

  • Git은 무작정 명령을 추정하지 않고, 어느 지점부터는 너무 멀다고 보고 후보를 내지 않음
  • 예시 동작은 다음과 같음
    • git bassrebase에 충분히 가까워 실행 확인을 띄움
    • git bassa는 더 이상 rebase로 보기 어렵다고 판단해 후보를 실행하지 않음
    • git dmamrm을 모두 유사한 명령으로 보여줌
    • git dmaam 하나로 매칭됨
  • 이 로직은 수정된 Levenshtein distance 알고리듬에 기반함
    • 한 문자열을 다른 문자열로 바꾸는 데 드는 문자 편집 비용을 계산함
    • 일부 연산은 다른 연산보다 더 비싸게 취급됨
  • Git에는 하드코딩된 cutoff가 있어, 알려진 명령과의 비용이 너무 크면 사용자가 크게 잘못 입력한 것으로 보고 추정하지 않음

1 해석을 바꾸려는 패치

  • help.autocorrect=1은 사람 기준으로 사실상 immediate와 같기 때문에, Scott Chacon은 1을 0.1초 대기가 아니라 즉시 실행으로 해석하는 작은 패치를 작성함
  • Junio Hamano는 "1"만 특수 처리하지 말고, yes, no, true, off 같은 불리언 문자열 값을 제대로 해석하자고 요청함
  • 패치의 두 번째 버전은 이러한 불리언 문자열 처리까지 포함하는 방향으로 진행 중임
  • 패치가 반영되면 향후 Git 버전에서 help.autocorrect의 혼동이 줄어들 수 있음

댓글과 토론

Hacker News 의견들
  • 70년대에 Hal Finney가 Mattel Intellivision용 BASIC 인터프리터를 2KB ROM에 맞추고 있었는데, 바이트 하나하나가 귀했음
    문법 오류를 표시하기 위해 모든 오류 메시지를 EH?로 줄였고, 본인은 그걸 꽤 자랑스러워했다는 점이 아직도 웃김

    • EH?는 옛날식 인터랙티브 픽션 게임의 텍스트 파서 응답으로도 잘 어울릴 것 같음
      약간 관련해서, 예전 BASIC 변종 중에는 PRINT 문을 ?로 쓰는 것도 있었는데, 메모리 절약보다는 REPL에서 타이핑 시간을 줄이려는 목적에 가까웠던 것 같음
    • 낭비가 심하네. ed는 모든 오류에 ? 하나만 쓰니 3배 절약
    • 인터프리터 응답으로 Eh?를 쓴 가장 이른 사례는 RAND의 JOSS에서 봤음
      [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
      메모리는 약 5KB였지만, Intellivision과 비교하면 기계 무게가 약 5,000파운드였음
    • 꽤 멋지다. Hal이 그 시절 개인용 컴퓨터 해커였다는 건 몰랐고, Hal 얘기를 들으면 항상 Bitcoin이 떠오름
    • Wordle 파생 게임인 xordle을 운영하는데, 한 보드에 Wordle 퍼즐 두 개가 들어감
      그래서 어떤 단어를 추측해 5글자가 전부 초록색이 됐는데도 두 정답 중 어느 것도 아닐 수 있음. 그럴 때 오른쪽에 그냥 Huh?라고 뜨게 했는데, 사람들이 그 부분을 좋아함
  • 근본 원인은 설정 이름이 나쁘게 지어진 것
    원래 설정이 help.autocorrect_enabled처럼 불리언스럽게 지어졌다면, 정수값을 받아 0.1초 단위로 해석하자는 요청은 말이 안 됐을 것임. 대신 help.autocorrect_accept_after_dsec 같은 다른 설정이 필요했을 테고, dsec는 워낙 생소해서 쓰는 사람이라면 찾아볼 수밖에 없었을 것임
    코드 리뷰에서 늘 이런 걸 요구함. 모호할 수 있으면 변수명에 단위가 들어가야 함. 예를 들어 int timeoutint timeout_msec가 되어야 함
    설정 이름에서는 이게 100배 더 중요함. 설정은 공개 인터페이스의 일부라서 나중에 바꿀 수 없기 때문임

    • 같은 생각임. 다만 이게 타입 시스템으로 밀려 들어갈 때는 아직도 고민됨
      C++ 맥락에서 대략적인 기준은 void FooBar(std::chrono::milliseconds timeout);은 괜찮음. 함수 시그니처라서 볼 때 타입도 같이 보이기 때문임
      하지만 변수에서 timeout은 안 괜찮음. 99%의 경우 실제 사용은 auto timeout = gl_timeout;이나 FooBar(timeout);처럼 보게 됨
      C++에서 auto를 흔히 쓰다 보니, 중요할 때 정확한 타입을 추적하는 게 꽤 귀찮아짐
      C++ 작업할 때 IDE나 언어 서버 붙은 편집기를 쓰지만, 5초마다 마우스를 올려 타입을 확인할 시간은 없음
    • 맞고, 여기에 평생 문자 그대로 0번 써본 시간 단위인 0.1초 단위(decisecond) 를 쓴 게 상황을 더 악화시킴
      “1ms 뒤에 실행합니다”라는 메시지를 보면 바로 설정을 확인했을 것임
    • 그러다 보면 systemd처럼 TimoutSec=60도 쓰고 TimeoutSec=1min도 쓸 수 있는 상태가 됨
      차라리 단위를 이름에 안 넣는 편이 나았을 거라고 봄. 다만 그 특이한 경우만 빼면 전적으로 동의함
    • 그렇게 하긴 하지만, 헝가리안 표기법 냄새가 난다는 생각을 떨치기 어려움
      지금까지 찾은 가장 나은 대안은 값에 단위를 받는 것임. 예를 들어 5 seconds5s를 허용하고, 그냥 1은 잘못된 값으로 처리하는 방식임
    • 코드 리뷰에서 그런 int 사용 자체를 표시하고, 대신 단위를 제대로 전달하는 값 클래스를 권함
      예를 들어 Second(2)Millisecond(2000) 같은 식임
      물론 이건 언어의 기능과 관습에 따라 달라짐
  • xmobar도 비슷하지만 더 문제 있는 곳에서 0.1초 단위를 씀. 각 섹션을 얼마나 자주 새로고침할지 선언하는 설정임
    예제 설정의 숫자가 너무 작아서 밀리초일 리는 없어 보이고, 그래서 합리적으로 초라고 가정하게 만들고, 결과적으로 의도보다 10배 자주 명령을 실행하게 됨
    이 문제에서 비롯된 우발적 부하 급증을 여러 번 봤음

  • 꽤 나쁜 설계로 보임
    다만 1번은 글을 잘못 읽은 결과였고, “이전 값”은 git에 존재한 적이 없었음

    1. 기존 설정값을 조용히 다른 의미로 재해석하는 변경, 예를 들어 1=true1=0.100ms 확인 지연으로 바꾸는 일은 거의 항상 피해야 함. 기존 값이 있었다면 지우고 싶겠지만, 설정 이름도 바꾸는 게 맞음
    2. help.autocorrect의 설정 인자가 시간이고, 대부분 사용자에게 표준적이지 않은 단위로 측정된다는 건 그냥 나쁨. 활성화는 불리언으로 받고, 확인 시간은 소수값으로 조절하게 해줘야 함
    • 1번에 대해서는 시간순서를 오해한 것 같음
      그 변경은 2008년에, 해당 옵션을 불리언으로 추가하려는 초기 패치의 코드 리뷰 중에 일어났고, 메인 git 트리에 커밋되기 전이었음
    • “설계”라고 하면 의도적인 넓은 맥락의 계획을 떠올리게 됨
      이건 설계라기보다 유기적으로 자라난 곁가지에 가까움
  • 이건 기능 과잉(creeping featurism) 의 좋은 예라고 봄
    좋게 봐도 불필요한 복잡성을 들여오고, 나쁘게 보면 거기에 의존하는 사람들이 자기가 뭘 하는지 덜 주의하게 만듦

    • git이 딱 그렇다. 우아한 자료 구조 위에 세월이 지나며 쌓인 불필요한 쓰레기 층이 여러 겹 덮여 있음
    • 왜 자동 실행을 허용하고 싶어 하는지 이해가 안 됨
      위쪽 화살표를 누르고 실수를 고치는 게 그렇게 어려운가? “대충 맞는” 것을 자동으로 실행하는 건 의도하지 않은 일을 하게 되는 레시피임
  • 실수는 여기 있었음. 기존 설정을 다른 의미로 재활용하지 말고 새 설정을 추가했어야 함
    help.autocorrect는 켜기/끄기, help.autocorrect.milliseconds는 얼마나 기다릴지로 나눴어야 함
    다른 시스템에도 비슷한 실수가 있음. 예를 들어 MySQL의 innodb_flush_log_at_trx_commit은 0이면 비활성, 1이면 활성이고, 2가 나중에 특수한 의미로 추가됨

    • 진짜 문제는 1이 무엇을 뜻하는지 추측하려는 타입 없는 설정 언어
      이제 1은 불리언 참으로 두면서 다른 정수는 0.1초 단위로 만들며 더 깊이 빠지고 있음
      YAML의 악명 높은 no == false와 같은 의심스러운 논리임
    • 어디에 쓰는 게 가장 좋을지는 모르겠지만, 0.1초도 말이 안 되는 값은 아님
      기록상 가장 빠른 무작위 반응 시간이 1.5ds 정도이고, 우연히 평균 게이머 반응 시간도 그쯤이지만, 비무작위 반응은 훨씬 빠를 수 있음. 예를 들어 박자에 맞춰 반응하는 경우가 그렇다
      그렇게 빠르게 가고 싶다면 가능하고, 호출 속도도 비교적 안정적이어야 함. 대략 몇 밀리초 수준일 것임
  • 1년 전에 자동 수정 기능을 켜고 3초로 설정했는데, 두 가지를 느꼈음

    1. 위험한 동작과 안전한 동작을 구분하지 않음
    2. 잘못 입력한 명령으로 셸 히스토리를 오염시킴
      이 글을 읽고 나니 1년 만에 끌 만큼의 계기가 됐음
    • 차라리 자주 하는 오타에는 별칭(alias) 을 만드는 편이 나음
      물론 셸 히스토리를 “오염”시키긴 함
    • 2번에 대해서는, 실제 오염자는 본인임
      히스토리를 거슬러 올라가서, 어차피 동작한다는 이유로 마지막의 잘못된 명령을 그대로 다시 쓰더라도 마찬가지임
  • 0.1초 단위는 정말 특이한 선택임
    지연 시간은 밀리초나 초로 지정하는 편이 낫고, 둘 다 컴퓨팅에서 훨씬 흔하게 쓰임

    • 잠깐 꽤 헷갈렸음. deciseconds가 git 전용 단위로, “결정을 내리는 데 필요한 초” 같은 decision-seconds를 뜻하는 줄 알았음 xD
      참고로 영어가 모국어는 아니지만, 미터법을 쓰는 문명화된 지역 출신임
    • 사람의 반응 시간에는 괜찮지만 흔치 않은 단위임
      0초와 1초의 차이는 뭔가를 기다릴 때 눈에 띄게 길지만, n밀리초와 n+1밀리초의 차이는 유용하게 쓰기엔 너무 미세함
  • 반응 시간은 자극 종류에 따라 다르고, 청각이 시각보다 약간 빠르며 촉각은 그보다 조금 더 빨라 90~180ms 정도임
    그래서 git이 오류 메시지 대신 한 대 때려준다면, 간신히 반응할 시간이 있을지도 모름

    • 그 때리는 장치가 맞는 느낌을 주려면 관성을 만들어야 함
      10ms면 그게 충분할까?
  • 이 글을 읽으니 소프트웨어 고고학과 “프로그래머 고고학자”라는 말이 떠오름
    뒤의 개념은 Vernor Vinge에게 감사해야 함

    • 이건 정말 거슬리는 지점임. 해커들이 “소프트웨어 고고학” 개념을 그 책이 도입했다고 띄워서, 『A Fire Upon The Deep』을 읽는 게 무척 기대됐음
      그런데 그 개념은 프롤로그에서 잠깐 암시되고, 그 뒤로는 전혀 없음. 고고학의 효과는 줄거리와 관련 있지만, “소프트웨어 고고학자”는 서사에서 의미 있는 인물이 아니었음
      낚였다는 느낌이 들었음
    • 소프트웨어 고고학의 위험은 결국 분석(糞石) 을 발견하게 된다는 점이라고 말하곤 함
    • 지금 나를 “늙었다”고 부르는 것 같은 느낌을 지울 수 없음