3 điểm bởi GN⁺ 2024-11-26 | 1 bình luận | Chia sẻ qua WhatsApp
  • Trong môi trường đặt cả kho lưu trữ cá nhân và công việc dưới ~/workspace, việc tách Git identity theo remote URL chính xác hơn là theo vị trí thư mục
  • includeIf của Git có thể tải cấu hình theo từng đường dẫn bằng gitdir, nhưng nếu các kho của nhiều tài khoản bị trộn trong cùng một thư mục làm việc thì cách phân nhánh theo đường dẫn sẽ chạm giới hạn
  • Dùng điều kiện hasconfig:remote.*.url: thì có thể include các tệp cấu hình riêng theo mẫu remote URL như GitHub, GitLab, SourceHut, hoặc một tổ chức GitHub cụ thể
  • Khóa SSH cần được quản lý riêng trong ~/.ssh/config bằng Host, Hostname, User, IdentityFile; và để dùng khóa theo từng tổ chức ngay cả trên cùng github.com thì cần bí danh Host
  • Nếu cấu hình thêm url.<base>.insteadOf, bạn vẫn có thể dùng git@github.com:orgname/project như thường lệ, nhưng bên trong nó sẽ được thay thành gh-work:orgname để đi qua đúng cấu hình SSH

Tách cấu hình Git theo remote URL

  • Ví dụ includeIf truyền thống sẽ include các tệp cấu hình khác nhau theo đường dẫn thư mục cục bộ như gitdir:~/code/**, gitdir:~/work/**
    • Dưới ~/code có thể tải ~/.config/git/personal, dưới ~/work có thể tải ~/.config/git/work
    • Các tệp được include thường chứa Git identity và khóa ký như user.name, user.email, user.signingkey
  • Nếu đặt toàn bộ mã nguồn dưới ~/workspace, thì các kho cá nhân, work-1, work-2 có thể bị trộn trong cùng một cấu trúc đường dẫn, khiến điều kiện theo đường dẫn khó phân tách như mong muốn
  • Dùng hasconfig:remote.*.url: của Git thì chỉ khi kho hiện tại có remote URL nhất định mới include tệp cấu hình tương ứng
    • Nếu khớp git@github.com:*/** thì include ~/.config/git/config-gh
    • Nếu khớp git@github.com:orgname/** thì include ~/.config/git/config-gh-org
    • Nếu khớp git@gitlab.com:*/** thì include ~/.config/git/config-gl
    • Nếu khớp git@git.sr.ht:*/** thì include ~/.config/git/config-srht
  • Git sẽ include cấu hình khớp sau cùng, nên thứ tự điều kiện rất quan trọng
    • Điều kiện github.com:orgname/** phải nằm dưới điều kiện github.com:*/** chung, để cấu hình riêng cho tổ chức không bị cấu hình GitHub chung ghi đè
  • Kết quả là các kho có remote github.com:orgname/** sẽ dùng config-gh-org, còn các kho GitHub khác sẽ dùng cấu hình GitHub thông thường

Khớp thông tin kết nối theo từng tổ chức bằng khóa SSH và insteadOf

1 bình luận

 
GN⁺ 2024-11-26
Các ý kiến trên Hacker News
  • Thay vì dùng insteadOf, hãy clone kho lưu trữ dưới dạng gh-work:org/repo, rồi trong cấu hình Git đặt includeIf "hasconfig:remote.*.url:gh-work:**/**"
    Làm như vậy, các kho lưu trữ được clone bằng danh tính SSH được định nghĩa dưới gh-work sẽ tự động lấy cấu hình gh-work.inc, trong đó có danh tính Git và khóa ký cùng các thiết lập SSH
    Rốt cuộc, tên gh-work trở thành tiêu chí phân biệt danh tính SSH và danh tính Git, nên dễ hiểu hơn

    • Cách giải quyết trong bài khiến tôi hơi lấn cấn vì có vẻ có nhiều mức độ tự do hơn cần thiết, nhưng đây trông như một cách thanh lịch để giảm tham số runtime xuống còn một
    • includeIf phân biệt chữ hoa/thường, và về mức ưu tiên thì cấu hình cuối cùng sẽ thắng
      Để kiểm tra xem nó có hoạt động đúng không, chỉ cần chạy git remote get-url origingit config --get user.email
    • Cách này có thể làm hỏng các script kỳ vọng URL kho lưu trữ từ xa có một dạng cụ thể
  • Tôi cho rằng cách tốt hơn là đặt alias theo từng danh tính trong .gitconfigHOME, rồi ngay sau khi khởi tạo hoặc clone kho lưu trữ thì chạy git config-company hoặc git config-personal
    Bật user.useConfigOnly = true, rồi trong alias đặt user.email, user.name, core.sshCommand của kho lưu trữ cục bộ tương ứng với khóa SSH cá nhân/công ty là được

    • Vấn đề là làm sao clone ban đầu nếu ngay từ đầu chưa có cấu hình SSH đúng
      Ưu điểm của cách trong bài có vẻ là nếu clone từ tổ chức thì nó cứ thế hoạt động
  • Trước đây ở một startup, có một người mỗi ngày đổi danh tính thành một cái tên vu vơ kiểu truyện cổ tích
    Commit thứ Hai là Mr. Bunnymann, commit thứ Ba là Doctor Funtime, kiểu vậy, nên khi làm forensics cho hệ thống quản lý phiên bản thì rất bất tiện
    Nếu nhìn rộng lượng, có thể người đó muốn nhắc rằng ai cũng có thể điền bất cứ giá trị nào vào cấu hình danh tính, nên không nên quá tin vào giá trị đó

    • Nếu là văn hóa không đổ lỗi, thì trong forensics của hệ thống quản lý phiên bản, khi nào và chuyện gì xảy ra quanh thay đổi nào sẽ quan trọng hơn ai đã làm
      Dù vậy, biết ai đã làm vẫn hữu ích khi cần hỏi chi tiết hoặc dự đoán phong cách và chuyên môn
      Nếu yêu cầu commit có chữ ký GPG và đăng ký các danh tính GPG được phép, có thể nhận diện tác giả thực sự bằng chữ ký thay vì metadata tác giả/committer
      Tất nhiên “đơn giản” và chữ ký GPG không phải lúc nào cũng đi đôi với nhau
    • Chỉ cần tin ở mức bạn tin tài liệu hay chữ ký do nhân viên viết
      Nếu không thể tin rằng nhân viên sẽ nhận diện đúng commit của chính họ, thì tôi nghĩ nên sa thải họ
    • Nhìn rộng lượng thì tôi tò mò liệu họ có dùng cùng một khóa ký hay không
    • Thật ngạc nhiên là người đó được trả tiền để làm mấy trò đùa như vậy
    • Git có hỗ trợ sẵn việc tách riêng tác giả và committer, và có lẽ người đó chỉ đổi thuộc tính tác giả
  • Không cần động đến ~/.ssh/config; chỉ cần đặt core.sshCommand = /usr/bin/ssh -o IdentitiesOnly=yes -i ~/.ssh/IdentityFile2 -a trong ~/.gitconfig hoặc ~/.config/git/personal như trong bài là được
    Như vậy submodule cũng dễ xử lý hơn mà không cần insteadOf

    • Vẫn còn câu hỏi là nếu có nhiều hơn một danh tính SSH thì làm thế nào
  • Tôi đã dùng includeIf theo thư mục từ lâu rồi (https://www.bobek.cz/til/git-identities/), nhưng hasconfig:remote thật sự gọn gàng
    Nó hoạt động cả khi clone kho lưu trữ

  • includeIf khá tốt
    Hiện tôi để phần phức tạp của SSH trong ~/.ssh, rồi tạo một include cho mỗi khách hàng/dự án/danh tính
    Với những nơi không có hostname riêng như GitHub, tôi đặt alias host kiểu customer-github, rồi cấu hình như HostName github.com, IdentityFile ~/.ssh/customer_rsa, User git
    Sau đó chỉ cần dùng alias đó trong git clone là xong

  • Tôi cũng gặp vấn đề tương tự, và giờ coi như đã có lời giải
    Nếu dùng NixOS và home-manager trên Linux và Mac thì cấu hình này trở nên đơn giản
    Chỉ cần đặt condition = "hasconfig:remote.*.url:git@github.com:/**" và cấu hình user.email trong programs.git.includes
    Tham khảo: https://nix-community.github.io/home-manager/options.xhtml#opt-programs.git.includes

    • Trông có vẻ kém đơn giản hơn so với viết trực tiếp vào .gitconfig
      Điều kiện và cấu hình giống như trong bài, nhưng còn thêm bước build/template và việc học một ngôn ngữ lập trình mới với cú pháp khác thường
  • Tôi vốn đã tách cấu hình công việc và cá nhân bằng includeIf: "gitdir", nhưng hasconfig:remote là một tính năng hoàn toàn thay đổi cuộc chơi

    • Không thể tin được là kho báu này đã nằm ẩn dưới dạng bản nháp suốt 3 năm
  • Với consultant, tôi luôn khuyên mạnh mẽ rằng nên dùng máy riêng cho công việc, hoặc ít nhất là người dùng OS riêng
    Dùng máy cá nhân cho công việc có nguy cơ khiến bạn gặp rắc rối lớn

    • “Dùng máy cá nhân cho công việc” có phạm vi rất rộng
      Có trường hợp ở công ty ưu tiên làm việc từ xa, bạn tự chuẩn bị laptop và cứ 2–3 năm lại được cấp tiền mua máy mới, nhưng đó vẫn là laptop cá nhân; cũng có thể là contractor tạm thời
      Cần giải thích cụ thể hơn trong tình huống nào và vì sao nó thành vấn đề
      Rủi ro là có thật, nhưng nếu không liệt kê được thì nó gần với việc gieo rắc FUD hơn là giáo dục
  • Đây là công cụ tôi tạo để dễ đổi danh tính Git theo từng dự án: https://github.com/cquintana92/git-switch-user
    Sau khi thiết lập danh tính, chạy $ git su Personal hoặc $ git su Work thì email, tên, khóa SSH, và tùy chọn cả khóa PGP sẽ được đặt vào .git/config của kho lưu trữ
    Nó đã tiết kiệm cho tôi rất nhiều thời gian

    • Cũng có công cụ quản lý danh tính GitHub cho truy cập Git qua SSH: https://github.com/dolmen/github-keygen
      Công cụ này đã 12 năm tuổi nhưng vẫn đang được bảo trì tích cực