1 điểm bởi GN⁺ 2025-01-20 | 1 bình luận | Chia sẻ qua WhatsApp
  • help.autocorrect=1 của Git sửa lệnh gõ sai rồi chỉ chờ 0,1 giây trước khi chạy, gần như là chạy ngay lập tức nên người dùng khó kịp xác nhận hoặc hủy
  • Hành vi này không phải mặc định của Git; ở cấu hình mặc định, Git không chạy lệnh không xác định mà chỉ hiển thị các lệnh tương tự rồi thoát
  • Trong cuộc thảo luận năm 2008, help.autocorrect đã được đổi từ kiểu boolean sang thời gian chờ tính bằng decisecond, khiến 1 được hiểu là chờ 0,1 giây thay vì true
  • Hiện help.autocorrect hỗ trợ 0, số dương, immediate, prompt, never; nếu muốn xác nhận rồi mới chạy thì prompt là lựa chọn an toàn hơn
  • Cơ chế suy đoán lệnh của Git dựa trên Levenshtein distance đã chỉnh sửa, và Scott Chacon đã đề xuất một bản vá để xử lý 1 cùng các chuỗi boolean theo cách tự nhiên hơn

Từ git pushy đến khi được chạy thành git push

  • Khi @dhh nhập git pushy, Git suy đoán đó là git push và chỉ chờ 0,1 giây trước khi chạy
  • 0,1 giây là quá ngắn để người dùng đọc lệnh, đánh giá xem có đúng hay không, rồi hủy
  • Hành vi này không phải hành vi mặc định của Git, mà xuất hiện khi cấu hình help.autocorrect được bật

Hành vi mặc định và sự ra đời của help.autocorrect

  • Phản ứng mặc định của Git là không chạy lệnh không xác định, mà hiển thị các lệnh khả dĩ dựa trên độ tương đồng chuỗi rồi thoát
    • Ví dụ: git pushy có thể được hiển thị là push, lệnh giống nhất
  • Ban đầu, với lệnh không xác định, Git chỉ trả lời đơn giản rằng “không phải lệnh Git”
  • Năm 2008, Johannes Schindelin đề xuất một bản vá nhỏ: duyệt qua các lệnh đã biết để tìm lệnh giống nhất, và nếu chỉ có một ứng viên gần thì chạy lệnh đó
  • Alex Riesen đưa ra bản vá điều khiển việc này bằng cấu hình help.autocorrect; ban đầu cấu hình này là boolean
    • Trong cấu hình Git, giá trị boolean có thể hiểu 1true
    • Vì vậy, trong bối cảnh ban đầu, help.autocorrect=1 có thể trông giống như giá trị bật tự động sửa

Vì sao 1 trở thành 0,1 giây

  • Junio Hamano đề xuất không để help.autocorrect chỉ là boolean đơn giản, mà biến nó thành số decisecond cần chờ trước khi chạy
    • Decisecond là đơn vị 0,1 giây
    • Mục đích là cho người dùng cơ hội nhấn ^C
  • Trong bản vá được chấp nhận sau đó, giá trị cấu hình được đổi thành thời gian chờ
  • Kết quả là help.autocorrect=1 không có nghĩa là “bật tính năng”, mà là “chờ 1 decisecond, tức 0,1 giây, rồi chạy”
  • Lý do decisecond được chọn làm đơn vị thời gian phù hợp không còn được ghi lại trong cuộc thảo luận

Các giá trị cấu hình có thể chọn hiện nay

  • Theo tài liệu Git, help.autocorrect hỗ trợ các giá trị sau
    • 0: giá trị mặc định, chỉ hiển thị lệnh được đề xuất
    • Số dương: chạy lệnh được đề xuất sau số decisecond đã chỉ định
    • immediate: chạy ngay lệnh được đề xuất
    • prompt: hiển thị đề xuất và hỏi xác nhận có chạy hay không
    • never: không chạy và cũng không hiển thị lệnh được đề xuất
  • Nếu muốn xác nhận rồi mới chạy, prompt hợp lý hơn với hầu hết người dùng
  • Ví dụ cấu hình như sau
git config --global help.autocorrect prompt
  • Sau đó, khi nhập lệnh như git pushy, Git sẽ hỏi bằng [y/N] xem có chạy push hay không

Cách Git chọn lệnh tương tự

  • Git không đoán lệnh một cách tùy tiện; đến một ngưỡng nào đó, nó coi là quá xa và không đưa ra ứng viên
  • Hành vi ví dụ như sau
    • git bass đủ gần với rebase nên sẽ hiện xác nhận chạy
    • git bassa bị xem là không còn giống rebase nữa, nên không chạy ứng viên nào
    • git dm hiển thị cả amrm là các lệnh tương tự
    • git dma khớp với một lệnh duy nhất là am
  • Logic này dựa trên thuật toán Levenshtein distance đã chỉnh sửa
    • Thuật toán tính chi phí chỉnh sửa ký tự để biến một chuỗi thành chuỗi khác
    • Một số thao tác được tính là tốn kém hơn các thao tác khác
  • Git có cutoff được hard-code; nếu chi phí so với lệnh đã biết quá lớn, Git xem đó là người dùng đã nhập sai quá nhiều và không suy đoán

Bản vá nhằm thay đổi cách diễn giải 1

  • help.autocorrect=1 về mặt con người gần như tương đương immediate, Scott Chacon đã viết một bản vá nhỏ để hiểu 1chạy ngay thay vì chờ 0,1 giây
  • Junio Hamano yêu cầu không chỉ xử lý đặc biệt riêng "1", mà phải diễn giải đúng các giá trị chuỗi boolean như yes, no, true, off
  • Phiên bản thứ hai của bản vá đang được phát triển theo hướng bao gồm cả việc xử lý các chuỗi boolean này
  • Nếu bản vá được đưa vào, sự nhầm lẫn quanh help.autocorrect có thể giảm trong các phiên bản Git tương lai

1 bình luận

 
GN⁺ 2025-01-20
Ý kiến trên Hacker News
  • Vào thập niên 70, Hal Finney đang nhét trình thông dịch BASIC cho Mattel Intellivision vào ROM 2KB, nên từng byte đều quý giá
    Để hiển thị lỗi cú pháp, ông rút gọn mọi thông báo lỗi thành EH?, và đến giờ vẫn buồn cười ở chỗ chính ông khá tự hào về điều đó

    • EH? có vẻ cũng rất hợp làm phản hồi của bộ phân tích cú pháp văn bản trong các trò interactive fiction kiểu cũ
      Hơi liên quan một chút, trong vài biến thể BASIC ngày xưa cũng có thể viết câu lệnh PRINT thành ?, nhưng có lẽ mục đích gần với việc giảm thời gian gõ trong REPL hơn là tiết kiệm bộ nhớ
    • Lãng phí quá. ed chỉ dùng một dấu ? cho mọi lỗi, nên tiết kiệm gấp 3 lần
    • Trường hợp sớm nhất tôi thấy dùng Eh? làm phản hồi của trình thông dịch là trong JOSS của 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
      Bộ nhớ khoảng 5KB, nhưng so với Intellivision thì cái máy nặng khoảng 5.000 pound
    • Khá thú vị. Tôi không biết Hal từng là hacker máy tính cá nhân thời đó; cứ nghe đến Hal là tôi luôn nghĩ tới Bitcoin
    • Tôi vận hành xordle, một trò phái sinh từ Wordle, trong đó một bảng có hai câu đố Wordle
      Vì vậy có thể bạn đoán một từ và cả 5 chữ cái đều xanh, nhưng nó vẫn không phải là một trong hai đáp án. Khi đó tôi cho hiện đơn giản Huh? ở bên phải, và mọi người thích chi tiết đó
  • Nguyên nhân gốc rễ là tên cấu hình được đặt tệ
    Nếu ban đầu cấu hình được đặt kiểu boolean như help.autocorrect_enabled, thì yêu cầu cho nó nhận giá trị số nguyên rồi diễn giải theo đơn vị 0,1 giây đã không hợp lý. Thay vào đó hẳn cần một cấu hình khác như help.autocorrect_accept_after_dsec, và vì dsec quá lạ nên ai dùng cũng buộc phải tra
    Khi review code tôi luôn yêu cầu điều này. Nếu có thể mơ hồ, tên biến phải có đơn vị. Ví dụ int timeout nên là int timeout_msec
    Với tên cấu hình, điều này còn quan trọng gấp 100 lần. Vì cấu hình là một phần của giao diện công khai nên về sau không thể đổi

    • Tôi cũng nghĩ vậy. Nhưng khi chuyện này bị đẩy vào hệ thống kiểu thì tôi vẫn còn băn khoăn
      Trong bối cảnh C++, tiêu chí đại khái là void FooBar(std::chrono::milliseconds timeout); thì ổn. Vì đó là chữ ký hàm, khi nhìn vào cũng thấy luôn kiểu
      Nhưng với biến thì timeout không ổn. Trong 99% trường hợp, lúc sử dụng thực tế ta sẽ thấy kiểu như auto timeout = gl_timeout; hoặc FooBar(timeout);
      Vì C++ dùng auto phổ biến, việc lần theo kiểu chính xác khi quan trọng trở nên khá phiền
      Khi làm C++ tôi có dùng IDE hoặc trình soạn thảo gắn language server, nhưng không có thời gian cứ 5 giây lại rê chuột lên để kiểm tra kiểu
    • Đúng, và việc dùng đơn vị 0,1 giây (decisecond), một đơn vị thời gian mà cả đời hầu như chưa ai viết trực tiếp lần nào, còn làm tình hình tệ hơn
      Nếu thấy thông báo “sẽ chạy sau 1ms” thì hẳn họ đã kiểm tra lại cấu hình ngay
    • Cứ thế rồi sẽ thành trạng thái như systemd, nơi có thể viết cả TimoutSec=60 lẫn TimeoutSec=1min
      Tôi nghĩ thà đừng đưa đơn vị vào tên còn hơn. Dù vậy, ngoài trường hợp đặc biệt đó ra thì tôi hoàn toàn đồng ý
    • Tôi cũng làm vậy, nhưng khó gạt bỏ cảm giác nó có mùi ký pháp Hungary
      Phương án tốt nhất tôi tìm được đến giờ là để giá trị nhận kèm đơn vị. Ví dụ cho phép 5 seconds hoặc 5s, còn chỉ 1 thì coi là giá trị sai
    • Khi review code, tôi sẽ đánh dấu chính việc dùng int như vậy và khuyến nghị dùng lớp giá trị truyền đơn vị đúng cách
      Ví dụ như Second(2) hoặc Millisecond(2000)
      Tất nhiên điều này tùy vào tính năng và quy ước của ngôn ngữ
  • xmobar cũng dùng đơn vị 0,1 giây ở một chỗ tương tự nhưng còn có vấn đề hơn. Đó là cấu hình khai báo mỗi section nên được làm mới thường xuyên ra sao
    Các con số trong cấu hình ví dụ nhỏ đến mức khó có thể là mili giây, nên khiến người ta hợp lý giả định là giây, và kết quả là lệnh bị chạy thường xuyên gấp 10 lần dự định
    Tôi đã thấy nhiều lần tải tăng đột biến ngoài ý muốn bắt nguồn từ vấn đề này

  • Có vẻ là thiết kế khá tệ
    Tuy nhiên điểm 1 là do đọc nhầm bài, và “giá trị trước đó” chưa từng tồn tại trong git

    1. Gần như luôn nên tránh thay đổi âm thầm cách diễn giải giá trị cấu hình hiện có sang nghĩa khác, chẳng hạn đổi 1=true thành 1=độ trễ xác nhận 0,100ms. Nếu từng có giá trị cũ thì có thể muốn xóa, nhưng đúng ra cũng nên đổi cả tên cấu hình
    2. Việc đối số cấu hình của help.autocorrect là thời gian, lại được đo bằng một đơn vị không chuẩn với đa số người dùng, đơn giản là tệ. Nên nhận boolean cho việc bật tính năng, và cho chỉnh thời gian xác nhận bằng giá trị thập phân
    • Về điểm 1, có vẻ bạn đã hiểu nhầm trình tự thời gian
      Thay đổi đó diễn ra năm 2008, trong quá trình review code của bản vá ban đầu định thêm tùy chọn này dưới dạng boolean, và trước khi nó được commit vào cây git chính
    • Nói “thiết kế” khiến người ta nghĩ tới một kế hoạch có chủ ý trong bối cảnh rộng
      Cái này giống một nhánh phụ mọc lên hữu cơ hơn là thiết kế
  • Tôi xem đây là một ví dụ hay về chủ nghĩa nhồi nhét tính năng (creeping featurism)
    Nhìn tích cực thì nó đưa vào độ phức tạp không cần thiết; nhìn tiêu cực thì khiến những người phụ thuộc vào nó bớt cẩn trọng về việc mình đang làm

    • git đúng là như vậy. Trên một cấu trúc dữ liệu thanh nhã là nhiều lớp rác không cần thiết tích tụ qua năm tháng
    • Tôi không hiểu vì sao lại muốn cho phép tự động thực thi
      Nhấn mũi tên lên rồi sửa lỗi khó đến thế sao? Tự động chạy thứ “đại khái đúng” là công thức dẫn tới việc làm điều ngoài ý muốn
  • Sai lầm nằm ở đây. Đáng lẽ không nên tái sử dụng cấu hình cũ với ý nghĩa khác, mà phải thêm cấu hình mới
    help.autocorrect nên được tách thành bật/tắt, còn help.autocorrect.milliseconds là chờ bao lâu
    Các hệ thống khác cũng có lỗi tương tự. Ví dụ innodb_flush_log_at_trx_commit của MySQL: 0 là vô hiệu hóa, 1 là bật, và 2 được thêm sau đó với một ý nghĩa đặc biệt

    • Vấn đề thật sự là ngôn ngữ cấu hình không có kiểu cố đoán xem 1 nghĩa là gì
      Giờ thì 1 vẫn là boolean đúng, còn các số nguyên khác lại được tính theo đơn vị 0,1 giây, khiến mọi thứ càng lún sâu hơn
      Đây là kiểu logic đáng ngờ giống như no == false khét tiếng của YAML
    • Không biết dùng ở đâu là hợp nhất, nhưng 0,1 giây cũng không phải là một giá trị vô lý
      Theo ghi nhận, thời gian phản ứng ngẫu nhiên nhanh nhất khoảng 1,5ds, và tình cờ thời gian phản ứng trung bình của game thủ cũng tầm đó, nhưng phản ứng không ngẫu nhiên có thể nhanh hơn nhiều. Ví dụ như phản ứng theo nhịp
      Nếu muốn nhanh đến mức đó thì vẫn có thể, và tốc độ gọi lệnh cũng phải tương đối ổn định. Có lẽ ở mức vài mili giây
  • Một năm trước tôi bật tính năng tự sửa và đặt thành 3 giây, rồi nhận ra hai điều

    1. Nó không phân biệt thao tác nguy hiểm và thao tác an toàn
    2. Nó làm “ô nhiễm” lịch sử shell bằng lệnh gõ sai
      Đọc bài này xong thì sau một năm tôi đã có đủ lý do để tắt nó
    • Thà tạo alias cho các lỗi gõ thường gặp còn hơn
      Tất nhiên như vậy cũng sẽ “làm bẩn” lịch sử shell
    • Về điểm 2, người thực sự làm bẩn là chính bạn
      Quay lại lịch sử rồi dùng lại nguyên lệnh sai cuối cùng chỉ vì dù sao nó cũng chạy được thì cũng như vậy thôi
  • Đơn vị 0,1 giây thật sự là một lựa chọn kỳ lạ
    Độ trễ nên được chỉ định bằng mili giây hoặc giây, cả hai đều phổ biến hơn nhiều trong điện toán

    • Tôi đã khá bối rối một lúc. Tôi tưởng deciseconds là đơn vị riêng của git, nghĩa là decision-seconds kiểu “số giây cần để đưa ra quyết định” xD
      Nhân tiện, tiếng Anh không phải tiếng mẹ đẻ của tôi, nhưng tôi đến từ một vùng văn minh dùng hệ mét
    • Với thời gian phản ứng của con người thì cũng ổn, nhưng đây là đơn vị không phổ biến
      Chênh lệch giữa 0 giây và 1 giây đủ dài để nhận thấy khi chờ đợi điều gì đó, còn chênh lệch giữa n mili giây và n+1 mili giây thì quá nhỏ để hữu ích
  • Thời gian phản ứng khác nhau tùy loại kích thích; thính giác hơi nhanh hơn thị giác, còn xúc giác nhanh hơn chút nữa, vào khoảng 90~180ms
    Vì vậy nếu git đấm bạn một cái thay vì hiện thông báo lỗi, có khi bạn vẫn vừa kịp phản ứng

    • Để thiết bị đấm đó cho cảm giác như bị đánh thật, nó phải tạo ra quán tính
      10ms liệu có đủ không?
  • Đọc bài này làm tôi nhớ đến khảo cổ học phần mềm và cụm “lập trình viên khảo cổ”
    Khái niệm sau thì phải cảm ơn Vernor Vinge

    • Đây là điểm thật sự gây khó chịu. Các hacker cứ ca ngợi như thể cuốn sách đó đã đưa ra khái niệm “khảo cổ học phần mềm”, nên tôi đã rất háo hức đọc 『A Fire Upon The Deep』
      Nhưng khái niệm đó chỉ được gợi ý thoáng qua trong phần mở đầu, rồi sau đó hoàn toàn biến mất. Tác động của khảo cổ học có liên quan đến cốt truyện, nhưng “nhà khảo cổ phần mềm” không phải là nhân vật có ý nghĩa trong tự sự
      Tôi có cảm giác như bị câu view
    • Người ta hay nói rằng rủi ro của khảo cổ học phần mềm rốt cuộc là sẽ phát hiện ra coprolite (phân hóa thạch)
    • Tôi không thể gạt bỏ cảm giác như bây giờ mình đang bị gọi là “già”