3 คะแนน โดย GN⁺ 2024-11-26 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • ในสภาพแวดล้อมที่เก็บทั้ง repository ส่วนตัวและงานไว้ที่ ~/workspace การแยก Git identity โดยอิงจาก remote URL จะแม่นยำกว่าการอิงตำแหน่งโฟลเดอร์
  • includeIf ของ Git สามารถโหลดการตั้งค่าตาม path ด้วย gitdir ได้ แต่ถ้า repository ของหลายบัญชีปะปนกันอยู่ใน working directory เดียวกัน การแยกตาม path จะชนข้อจำกัด
  • หากใช้เงื่อนไข hasconfig:remote.*.url: จะสามารถ include ไฟล์ตั้งค่าแยกตาม pattern ของ remote URL เช่น GitHub, GitLab, SourceHut หรือองค์กร GitHub เฉพาะได้
  • ต้องจัดการ SSH key แยกต่างหากใน ~/.ssh/config ด้วย Host, Hostname, User, IdentityFile และหากต้องการใช้ key แยกตามองค์กรแม้จะเป็น github.com เดียวกัน ก็จำเป็นต้องมี Host alias
  • เมื่อตั้งค่า url.<base>.insteadOf ร่วมด้วย จะยังใช้ git@github.com:orgname/project ได้ตามปกติ แต่ภายในจะถูกแทนที่เป็น gh-work:orgname เพื่อให้ไปใช้การตั้งค่า SSH ที่ถูกต้อง

แยกการตั้งค่า Git ตาม remote URL

  • ตัวอย่าง includeIf แบบเดิมจะ include ไฟล์ตั้งค่าต่างกันตาม path ของ local directory เช่น gitdir:~/code/**, gitdir:~/work/**
    • ใต้ ~/code สามารถโหลด ~/.config/git/personal และใต้ ~/work สามารถโหลด ~/.config/git/work ได้
    • ไฟล์ที่ถูก include มักมี Git identity และ signing key เช่น user.name, user.email, user.signingkey
  • หากวางโค้ดทั้งหมดไว้ใต้ ~/workspace repository ส่วนตัว, work-1, work-2 อาจปะปนกันในโครงสร้าง path เดียวกัน ทำให้ยากที่จะแยกตามต้องการด้วยเงื่อนไขแบบ path เพียงอย่างเดียว
  • เมื่อใช้ hasconfig:remote.*.url: ของ Git จะสามารถ include ไฟล์ตั้งค่าได้เฉพาะเมื่อ repository ปัจจุบันมี remote URL ที่กำหนด
    • ถ้าตรงกับ git@github.com:*/** ให้ใช้ ~/.config/git/config-gh
    • ถ้าตรงกับ git@github.com:orgname/** ให้ใช้ ~/.config/git/config-gh-org
    • ถ้าตรงกับ git@gitlab.com:*/** ให้ใช้ ~/.config/git/config-gl
    • ถ้าตรงกับ git@git.sr.ht:*/** ให้ใช้ ~/.config/git/config-srht
  • Git จะ include การตั้งค่าที่ match เป็นลำดับสุดท้าย ดังนั้น ลำดับของเงื่อนไข จึงสำคัญ
    • เงื่อนไข github.com:orgname/** ต้องอยู่ถัดลงมาจากเงื่อนไขทั่วไป github.com:*/** เพื่อไม่ให้การตั้งค่าเฉพาะองค์กรถูกการตั้งค่า GitHub ทั่วไปเขียนทับ
  • ผลลัพธ์คือ repository ที่มี remote github.com:orgname/** จะใช้ config-gh-org ส่วน repository GitHub อื่น ๆ จะใช้การตั้งค่า GitHub ทั่วไป

ปรับข้อมูลการเชื่อมต่อตามองค์กรด้วย SSH key และ insteadOf

  • นอกเหนือจาก Git identity แล้ว หากต้องการ pull·push กับ remote จำเป็นต้องมี การตั้งค่า SSH key
    • สำหรับ gitlab.com ใน ~/.ssh/config สามารถกำหนด IdentityFile เป็น ~/.ssh/gitlab.id_ed25519
    • สำหรับ github.com สามารถกำหนดเป็น ~/.ssh/github.id_ed25519 ได้เช่นกัน
  • ขึ้นอยู่กับการตั้งค่า ssh-agent อาจควรเพิ่ม IdentitiesOnly yes ใต้ IdentityFile ของแต่ละ Host
  • หากต้องการใช้ key ต่างกันตามองค์กรบน github.com ซึ่งเป็น Hostname เดียวกัน ต้องตั้งค่า Host ให้แตกต่างกัน
    • รูปแบบการตั้งค่าคือ Host gh-work, Hostname github.com, User git, IdentityFile ~/.ssh/work.id_ed25519
  • หากใช้ url "gh-work:orgname" กับ insteadOf = git@github.com:orgname ในการตั้งค่า Git จะสามารถแทนที่ Git URL ได้โดยอัตโนมัติ
    • ผู้ใช้ป้อนเหมือน git clone git@github.com:orgname/project
    • Git จะเปลี่ยนส่วน github.com:orgname เป็น gh-work:orgname แล้วใช้การตั้งค่า gh-work ใน ~/.ssh/config
  • วิธีนี้เป็นทริกที่อ้างอิงจาก SSH and multiple Git credentials และบทความที่อ้างอิงร่วมกันมีดังนี้

1 ความคิดเห็น

 
GN⁺ 2024-11-26
ความคิดเห็นจาก Hacker News
  • แทนที่จะใช้ insteadOf ให้โคลนรีโพซิทอรีเป็น gh-work:org/repo แล้วใส่ includeIf "hasconfig:remote.*.url:gh-work:**/**" ไว้ในการตั้งค่า Git
    วิธีนี้ทำให้รีโพซิทอรีที่โคลนด้วย SSH identity ที่กำหนดไว้ใต้ gh-work ดึงการตั้งค่า gh-work.inc มาใช้โดยอัตโนมัติ และในนั้นจะมี Git identity กับคีย์สำหรับเซ็นที่เหมือนกับการตั้งค่า SSH
    สุดท้ายชื่อ gh-work จะกลายเป็นเกณฑ์ที่ใช้แยก SSH identity กับ Git identity ทำให้เข้าใจง่ายขึ้น

    • วิธีแก้ในบทความดูมี อิสระในการปรับแต่ง มากเกินจำเป็นจนรู้สึกไม่ค่อยสบายใจ แต่วิธีนี้ดูเป็นแนวทางที่สง่างามในการลดพารามิเตอร์ตอนรันไทม์ให้เหลือหนึ่งตัว
    • includeIf แยกตัวพิมพ์ใหญ่-เล็ก และลำดับความสำคัญคือการตั้งค่าตัวสุดท้ายชนะ
      ถ้าต้องการตรวจสอบว่าทำงานถูกต้องหรือไม่ ให้รัน git remote get-url origin และ git config --get user.email
    • วิธีนี้อาจทำให้ สคริปต์ ที่คาดว่า URL ของรีโมตรีโพซิทอรีต้องมีรูปแบบเฉพาะพังได้
  • ผมมองว่าวิธีที่ดีกว่าคือใส่ alias แยกตาม identity ไว้ใน .gitconfig ของ HOME แล้วรัน git config-company หรือ git config-personal ทันทีหลังจาก init หรือโคลนรีโพซิทอรี
    เปิด user.useConfigOnly = true แล้วให้ alias ตั้งค่า user.email, user.name, core.sshCommand ของรีโพซิทอรีโลคัลให้ใช้คีย์ SSH ส่วนตัว/ของบริษัทตามลำดับก็พอ

    • ปัญหาคือจะโคลนครั้งแรกอย่างไรถ้ายังไม่มี การตั้งค่า SSH ที่ถูกต้องตั้งแต่ต้น
      วิธีในบทความมีข้อดีตรงที่ถ้าโคลนจากองค์กรก็ใช้งานได้เลย
  • เมื่อก่อนที่สตาร์ทอัพแห่งหนึ่ง เคยมีคนที่เปลี่ยน identity เป็นชื่อมั่ว ๆ เหมือนในนิทานทุกวัน
    คอมมิตวันจันทร์เป็น Mr. Bunnymann วันอังคารเป็น Doctor Funtime อะไรทำนองนั้น ทำให้ลำบากมากเวลาไล่ทำ นิติวิทยาศาสตร์ด้านเวอร์ชันคอนโทรล
    ถ้ามองแบบใจดี เขาอาจตั้งใจเตือนว่าทุกคนสามารถใส่อะไรก็ได้ในการตั้งค่า identity ดังนั้นไม่ควรเชื่อค่าพวกนั้นมากเกินไป

    • ถ้าเป็น วัฒนธรรมไม่กล่าวโทษ เวลาไล่ตรวจเวอร์ชันคอนโทรล สิ่งที่สำคัญกว่าคือเกิดขึ้นเมื่อไร และเกิดรอบ ๆ การเปลี่ยนแปลงอะไร มากกว่าใครเป็นคนทำ
      ถึงอย่างนั้น การรู้ว่าใครทำก็ยังมีประโยชน์เมื่ออยากถามรายละเอียด หรือคาดเดาสไตล์กับความเชี่ยวชาญ
      ถ้าบังคับให้คอมมิตต้องมี ลายเซ็น GPG และลงทะเบียน GPG identity ที่อนุญาตไว้ ก็สามารถระบุตัวผู้เขียนจริงจากลายเซ็น แทนที่จะพึ่งเมทาดาทา author/committer ได้
      แน่นอนว่า “ทำให้ง่าย” กับลายเซ็น GPG ไม่ได้เข้ากันดีเสมอไป
    • ก็ควรเชื่อถือได้เท่ากับที่เชื่อถือเอกสารหรือลายเซ็นที่พนักงานเขียน
      ถ้าไว้ใจไม่ได้ว่าพนักงานจะระบุคอมมิตของตัวเองให้ถูกต้อง ก็ควรไล่ออก
    • ถ้ามองแบบใจดี ผมสงสัยว่าเขาใช้ คีย์สำหรับเซ็น เดียวกันหรือเปล่า
    • น่าทึ่งที่ยังได้เงินจากการเล่นพิเรนทร์แบบนั้น
    • Git มีการรองรับในตัวสำหรับแยก author กับ committer และคงเป็นแค่การเปลี่ยนเฉพาะคุณสมบัติ author เท่านั้น
  • ไม่จำเป็นต้องไปแตะ ~/.ssh/config; แค่ใส่ core.sshCommand = /usr/bin/ssh -o IdentitiesOnly=yes -i ~/.ssh/IdentityFile2 -a ไว้ใน ~/.gitconfig หรือ ~/.config/git/personal ตามในบทความก็พอ
    แบบนี้ทำให้ ซับโมดูล ง่ายขึ้นแม้ไม่ใช้ insteadOf

    • แล้วถ้ามี SSH identity มากกว่าหนึ่งตัวจะทำอย่างไรต่อ
  • ผมใช้ includeIf แบบอิงไดเรกทอรีมาตั้งนานแล้ว (https://www.bobek.cz/til/git-identities/) แต่ hasconfig:remote นี่เรียบร้อยมากจริง ๆ
    ใช้ได้ตั้งแต่ตอนโคลนรีโพซิทอรีด้วย

  • includeIf ค่อนข้างดี
    ตอนนี้ผมเก็บความซับซ้อนของ SSH ไว้ที่ ~/.ssh แล้วมี include แยกหนึ่งตัวต่อหนึ่งลูกค้า/โปรเจกต์/identity
    อะไรที่ไม่มีโฮสต์เนมเฉพาะอย่าง GitHub ก็ใส่ host alias เช่น customer-github แล้วตั้งค่า HostName github.com, IdentityFile ~/.ssh/customer_rsa, User git
    จากนั้นเวลา git clone ก็ใช้ alias นั้นอย่างเดียว จบ

    • ผมเคยทำเครื่องมือสำหรับจัดการ GitHub SSH identity หลายตัวไว้เมื่อ 12 ปีก่อน และยังดูแลอยู่: https://github.com/dolmen/github-keygen
  • ผมเคยเจอปัญหาเดียวกัน และตอนนี้ก็เหมือนมีทางแก้แล้ว
    ถ้าใช้ NixOS กับ home-manager บน Linux และ Mac การตั้งค่านี้จะง่ายขึ้น
    ใส่ condition = "hasconfig:remote.*.url:git@github.com:/**" และการตั้งค่า user.email ไว้ใน programs.git.includes ก็พอ
    อ้างอิง: https://nix-community.github.io/home-manager/options.xhtml#opt-programs.git.includes

    • ดูไม่ง่ายกว่าการเขียนลง .gitconfig โดยตรงเท่าไร
      เงื่อนไขกับการตั้งค่าก็เหมือนในบทความ แต่เพิ่ม ขั้นตอน build/template และต้องเรียนภาษาโปรแกรมใหม่ที่มีไวยากรณ์แปลก ๆ เข้าไปอีก
  • ผมแยกการตั้งค่างานกับส่วนตัวด้วย includeIf: "gitdir" อยู่แล้ว แต่ hasconfig:remote นี่เป็นฟีเจอร์ที่เปลี่ยนเกมโดยสิ้นเชิง

    • ไม่น่าเชื่อว่าสมบัตินี้ซ่อนอยู่ในสถานะร่างมานาน 3 ปี
  • สำหรับคอนซัลแตนต์ ผมแนะนำอย่างหนักแน่นเสมอให้ใช้ เครื่องแยกต่างหาก สำหรับงาน หรืออย่างน้อยก็ใช้ผู้ใช้ OS แยกต่างหาก
    ถ้าใช้เครื่องส่วนตัวทำงาน มีความเสี่ยงที่จะเจอปัญหาใหญ่

    • “การใช้เครื่องส่วนตัวทำงาน” มีขอบเขตกว้างมาก
      อาจเป็นกรณีบริษัทที่ทำงานแบบรีโมตเป็นหลัก ให้เตรียมแล็ปท็อปเองและจ่ายเงินซื้อเครื่องใหม่ทุก 2–3 ปี แต่ก็ยังเป็นแล็ปท็อปส่วนตัวอยู่ หรืออาจเป็นผู้รับเหมาชั่วคราวก็ได้
      ควรอธิบายให้เจาะจงกว่านี้ว่าในสถานการณ์ไหนและเพราะอะไรจึงเป็นปัญหา
      ความเสี่ยงมีจริง แต่ถ้าแจกแจงไม่ได้ ก็ใกล้เคียงกับการปล่อย FUD มากกว่าการให้ความรู้
  • นี่คือเครื่องมือที่ผมทำไว้เพื่อเปลี่ยน Git identity ตามโปรเจกต์ได้ง่าย ๆ: https://github.com/cquintana92/git-switch-user
    หลังตั้งค่า identity แล้ว รัน $ git su Personal หรือ $ git su Work จากนั้นอีเมล ชื่อ คีย์ SSH และเลือกได้ว่าจะรวมคีย์ PGP ด้วยหรือไม่ จะถูกตั้งค่าใน .git/config ของรีโพซิทอรี
    ช่วยประหยัดเวลาไปได้มาก

    • ยังมีเครื่องมือจัดการ GitHub identity สำหรับเข้าถึง Git ผ่าน SSH ด้วย: https://github.com/dolmen/github-keygen
      เป็นเครื่องมืออายุ 12 ปีแล้ว แต่ยังดูแลอย่างต่อเนื่อง