Git Notes: ฟีเจอร์ที่เจ๋งที่สุดและถูกมองข้ามที่สุดของ Git (2022)
(tylercipriani.com)- Git notes เป็นฟีเจอร์สำหรับแนบเมตาดาต้าไว้กับอ็อบเจ็กต์ของ Git ในเนมสเปซแยก โดยไม่เปลี่ยนแปลงตัวอ็อบเจ็กต์เอง แต่ไม่ได้ถูกใช้อย่างแพร่หลายเพราะใช้งานไม่สะดวกและมีการนำไปใช้ค่อนข้างจำกัด
- สามารถเพิ่มข้อมูลใหม่ให้คอมมิตเก่าได้โดยไม่ต้องแก้ commit message เดิม จึงเหมาะกับบันทึกที่ระบบอัตโนมัติทิ้งไว้ เช่น ข้อมูลรีวิว·บิลด์·ตั๋วงาน
- โปรเจ็กต์ Git และ Gerrit ใช้ notes จริง ทำให้ดูการสนทนาใน mailing list, ผลการทดสอบ, และข้อมูลผู้รีวิวของแต่ละคอมมิตได้จาก
git log - git-appraise ของ Google สร้างระบบรีวิวโค้ดแบบกระจายศูนย์บน git notes ทำให้สามารถขอรีวิว, ใส่คอมเมนต์, รีวิว, และรวมโค้ดได้จากเครื่องโลคัล
- GitHub หยุดแสดง commit notes ในปี 2014 และ notes สำหรับ blob·tree ก็ใช้งานยากเพราะต้องคุ้นกับคำสั่งภายในของ Git แม้จะมีศักยภาพในการกระจายประวัติโปรเจ็กต์ก็ตาม
เมตาดาต้าที่ไม่แก้ไขอ็อบเจ็กต์ของ Git
- Git notes คือฟีเจอร์สำหรับเก็บเมตาดาต้าแยกต่างหากไว้กับอ็อบเจ็กต์ที่ Git ติดตาม
- เป้าหมายไม่ได้มีแค่คอมมิต แต่รวมถึง blob และ tree ด้วย
- แนบข้อมูลไว้ในเนมสเปซแยก โดยไม่แก้ไขตัวอ็อบเจ็กต์เอง
- โดยทั่วไป commit message ของคอมมิตที่เข้าไปอยู่ในประวัติแล้วจะแก้อย่างปลอดภัยได้ยาก แต่ถ้าใช้ notes ก็สามารถเพิ่มข้อมูลใหม่ให้คอมมิตเก่าได้
- สามารถแนบบันทึกได้ด้วย
git notes add -mแบบนี้git notes add -m 'Acked-by: <tyler@tylercipriani.com>' - หลังจากนั้นจะถูกแสดงเป็นบล็อก
Notes:ใต้คอมมิตนั้นในgit log
- สามารถแนบบันทึกได้ด้วย
- Scott Chacon เขียนไว้ใน GitHub.blog ปี 2010 ว่า notes เหมาะกับการแนบบันทึกจากระบบอัตโนมัติอย่าง ระบบตั๋วงาน·ระบบบิลด์ มากกว่าจะใช้เป็นบทสนทนาระหว่างนักพัฒนา
การใช้งานจริงและจุดที่ติดขัด
- โปรเจ็กต์ Git ใช้ notes เพื่อเชื่อมแต่ละคอมมิตเข้ากับการสนทนาใน mailing list
- ในคอมมิตตัวอย่าง
Notes (amlog)จะมีMessage-Idอยู่ และค่านี้ลิงก์ไปยังเธรดสนทนาแพตช์
- ในคอมมิตตัวอย่าง
- notes ยังใช้ได้กับการติดตามเวลาทำงานแยกตามคอมมิตหรือบรันช์, การเพิ่มข้อมูลรีวิว·ทดสอบใน
git log, และการทำ code review แบบกระจายศูนย์เต็มรูปแบบ - ปลั๊กอิน reviewnotes ของ Gerrit ทำให้ดูเมตาดาต้าการรีวิวโค้ดแบบออฟไลน์จากภายใน Git ได้
- คำสั่งสำหรับดึงและแสดง notes มีดังนี้
git fetch origin refs/notes/review:refs/notes/review git log --show-notes=review - ข้อมูลที่แสดงมี
Verified+1,Verified+2,Code-Review+2,Submitted-by,Submitted-at,Reviewed-on,Project,Branchเป็นต้น
- คำสั่งสำหรับดึงและแสดง notes มีดังนี้
- git-appraise ของ Google คือระบบ “fully distributed code review” ที่สร้างบน git notes
- ทำงานได้อย่างอิสระจาก code forge อย่าง GitHub หรือ GitLab
- สามารถขอรีวิวการเปลี่ยนแปลง, ใส่คอมเมนต์ต่อการเปลี่ยนแปลง, รีวิว และรวมโค้ดได้จากคอมพิวเตอร์โลคัล
- มีเว็บอินเทอร์เฟซรวมมาด้วย
- จุดอ่อนที่สุดคือ การใช้งาน
- GitHub หยุดแสดง commit notes ในปี 2014
- สำหรับ commit notes สามารถทำให้การ fetch อัตโนมัติและการแสดงใน
git logง่ายขึ้นได้ระดับหนึ่งด้วยการตั้งค่าgitconfiggit config --add \ remote.origin.fetch \ '+refs/notes/*:refs/notes/*' git config \ notes.displayRef \ 'refs/notes/*' - หากต้องการเก็บ notes ไว้กับ blob หรือ tree จะต้องคุ้นกับ plumbing ของ Git
- Git ทำให้ประวัติโค้ดกระจายศูนย์ได้ แต่คุณค่าจำนวนมากของรีโพซิทอรี Git กลับถูกล็อกไว้ใน forge อย่าง GitHub
- git notes อาจเป็นเส้นทางสู่การกระจายศูนย์ไม่ใช่แค่โค้ด แต่รวมถึงประวัติทั้งหมดของโปรเจ็กต์ด้วย
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ยังมีอีกฟีเจอร์หนึ่งที่ไม่ค่อยเป็นที่รู้จักคือ git trailers: https://alchemists.io/articles/git_trailers
เป็นข้อมูลเชิงโครงสร้างแบบคีย์-ค่าที่สามารถใส่ไว้ตอนสร้างคอมมิตได้ และบางระบบใช้เพื่อแนบ metadata เช่น Gerrit ใช้ฟีเจอร์นี้ในการใส่ Change-Id
ทำให้สามารถแนบข้อความกับอ็อบเจกต์ฐานข้อมูลหลายประเภทของ PostgreSQL ได้ ถ้า PostgreSQL มีฟีเจอร์ metadata ของอ็อบเจกต์ฐานข้อมูลแบบคีย์-ค่าที่มีโครงสร้างและแก้ไขได้ก็คงดี
[skip ci]และน่าจะเพื่อให้ subsystem ที่บริโภคข้อความคอมมิตลบออกได้ง่ายขึ้น: https://docs.github.com/en/actions/managing-workflow-runs-an...ไม่รู้ว่าทำไมถึงบังคับว่าต้องเป็น trailer ตัวสุดท้าย อาจเป็นเพราะ regex ก็ได้
มีประโยชน์ตอนทำงานกับ upstream โอเพนซอร์สและอยากขัดเกลา branch ให้สมบูรณ์ด้วย
git rebase -iตอนนี้ข้อมูลนั้นดูเหมือนควรใส่ไว้ใน git trailers มากกว่า ส่วนเรื่อง Change-Id ถ้า Git เองมีตัวระบุแบบนี้ เครื่องมือต่าง ๆ ก็น่าจะเข้าใจได้ ซึ่งคงดี การระบุคอมมิตด้วยข้อความคอมมิตนั้นเปราะบาง โดยเฉพาะใน MR ที่อาจแก้ข้อความได้ commit ID ระบุคอมมิตได้แบบไม่ซ้ำก็จริง แต่เมื่อสามารถย้ายการเปลี่ยนแปลงเดียวกันไปวางบนคอมมิตอื่นได้ มันก็ไม่ใช่ตัวระบุที่มีประโยชน์นัก อย่างไรก็ตาม trailers เป็นส่วนหนึ่งของคอมมิตจริง ๆ ส่วน notes ไม่ใช่ ดังนั้นสำหรับกรณีใช้งานเดิมของผม มันคงไม่ใช่ตัวแทนที่ดีสงสัยว่าการใส่เองในข้อความคอมมิตกับการใช้แฟล็ก
--trailerนั้นเหมือนกันในเชิงฟังก์ชันหรือไม่ผมเคยพยายามรัน instance ในเครื่องแล้วผสานกับ repository ที่โฮสต์บน GitHub แต่ลงเอยด้วยความหงุดหงิด อยากรู้ว่ามีทางเลือกอื่นไหมที่จัดการการติดตามการเปลี่ยนแปลงข้ามคอมมิต ฯลฯ ได้ดีกว่า GitHub และยังพัฒนาอย่างคึกคักกว่า พร้อมผสานกับ GitHub ได้เป็นมิตรกว่า เครื่องมือ code review ของ GitHub นี่ผมไม่ชอบจริง ๆ
Forgejo ก็รองรับตั้งแต่เวอร์ชัน 10 ที่ออกเมื่อเดือนมกราคมปีนี้: https://forgejo.org/2025-01-release-v10-0/#new-features
https://codeberg.org/forgejo/forgejo/pulls/4753
ดูเจ๋งมาก แต่สงสัยว่า notes ทำงานร่วมกับฟีเจอร์ เขียนประวัติใหม่ อย่าง amend หรือ rebase ที่โดยผลลัพธ์แล้วแทนที่คอมมิตด้วยสำเนาที่แก้ไขแล้วอย่างไร
ฟังดูเหมือน notes ผูกอยู่กับ commit, tree, blob ID เฉพาะตัว สงสัยว่า
git rebaseและคำสั่งทำนองนี้ฉลาดพอที่จะคัดลอก notes ไปยังคอมมิตใหม่หรือไม่ หรือมันหายไปเฉย ๆ และก็สงสัยด้วยว่าถ้า squash หลายคอมมิตเป็นหนึ่งเดียวใน interactive rebase จะเป็นอย่างไร การใส่ notes ให้ blob กับ tree ก็ดูมีปัญหาเดียวกัน เหมือนเป็นการติด metadata ให้ไฟล์หรือไดเรกทอรีใน repository แต่จริง ๆ คือผูกกับเนื้อหาเฉพาะ เช่น ถ้าใส่ note ให้ blob ที่มีสตริง"Hello world!"Git จะเชื่อม note นั้นกับทุกไฟล์ที่มีเนื้อหานั้นหรือไม่? แล้วถ้าเปลี่ยนไฟล์หนึ่งเป็น"Hello, world!"จะเสีย notes ไปหรือเปล่า?notes.rewriteได้ในgit-config(1)ใช้ Git มาน่าจะราว 10 ปี แต่ไม่เคยรู้ว่ามี git notes ด้วย เจ๋งดี
คำขอที่ว่า “ขอให้ forge ทุกเจ้าทำให้ metadata ของ code review ใช้งานแบบออฟไลน์ภายใน Git ได้” น่าจะไม่ค่อยเวิร์กกับ forge เชิงพาณิชย์อย่าง GitHub เท่าไร อย่างที่คุณเองก็บอก มูลค่าจำนวนมากของ repository Git ถูกล็อกไว้ใน forge อย่าง GitHub บริษัทแสวงกำไรโดยปกติไม่ค่อยกระตือรือร้นที่จะทำให้มูลค่าเพิ่มของตัวเองกลายเป็นของทั่วไป ไม่ได้จะตำหนิ GitHub นะ ผมคิดว่าพวกเขาทำได้ดี ทั้งให้บริการที่ยอดเยี่ยมและมี free tier ที่ใจกว้างมาก แถมถ้าอยากย้ายออก ก็ให้ดึงข้อมูลทั้งหมดผ่าน API ได้ด้วย นี่เป็นเพียงธรรมชาติของการดำเนินงานเชิงพาณิชย์เท่านั้น
Git notes จะเจ๋งก็ต่อเมื่อคุณต้องเพิ่มข้อความบ่อย ๆ หลังจากคอมมิตถูกสร้างและคนอื่นเห็นไปแล้วเท่านั้น
ตัวอย่าง Acked-By กับลิงก์การอภิปรายในเมลลิงลิสต์ดูไม่ค่อยใช่ตัวอย่างที่ดี ทั้งสองอย่างน่าจะรู้อยู่แล้วตอนสร้างคอมมิต ข้อความคอมมิตของ Git แทบไม่มีข้อจำกัดความยาวในทางปฏิบัติ ดังนั้นจะคัดลอกการอภิปรายเกี่ยวกับคอมมิตที่เกิดขึ้นบน forge ไปไว้ในข้อความคอมมิตเองก็ได้ ตัวอย่างที่ดีกว่าน่าจะเป็นกรณีเพิ่ม git note ให้กับคอมมิตที่ถูก revert ในภายหลัง
อาจเป็นผมที่แปลกก็ได้ แต่ผมเห็นเพื่อนร่วมงานจำนวนมากไม่ค่อยดูคอมเมนต์หรือ annotate อย่างจริงจังเพื่อรำลึกว่าโค้ดถูกเขียนขึ้นมาตั้งแต่แรกทำไม แค่เปลี่ยนไปดื้อ ๆ แล้วหวังว่าปัญหาจะไม่โยงกลับมาหาตัวเอง แต่ถ้าคุณเคยรับมือลูกค้าที่โกรธและรอแค่การแก้บั๊ก แล้วไม่นานก็เจอบั๊กนั้นกลับมาอีก คุณอาจระวังเรื่องการแก้บั๊กมากขึ้น การแก้บั๊กหลายตัวพร้อมกันมักต้องรีแฟกเตอร์ และการรีแฟกเตอร์ก็อาจเปิดโอกาสให้มีฟีเจอร์ใหม่หรือปรับปรุงประสิทธิภาพได้
ถ้าใช้เพื่อทิ้งเครื่องหมายไว้กับคอมมิตที่ถูก revert ในภายหลัง ข้อความคอมมิตจะดีกว่า เมื่อทำ blame กับไฟล์ คุณจะเห็นการเปลี่ยนแปลงล่าสุดของไฟล์นั้น และถ้าคอมมิตหนึ่งย้อนการเปลี่ยนแปลงของอีกคอมมิต คอมมิต revert ที่ใหม่กว่าก็จะปรากฏใน blame
นี่ไม่ใช่ปัญหาขาดความรู้ แต่เป็น ปัญหา UI ถ้า UI ของ GitHub แสดง notes การใช้งานจะเพิ่มขึ้นมากทันที
“ฟีเจอร์ที่เจ๋งที่สุดแต่ไม่ได้รับความรักของ Git” มีอยู่หลายอย่าง เช่น bisect, pickaxe, reflog, range-diff, archive, annotated tags ฯลฯ
น่าเสียดายที่หลายคนคิดว่า Git เป็นแค่ Google Drive แบบหรู ๆ ทำให้ฟีเจอร์เหล่านี้มักถูกลืม
แต่ผมก็คิดว่าไม่เป็นไร ปรัชญา Unix คือโฟกัสที่สิ่งเดียวและทำสิ่งนั้นให้ดี
โปรเจกต์ LibreOffice เคยใช้ Git notes เพื่อติดตามแต่ละคอมมิตของ repository Apache OpenOffice
โดย mirror repository นั้นเป็น branch ใน Git repository ของ LibreOffice แล้วบันทึกว่าแต่ละคอมมิตเป็นการเปลี่ยนแปลงที่ไม่เกี่ยวข้องหรือไม่ เช่น เป็นการเปลี่ยนแปลงระบบ build ที่ LibreOffice เปลี่ยนไปใช้สิ่งที่ดีกว่ามานานแล้ว เป็นการเปลี่ยนแปลงที่ซ้ำกับสิ่งที่มีอยู่แล้วใน LibreOffice หรือในกรณีที่พบไม่บ่อยนัก คือถูกนำเข้า LibreOffice หรือไม่ และถูก cherry-pick มาเป็นคอมมิตใด ยังดูได้โดยตรงที่ https://cgit.freedesktop.org/libreoffice/core/log/?h=aoo/tru... และ Git frontend นี้ก็ยังแสดง notes อยู่ ตั้งแต่ไม่กี่ปีก่อนพวกเขาหยุดติดตามการเปลี่ยนแปลงแบบนี้แล้ว อาจเป็นเพราะความเร็วการเปลี่ยนแปลงของ Apache OpenOffice ช้าลงมาก จนประโยชน์จากการ cherry-pick การเปลี่ยนแปลงไม่กี่อย่างเหล่านั้นแทบไม่มีแล้ว
มันไม่ใช่ฟีเจอร์ที่เจ๋งที่สุดแต่ไม่ได้รับความรัก แต่ใกล้เคียงกับ ฟีเจอร์กิมมิก ที่อาจเจ๋งได้ในกรณีเฉพาะมาก ๆ เช่นทีมที่ทั้งบริษัทมีแต่นักพัฒนา
สิ่งที่จำเป็นก็อยู่ในข้อความคอมมิตอยู่แล้ว และการอ้างถึง ticket ในระบบแยกต่างหากไม่ใช่บั๊ก แต่เป็นฟีเจอร์ เพราะ JIRA หรือระบบอื่น ๆ ใช้สื่อสารกับคนที่ไม่ใช่นักพัฒนา เช่น business analyst ไม่มีสิทธิ์เข้าถึงโค้ดหรือ repository เลย และฝ่าย support ก็เข้าถึง repository กับโค้ดไม่ได้ จะทำ frontend ให้คนที่ไม่ใช่นักพัฒนาดูและแก้ notes ได้ก็ได้ แต่ก็ยังไม่ได้มีความหมายมากนัก BA หรือทีม support ไม่ได้สนใจคอมมิตเฉพาะเจาะจง ฟีเจอร์หนึ่งอาจพอดีกับคอมมิตเดียวเป๊ะ ๆ ได้ แต่โดยปกติไม่ใช่แบบนั้น เมื่อใช้หลาย repository และฟีเจอร์หนึ่งครอบคลุมหลาย service git notes ก็แทบไร้ประโยชน์ และสุดท้ายก็ต้องมีการอ้างอิงไปยังระบบภายนอกอยู่ดี
แต่สิ่งนั้นกลับเป็นกระแสหลัก บางครั้งนักวิเคราะห์จากทีมอื่นที่ใช้ monorepo เดียวกันถามคำถามกับผม ทั้งที่ตอบได้ทันทีด้วยโค้ดบรรทัดเดียว นักวิเคราะห์คนนั้นค่อนข้างเชิงเทคนิคและรู้ SQL ด้วย และโค้ดของเราก็เขียนแบบ idiomatic และระดับสูงมาก ถึงอย่างนั้น วัฒนธรรมก็ไม่อาจเปลี่ยนตัวเองได้จนกว่าจะตายเพราะความไร้ประสิทธิภาพที่ฝังอยู่ภายใน
[^1] https://news.ycombinator.com/item?id=44348438
feature request อายุ 9 ปี ที่ขอให้ GitLab รองรับ notes เพิ่งถูกปิดเมื่อไม่นานมานี้: https://gitlab.com/gitlab-org/gitlab/-/issues/15029
น่าเสียดายที่ต้องล็อกอินถึงจะอ่านได้ แต่บัญชี gitlab.com อะไรก็น่าจะใช้ได้