5 คะแนน โดย GN⁺ 2024-02-14 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • แม้แต่ผู้ใช้ที่ใช้ Git มานานก็ยังอาจพลาด ความสามารถที่ไม่ค่อยเป็นที่รู้จัก หลายอย่าง ทำให้สมมติฐานที่ว่าความรู้คำสั่งขั้นสูงบนบรรทัดคำสั่งเป็นเรื่องแพร่หลายเริ่มสั่นคลอน
  • ต่างจากคนรุ่นที่ย้ายมาจาก SVN หรือ CVS นักพัฒนาที่ใช้แต่ Git มาโดยตลอดมีโอกาสน้อยที่จะได้เรียนรู้ วิธีใช้งานขั้นสูง บางอย่าง
  • Git ได้เพิ่มความสามารถเล็ก ๆ แต่มีประโยชน์อย่างต่อเนื่องตามกาลเวลา และการเปลี่ยนแปลงเหล่านี้อาจมี คุณค่าเชิงปฏิบัติ ในบางสถานการณ์
  • สำหรับผู้ใช้ระดับกลางถึงขั้นสูง ได้แบ่งหัวข้อฟีเจอร์ที่เก่าแต่มีประโยชน์ ฟีเจอร์ที่เพิ่งเพิ่มเข้ามา และหัวข้อเรื่องรีโพขนาดใหญ่·โมโนรีโพ ออกเป็น ซีรีส์สั้น 3 ตอน
  • หากกลับมาทบทวนความสามารถที่มองไม่เห็นจากพฤติกรรมการใช้ Git แบบคุ้นเคย ก็อาจช่วยให้จัดการงานประจำในรีโพได้อย่างมีประสิทธิภาพยิ่งขึ้น

เหตุผลที่ควรกลับมาดู Git อีกครั้ง

  • ระหว่างการบรรยายเกี่ยวกับ Git และ GitButler เมื่อไม่นานมานี้ ผู้เขียนพบว่านักพัฒนาจำนวนมากยังมี สิ่งที่ไม่รู้ เกี่ยวกับ Git อยู่มาก
  • เมื่อก่อนเคยบรรยายเรื่อง Git ขั้นสูง แต่ตลอดช่วงประมาณ 10 ปีที่ผ่านมา ผู้คนมักถูกมองว่ารู้ฟีเจอร์คำสั่งขั้นสูงเหล่านี้กันอยู่แล้ว
  • นักพัฒนารุ่นที่ใช้แต่ Git มาโดยตลอดไม่เคยต้องย้ายจากเครื่องมืออย่าง SVN หรือ CVS มายัง Git หรือกลับไปเรียนรู้แนวคิดเดิมอีกครั้ง
  • Git เองก็เรียนรู้ความสามารถใหม่ ๆ ไปตามกาลเวลา และแม้ส่วนใหญ่จะเป็นการเปลี่ยนแปลงเล็กน้อยหรือเฉพาะทาง แต่ก็อาจช่วยงานจริงได้
  • บล็อกซีรีส์นี้จัดทำขึ้นจากงานนำเสนอ FOSDEM 2024 little known Git stuff

ซีรีส์เคล็ดลับ Git ที่แบ่งเป็น 3 ตอน

  • กลุ่มเป้าหมายคือ ผู้ใช้ Git ระดับกลางถึงขั้นสูง และกล่าวถึงความสามารถที่อาจพลาดไปได้แม้จะใช้ Git มานานแล้วก็ตาม
  • แทนที่จะรวมทุกอย่างไว้ในบทความเดียว จึงแบ่งเป็นบทความสั้น 3 ตอนตามหัวข้อย่อยต่าง ๆ
  • หัวข้อที่รวมอยู่:
    • Oldies but Goodies: ความสามารถของ Git ที่เก่าแต่ยังมีประโยชน์
    • Some Subtle New Things: การเปลี่ยนแปลงเล็กน้อยที่เพิ่งถูกเพิ่มเข้ามาใน Git
    • Really Large Repositories and Monorepos: เนื้อหาเกี่ยวกับรีโพขนาดใหญ่มากและโมโนรีโพ
  • บทความแรกจะต่อเนื่องไปยัง Oldies but Goodies

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

 
GN⁺ 2024-02-14
ความคิดเห็นจาก Hacker News
  • ในฐานะผู้เขียน ยอมรับว่าเนื้อหาจำนวนมากในนี้เพิ่งได้เรียนรู้เมื่อไม่นานมานี้เอง ฟีเจอร์ที่เกี่ยวกับ repository ขนาดใหญ่ เป็นสิ่งที่ Microsoft และ GitHub ค่อย ๆ ใส่เข้ามาใน Git core ตลอดช่วงไม่กี่ปีที่ผ่านมา จึงมีปัญหาว่าหาเอกสารที่รวบรวมสิ่งที่พวกเขาทำไว้ในที่เดียวได้ยาก
    ได้คุยเรื่องสนุก ๆ กับคนฝั่ง Mercurial ด้วย และบอกว่าช่วงหลัง ๆ การเขียนบางส่วนภายในของ Hg ด้วย Rust ทำให้ได้ความเร็วเพิ่มขึ้นอย่างน่าทึ่ง
    กำลังคิดถึง Pro Git ฉบับพิมพ์ครั้งที่ 3 อยู่ด้วย หากมีเรื่องที่ได้เรียนรู้มาอย่างยากลำบากเกี่ยวกับ Git หรือเรื่องที่อยากรู้ ก็ขอให้บอกมา
    • คุณอาจรู้อยู่แล้ว แต่การใช้ difftastic แทน diff ของ Git ก็ดี: https://difftastic.wilfred.me.uk/
      alias ใน gitconfig ที่ใช้บ่อยคือ fza, gone, root โดย git fza จะแสดงไฟล์ที่แก้ไข/ไฟล์ใหม่ในหน้าต่าง fzf แล้วส่งไฟล์ที่เลือกต่อให้ git add: https://github.com/junegunn/fzf
      git gone จะลบ branch local ที่ไม่มีอยู่บน remote แล้ว ส่วน git root จะแสดง root ของ repository จึงเหมาะเวลาจะกลับไปยัง root จาก directory ลึก ๆ ช่วงนี้ใช้ zoxide เลยใช้น้อยลง: https://github.com/ajeetdsouza/zoxide
    • ในส่วนที่เกี่ยวกับความต่างของ whitespace น่าจะใส่ ignore-revs-file เข้าไปด้วย คือ commit ไฟล์ ignore-revs ไว้ใน repository แล้วให้คนที่ทำ reformat ครั้งใหญ่เพิ่ม SHA นั้นเข้าไป เพื่อไม่ให้ git blame พัง
      https://git-scm.com/docs/git-blame#Documentation/git-blame.txt---ignore-revltrevgt
    • สิ่งหนึ่งที่ได้เรียนรู้อย่างยากลำบากใน Git คือการทำงานอย่าง merge, cherry-pick, rebase ไม่ได้ทำงานด้วย snapshot แต่ทำงานด้วย diff และ patch หรือให้แม่นกว่านั้นคือ 3-way merge Pro Git เน้นโมเดลการจัดเก็บแบบ snapshot ของ Git ได้ดี แต่ถ้าคิดถึงแต่โมเดลนี้ อาจสับสนได้ โดยเฉพาะกับ rebase
      เช่น ระหว่าง rebase แค่ลบ commit หนึ่งออก แต่ไม่เข้าใจว่าทำไม commit หลังจากนั้นทั้งหมดถึงเปลี่ยนไป ท้ายที่สุดจึงเข้าใจว่าแม้การจัดเก็บจะอิง snapshot แต่การดำเนินงานอิง diff หลังจากนั้นถึงเข้าใจ rebase และเวลาสอน หากเน้นจุดนี้มากขึ้นก็น่าจะช่วยได้
  • ไม่ได้อยากเรียนท่าพิสดารของ Git แต่อยากใช้ให้เรียบง่ายที่สุด แค่อยาก push โค้ด จบเรื่อง Git แล้วไปทำงานต่อ
    เคารพคนที่ชอบ Git แต่มันเป็นแค่เครื่องมือที่ต้องใช้สำหรับผม
    • ความซับซ้อนบางส่วนของ Git มาจากเดิมที Git ถูกออกแบบเป็น plumbing ระดับต่ำ โดยคาดว่าจะมีพื้นผิวสำหรับผู้ใช้ที่เป็นมิตรกว่า (porcelain) วางอยู่บน data model ของ Git ดังนั้นถ้าต้องการ UI ที่เรียบง่ายและสม่ำเสมอ ทุกวันนี้แนวทางนั้นก็อาจยังดีกว่า ตัวอย่างเช่น Jujutsu และ Got (game of trees)
    • เข้าใจความรู้สึกนั้น แต่ Git ก็ไม่ได้ยากขนาดนั้น พอเลยจาก checkout/commit/push พื้นฐานไปแล้ว ถ้ารู้บางอย่าง โดยเฉพาะอย่าง การเขียนประวัติใหม่ คุณภาพของ commit history จะดีขึ้นมาก และวิศวกรคนอื่นในโปรเจกต์จะเข้าใจ flow ได้ง่ายขึ้น
      Git ดูเหมือนจะเป็นค่าคงที่ที่อยู่ในวงการไปอีกนาน และเป็นหนึ่งในเครื่องมือที่แตะบ่อยที่สุดในการพัฒนารายวัน จึงคุ้มค่าที่จะลองดูสักหน่อย
    • มีรายละเอียดบางอย่างที่เป็นธรรมชาติของปัญหาเอง และบางอย่างก็ไม่ใช่ ผมคิดว่าเรามักประเมินความยากที่มีอยู่โดยธรรมชาติต่ำเกินไป
      ดังนั้นผมคิดว่า ความซับซ้อน ของ Git ในระดับหนึ่งก็ไม่เป็นไร
    • ฟังดูคล้ายกับการบอกว่าไม่อยากเรียน programming และอยากใช้คอมพิวเตอร์ให้เรียบง่ายที่สุด แค่อยากบอกสิ่งที่ต้องทำแล้วจบ
    • อินเทอร์เฟซของ Git ให้ความรู้สึกเหมือน abstraction ที่รั่ว ไม่ได้อยากเรียนท่าพิสดารของ Git แต่สุดท้ายก็รู้มากกว่าที่อยากรู้
  • เพิ่งได้เรียนรู้เกี่ยวกับ core.fsmonitor จากมุมมองของ monorepo ขนาดใหญ่ อยากให้ git clone มีตัวเลือก resume
    ในยุค 2000 เคยเจอปัญหาเดียวกันตอนพยายาม clone kernel repository ผ่านการเชื่อมต่อ bandwidth ต่ำ และหลังจากขอความช่วยเหลือใน mailing list ก็มีคนเอา repository ทั้งหมดเป็น tar บีบอัดขึ้นไว้บนเว็บส่วนตัวให้ จึงค่อยดาวน์โหลดได้
    ทุกวันนี้ถ้า VPN บริษัทหลุดชั่วคราว ก็ยังเกิดปัญหาแบบเดียวกันเป็นครั้งคราวตอน clone repository ใหญ่ ๆ ลองนึกภาพว่าดาวน์โหลด repository ของ Windows ขนาด 300GB ไปแล้ว 95% แล้ว Wi‑Fi หลุดแวบหนึ่ง
    แปลกที่ Git กับ Docker ซึ่งเป็นสองเครื่องมือที่ใช้ bandwidth มากในสแตกการพัฒนาสมัยใหม่ กลับไม่รองรับการดาวน์โหลดแบบ resume อย่างเหมาะสม
    • สิ่งที่ต้องการดูใกล้เคียงกับ git bundle แต่มีเงื่อนไขว่าต้องมีใครสักคนสร้าง bundle ไว้ตั้งแต่แรก
      https://git-scm.com/docs/git-bundle
    • น่าจะทำได้ด้วยการทำ shallow clone แล้วค่อยขยายหลาย ๆ ครั้ง ถึงอย่างนั้น fetch/push protocol โดยพื้นฐานก็ค่อนข้างคาดหวัง repository ที่เล็กกว่า หรืออินเทอร์เน็ตกับเซิร์ฟเวอร์ที่ดีมาก
  • น่าสนใจมาก อยากเห็นว่าใครจะแก้ปัญหาที่หลายคนร่วมกัน contribute ไปยัง release, feature, hotfix ต่าง ๆ ติด tag ให้ release และย้อนเวลากลับไปหา bug ด้วย อินเทอร์เฟซที่ง่ายกว่า ได้
    คล้ายกับการบอกว่าอยากได้ภาษา low-level ที่ซ่อนความซับซ้อนของระบบ ซึ่งจริง ๆ แล้วสองอย่างนี้แทบจะขัดกันเอง Git น่าพอใจและไม่ได้เรียนยากขนาดนั้น ดังนั้นบางส่วนก็ควรแค่เรียน Git
    • เพราะแบบนี้จึงแนะนำ GitKraken อย่างแรง แม้จะระวังเพราะเป็นผลิตภัณฑ์เสียเงิน แต่ลองมาหลายเครื่องมือแล้ว ไม่มีอะไรปลดล็อกพลังได้เท่า GitKraken
      มันเปิดกล่องดำที่นักพัฒนาหลายคนรู้สึกเวลาใช้ terminal ออกไป วางกราฟไว้ด้านหน้า และแสดงการทำ rebase ให้เห็นเป็นภาพอย่างเป็นธรรมชาติ ทำให้ Git สนุกขึ้น
      ความชำนาญ CLI ยังมีคุณค่าอยู่ แต่พอเห็นนักพัฒนาประสบการณ์ 10 ปีติดขัดกับปัญหาพื้นฐาน หรือทำ history ของโปรเจกต์พังเพราะบรรยากาศแบบ “ถ้าเป็นวิศวกรตัวจริงต้องใช้ Git CLI เท่านั้น” ก็รู้สึกหงุดหงิด
      ทุกวันนี้ถึงจะใช้ CLI ก็ยังบอกให้เปิดกราฟดูในหน้าต่างอื่นทั้งวัน ซึ่งทำได้ฟรีใน VS Code, JetBrains และแม้แต่ใน CLI

เพราะเมื่อเพื่อนร่วมทีม merge PR ผมก็จะเห็นทันทีแล้ว rebase branch ของตัวเอง ทำให้ branch อัปเดตอยู่บนฐาน main เสมอ จึงไม่ต้องเจอนรกของการ merge หรือทิ้ง commit “fix conflicts” แย่ ๆ ไว้

  • ระหว่างหาว่าไฟล์ 10 อันดับแรกที่ถูกแก้ไขมากที่สุดหลังจากสร้างเมื่อวานคือไฟล์ไหน ก็เจอ https://github.com/tj/git-extras/blob/main/Commands.md
    มี คำสั่งเสริมของ Git ที่น่าใช้หลายอย่าง

  • ไม่ค่อยเข้าใจว่าทำไมนักพัฒนาส่วนใหญ่ถึงยืนกรานจะใช้ Git CLI ทั้งที่ client แบบ UI สมัยใหม่อย่าง GitKraken ก็ใช้งานได้ดีและช่วยได้มากพอ: https://www.gitkraken.com/

    • ความรู้ CLI นำไปสู่การเขียนสคริปต์ และความรู้ Git ที่ได้จากสคริปต์ก็ย้อนกลับมาช่วยการใช้งานประจำวันอีกที ผมไม่อยากรู้สึกไร้พลังเพียงเพราะต้องใช้ CLI ตอน SSH เข้า Raspberry Pi ที่ใช้เป็นเซิร์ฟเวอร์
      ไม่ได้ต่อต้าน GUI แบบสิ้นเชิง แต่ตอนนี้ CLI มีประสิทธิภาพกว่า และไม่อยากเสียเวลาไปหา GUI ที่ตรงเงื่อนไขต่อไปนี้
      ต้องดูดี เป็นแอป native ที่ไม่ใช่แค่ยัดเว็บเบราว์เซอร์เก่า ๆ เข้ามา ไม่มี telemetry หรือปิดเป็นค่าเริ่มต้น เป็นโอเพนซอร์สเต็มรูปแบบ และคาดหวังได้ว่าจะไม่หายไปในอีก 5 ปี
      อีกทั้งต้องไม่ทำให้สับสนกว่าเดิม ที่บริษัทเก่าเคยต้องใช้ Visual Studio แล้วมีปุ่มหนึ่งที่จริง ๆ หมายถึง “ทำเครื่องหมายว่าแก้ conflict แล้ว” แต่กลับเขียนชวนหวาด ๆ ว่า “Accept merge”
      ไม่ควรทำให้คนที่คาดหวังว่าคำบางคำมีความหมายเฉพาะต้องสับสน และพฤติกรรมอย่างปุ่ม “Commit changes” ที่ทำตัวเหมือนจะช่วย แต่ดัน push ไป remote ด้วย ก็ไว้ใจได้ยาก
    • CLI ก็ใช้งานได้ดีพออยู่แล้ว ผมใช้ปลั๊กอินใน editor ด้วย แต่ถ้าอยู่ใน command line อยู่แล้วก็จัดการตรงนั้น
      ถ้าต้องสลับไปโปรแกรมอื่นเพื่อทำ commit เดียว แรงจูงใจที่จะ commit บ่อย ๆ ก็ลดลง
    • ถ้าไม่มีปัญหาที่เฉพาะเจาะจงมาก ๆ ผมจะลดงานที่ทำกับ Git ให้น้อยที่สุด สำหรับผมจริง ๆ ก็ประมาณ push, pull, checkout เลยรู้สึกว่าการใช้ GUI มันเกินจำเป็น
    • ดูเรียบร้อยดี แต่ graphical interface ทำให้เสียสมาธิได้ง่ายเกินไป สุดท้ายดูเหมือนเป็นเรื่องรสนิยมส่วนตัว และ CLI นั้นเร็ว แต่ learning curve สูง
      เวลาผมใช้ Git บน CLI ส่วนใหญ่ก็ไม่ได้มีอะไรพิเศษ แค่ไม่กี่คำสั่ง ส่วน tip หรือ trick ที่ไม่ค่อยได้ใช้ก็จดไว้ในไฟล์ข้อความ
  • รู้จัก -committerdate อยู่แล้ว แต่ไม่รู้ว่าตั้งเป็นการเรียงลำดับค่าเริ่มต้นได้ และมีประโยชน์มาก มีบันทึกอยู่สองสามอย่าง
    git columns ถ้ามันไม่พอดีกับหน้าจอจนต้องเลื่อนดูจะค่อนข้างชวนสับสน ถ้ามีตัวเลขด้วยก็คงดี
    git maintenance ดูดี แต่กังวลเพราะ rebase บ่อย อยากรู้ว่าจะเสีย loose object เร็วกว่า gc หรือเปล่า เห็นว่า gc ถูกปิดอยู่ แต่ยังไม่ชัดเจน
    เกี่ยวกับ git blame มีสคริปต์ที่มีประโยชน์แต่ไม่ค่อยเป็นที่รู้จักคือ https://github.com/gnddev/git-blameall มันไม่ค่อยมีคนรู้จักจนผมต้อง port ไปเป็น Python 3 เอง และผมก็ไม่ใช่นักพัฒนา Python ด้วย

    • ใน scheduled maintenance จะปิด gc ไว้ เมื่อรัน maintenance run แบบระบุเอง จึงจะเปิดเป็น task
      มันไม่ได้เก็บ loose object เร็วกว่า gc สุดท้ายก็แค่ รัน gc นั่นเอง
    • สงสัยว่าจัดเรียงย้อนกลับได้ไหม วิธีแก้แบบง่าย ๆ สำหรับปัญหาที่ branch ถูกดันออกนอกหน้าจอดูเหมือนคือให้ branch ใหม่สุดอยู่ท้ายสุด ผมทำแบบนั้นด้วยสคริปต์ของผู้ใช้เอง
    • ไม่ได้หายเร็วกว่าเดิม แค่ดึงข้อมูลจาก remote บ่อยขึ้นและ repack ข้อมูลเท่านั้น ถ้า ปิด GC อยู่ ข้อมูลจะไม่ถูกลบ
      git-blameall ดูใช้ได้ น่าจะลองใช้ดู
  • ทำให้ flow การใช้ Git ง่ายขึ้นมากด้วย alias ไม่กี่ตัวที่ทำงานได้หลาย environment
    git synced จะซิงก์ branch ปัจจุบันด้วย rebase ให้ตรงกับ upstream ถ้ามี หรือกับ origin ถ้าไม่มี ใช้ master หรือ main โดยให้ความสำคัญกับ main ก่อน
    git pub จะเผยแพร่การเปลี่ยนแปลงไปยัง remote origin และใช้ force push แบบมี lease
    git pr จะเปิด URL ของ PR ที่เหมาะสมบน GitHub โดยไม่ต้องใช้ GH client ถ้ากำหนด upstream ไว้ ก็จะส่ง PR ไปทางนั้น
    git hub จะเปิดหน้า GitHub ของ repository
    https://softwaredoug.com/blog/2022/11/09/idiot-proof-git-aliases.html

    • สงสัยว่าทำไมถึงเลือกใช้ลูกศรประหลาดมีขน ๆ นั่นเป็นตัวคั่น
  • เลิกแกล้งทำเป็นรู้ว่ากำลังทำอะไร แล้วใช้ เครื่องมือ Git แบบภาพ แทน เช่น SmartGit หรือเครื่องมือที่อยู่ใน IntelliJ ผมมองว่า Git “ฮีโร่สาย command line” ออกแนวโชว์มากกว่า
    ชั้นคำสั่งสำหรับผู้ใช้อาจสับสนจนน่าหงุดหงิดได้ เช่น Yours กับ Theirs อาจมีความหมายตรงข้ามกันโดยสิ้นเชิงตามบริบท
    อินเทอร์เฟซผู้ใช้ทั้งหมดไม่มีสไตล์หรือธีมร่วมกัน จึงต้องมีชั้นภาพใหม่เพื่อไม่ให้คนใช้แทบบ้า

    • ผมก็เหมือนกัน ชอบที่เห็น diff ได้ตลอด และดูด้วยภาพได้ทันทีว่าจะเกิดอะไรขึ้น ไม่ต้องรันคำสั่งเพิ่มหลายคำสั่ง
      ผมรู้จักแอปและ Git โดยรวมแค่เท่าที่จำเป็นกับงาน และถ้านาน ๆ ครั้งต้องการมากกว่านั้นก็ค่อยค้นหา ใช้มาหลายปีมีกรณีแบบนั้นแค่ครั้งสองครั้ง
    • งานประจำวันผมใช้เครื่องมือ Git แบบภาพเสมอ โดยเฉพาะ Tortoise Git
      แม้แต่งานซับซ้อนที่ต้องแก้ความผิดพลาดของคนอื่นหรือของตัวเอง ก็จะดู history, commit, reflog และ diff ด้วยเครื่องมือภาพก่อน เพื่อเข้าใจว่าอะไรพังและมีอะไรที่กู้ได้บ้าง
      ถ้ามี commit เดียวที่ต้องกลับไป ก็ใช้ reset --hard; ถ้าต้องรวมอะไรบางอย่างจากหลาย commit ปกติจะใช้ command line
  • ทั้งสองอย่างไม่ได้ขัดแย้งกันโดยสิ้นเชิง เรื่องอย่าง diff หรือ conflict ผมใช้แค่เครื่องมือแบบภาพ แต่ก็ได้เรียนรู้อะไรมากมายจากการทำความเข้าใจ commit object, reflog, สิ่งที่ rebase ทำอยู่เบื้องหลัง, interactive rebase, hard/soft reset ฯลฯ