คอมมิต Git ที่ฉันชอบที่สุด (2019)
(dhwthompson.com)- คอมมิต “Convert template to US-ASCII to fix error” ของ Dan Carley ที่เกิดขึ้นระหว่างทำงานกับ GOV.UK แสดงให้เห็นว่าการเปลี่ยนแปลงโค้ดเล็ก ๆ ก็สามารถกลายเป็นเอกสารระยะยาวของ codebase ได้ผ่าน ข้อความคอมมิตที่ละเอียด
- ข้อความที่ดีจะทิ้งไว้ว่าเหตุใดจึงเปลี่ยน มากกว่าว่าเปลี่ยนอะไร โดยกรณีนี้บันทึกข้อผิดพลาด
invalid byte sequence in US-ASCIIที่เกิดขึ้นเมื่อรันbundle exec rakeและเงื่อนไขการทำซ้ำอย่างเป็นรูปธรรม - มีทั้งสตริงข้อผิดพลาดและกระบวนการสืบค้นบันทึกไว้ด้วย ทำให้คนที่เจอปัญหาเดียวกันในภายหลังสามารถค้นหา บันทึกการแก้ไขก่อนหน้า ได้ด้วย
git log --grepหรือการค้นหาคอมมิตบน GitHub - ข้อความยังรวมขั้นตอนการใช้เครื่องมือ Unix เช่น
find -exec,file --mime,iconvทำให้ผู้รีวิวและผู้อ่านภายหลังตามลำดับการแก้ปัญหาได้ - ไม่ใช่ทุกคอมมิตจำเป็นต้องยาวขนาดนี้ แต่ข้อความที่ทิ้งบริบท กระบวนการสืบค้น และแม้แต่อารมณ์ไว้ จะช่วยสร้าง ความเข้าใจร่วมกันต่อ codebase และความไว้วางใจในทีม
คอมมิตที่ทำให้การเปลี่ยนแปลงเล็ก ๆ กลายเป็นเอกสารระยะยาว
- หากเขียนให้ดี ข้อความคอมมิต Git สามารถเป็น เครื่องมือทำเอกสารที่ทรงพลัง ซึ่งคงอยู่ตลอดอายุของ codebase ได้
- คอมมิตที่ยกเป็นตัวอย่างเป็นการเปลี่ยนแปลงในช่วงที่ Government Digital Service ทำงานกับ GOV.UK
- ผู้เขียนคือ Dan Carley และหัวข้อคือ “Convert template to US-ASCII to fix error”
- ด้วยวิธีการพัฒนาแบบเปิดเผยของ GDS แม้แต่กรณีภายในองค์กรเช่นนี้ก็สามารถแชร์ออกสู่ภายนอกได้
บริบทสำคัญกว่าความยาว
- คอมมิตนี้มีข้อความยาวเมื่อเทียบกับปริมาณการเปลี่ยนแปลงโค้ด แต่คุณค่าหลักไม่ได้อยู่ที่ความยาวเอง แต่อยู่ที่ บริบทที่เป็นประโยชน์
- การเปลี่ยนแปลงแบบเดียวกันในที่อื่นอาจถูกทิ้งไว้สั้น ๆ ว่า
change whitespace,fix bug - Dan ทิ้งบันทึกอย่างละเอียดเพื่อให้เพื่อนร่วมงานรอบตัวและผู้อ่านในภายหลังเข้าใจสาเหตุของปัญหาและกระบวนการแก้ไข
ไม่ใช่แค่ว่าเปลี่ยนอะไร แต่ทำไมจึงเปลี่ยน
- ข้อความคอมมิตที่ดีอธิบายไม่เพียงสิ่งที่เปลี่ยน แต่ยังอธิบาย เหตุผลที่เปลี่ยน ด้วย
- คอมมิตนี้บันทึกว่า หลังจากเพิ่มเทสต์ใน feature branch เพื่อให้ตรงกับเนื้อหาของ
/etc/nginx/router_routes.confผลลัพธ์ต่างกันขึ้นอยู่กับวิธีรัน- หากรันด้วย
bundle exec rake specหรือbundle exec rspec modules/router/specจะทำงานปกติ - หากรันด้วย
bundle exec rakeแต่ละบล็อกshouldจะล้มเหลว - ข้อผิดพลาดคือ
ArgumentError: invalid byte sequence in US-ASCII
- หากรันด้วย
- หากไม่มีคำอธิบายเช่นนี้ ก็มีความเป็นไปได้สูงว่าจะต้องเดาเองว่าเกิดข้อผิดพลาดการ parse ในเครื่องมือใด
- บริบทของงานดั้งเดิมอาจเลือนหายได้ง่ายเมื่อคนลืม ย้ายทีม หรือออกจากองค์กร
บันทึกข้อผิดพลาดที่ค้นหาได้
- ตอนต้นของข้อความคอมมิตมี ข้อความข้อผิดพลาด ที่เป็นต้นเหตุของการเปลี่ยนแปลงอยู่แบบตรงตัว
- คนที่เจอข้อผิดพลาดเดียวกันสามารถค้นหาบันทึกก่อนหน้าใน codebase ได้ด้วยวิธีต่อไปนี้
git log --grep "invalid byte sequence"- GitHub commit search
- จากผลการค้นหา เห็นได้ว่ามีหลายคนค้นหาข้อผิดพลาดนี้ และยังตรวจสอบได้ว่าใครเจอปัญหาก่อน รวมถึงดำเนินการอย่างไร
ทิ้งกระบวนการแก้ปัญหาไว้เป็นเรื่องเล่า
- ข้อความถูกจัดโครงสร้างให้ติดตามได้ว่าปัญหาดูเป็นอย่างไร ตรวจสอบตามลำดับใด และสุดท้ายแก้อย่างไร
- ตัวอย่างเช่น มีเนื้อหาระบุว่าเมื่อลบ matcher
.with_content(//)ข้อผิดพลาดก็หายไป, ในไฟล์ spec ไม่มีอักขระแปลก ๆ และสามารถทำซ้ำได้เมื่อ require Puppet ใน interpreter เดียวกัน - ข้อความคอมมิตไม่ได้ทำเอกสารให้ไฟล์ ฟังก์ชัน หรือโค้ดหนึ่งบรรทัดโดยเฉพาะ แต่ทำเอกสารให้ การเปลี่ยนแปลงนั้นเอง จึงเป็นตำแหน่งที่เหมาะสำหรับบันทึกเส้นทางที่ codebase ผ่านมา
ผลพลอยได้ที่ช่วยขยายความรู้ของทีม
- Dan บันทึกคำสั่งที่รันในแต่ละขั้นตอนการสืบค้น ซึ่งอาจเป็นวิธีเผยแพร่ความรู้ภายในทีมอย่างเบา ๆ
- ผู้อ่านสามารถเรียนรู้วิธีใช้เครื่องมือ Unix ได้จากข้อความคอมมิตเพียงอย่างเดียว
- สามารถส่งอาร์กิวเมนต์
-execให้findเพื่อรันคำสั่งกับแต่ละไฟล์ที่พบได้ - หากใส่
\+ท้ายคำสั่ง แทนที่จะรันทีละครั้งต่อไฟล์ จะส่งชื่อไฟล์หลายชื่อให้คำสั่งfileครั้งเดียว file --mimeบอก MIME type ของไฟล์- มีเครื่องมือชื่อ
iconvอยู่
- สามารถส่งอาร์กิวเมนต์
- ไม่ใช่แค่คนที่รีวิวการเปลี่ยนแปลงเท่านั้น แต่คนที่ค้นพบคอมมิตนี้ในภายหลังก็ได้รับข้อมูลเดียวกัน
- เมื่อมีเวลาและคอมมิตสะสมมากพอ ข้อความแบบนี้สามารถกลายเป็น เครื่องขยายความรู้ ของทีมได้
บันทึกที่สร้างความเห็นอกเห็นใจและความไว้วางใจ
- ท้ายคอมมิตมีประโยคว่า “Now the tests work! One hour of my life I won't get back..”
- ประโยคนี้ถ่ายทอดทั้งความหงุดหงิดของนักพัฒนาที่ไล่ตามบั๊กซับซ้อนอยู่หนึ่งชั่วโมง และความพอใจเมื่อแก้ได้
- แม้ในกรณีที่โค้ดแฮ็กระยะสั้นหรือโค้ดต้นแบบถูกนำเข้าโปรดักชันและหยั่งรากอยู่ในระบบ ข้อความเช่นนี้ก็ช่วยเตือนให้ระลึกว่าเบื้องหลังทุกการเปลี่ยนแปลง เคยมีคนที่ตัดสินใจอย่างดีที่สุดภายใต้ข้อมูลที่มีในตอนนั้น
ไม่ใช่ทุกคอมมิตจำเป็นต้องยาว
- กรณีนี้เป็นตัวอย่างแบบสุดโต่ง และโดยเฉพาะอย่างยิ่ง ไม่จำเป็นต้องคาดหวังรายละเอียดระดับเดียวกันจากทุกคอมมิตที่มีขนาดเท่านี้
- ถึงอย่างนั้น นี่ก็เป็นตัวอย่างที่ดีของการอธิบายบริบทเบื้องหลังการเปลี่ยนแปลง ทำให้คนอื่นได้เรียนรู้ และมีส่วนช่วยสร้าง mental model ร่วมกัน ต่อ codebase ของทีม
- หากสนใจข้อความคอมมิตที่ดีและเครื่องมือสำหรับจัดโครงสร้างการเปลี่ยนแปลง สามารถดูแหล่งข้อมูลต่อไปนี้
- Telling stories through your commits by Joel Chippindale
- A branch in time by Tekin Süleyman
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ไม่ว่าจะมองว่าดีหรือแย่ ในฐานะผู้ร่วมก่อตั้ง GitHub และผู้เขียนหนังสือ Git อย่าง Pro Git ก็เห็นว่า ข้อความคอมมิตของ Git เป็นช่องทางเฉพาะตัวสำหรับการทำเอกสารประกอบโค้ด แต่ไม่มีประสิทธิภาพมาก
ปัญหาหลักคือเครื่องมือส่วนใหญ่ เช่น Git, GitHub มัก แสดงแค่บรรทัดแรก เท่านั้น ตัวอย่างคอมมิตก็เห็นเพียงบรรทัดทั่วไปอย่าง “US-ASCII error” ส่วนที่เหลือซึ่งบทความชื่นชม แทบไม่มีใครเห็นในเครื่องมือสมัยใหม่
Git ออกแบบข้อความคอมมิตให้เป็น เนื้อหาอีเมล ที่ทุกคนในโปรเจ็กต์อ่าน แต่ทุกวันนี้ส่วนใหญ่ไม่ได้ทำหน้าที่แบบนั้นแล้ว ถ้าไม่ได้ถกกันเป็นชุดแพตช์ใน mailing list ก็แทบไม่มีใครอ่านเกิน 50 ตัวอักษรแรกของหัวข้อ
ใน
git blameต่อให้ตามหาข้อความที่เกี่ยวข้องด้วย-w -C -C -Cหรือ-Cสองตัว ก็ยังเห็นแค่บรรทัดแรก สุดท้ายต้องหา SHA แล้วใช้git showเพื่ออ่านข้อความยาวอยู่ดี หนึ่งในข้อไม่พอใจที่ใหญ่ที่สุดเกี่ยวกับ Git คือ ถึงจะเขียนดีแค่ไหน ข้อมูลก็หาเจอกลับมาได้ยากมากถ้าดูประวัติของโปรเจ็กต์ Git จะเห็นว่าข้อความคอมมิตแทบทุกครั้งยอดเยี่ยมมาก แต่ถึงจะรัน
blameกับไฟล์เดียว ก็ยังตามบริบทของการพัฒนาฟังก์ชันได้ยากมาก เอกสารที่ Jeff King เขียนไว้ตลอด 10 ปีที่ผ่านมาอยู่ในระดับอัจฉริยะ แต่แทบไม่มีใครได้ซาบซึ้งกับมันเลย ซึ่งเป็นเรื่องน่าเศร้าไม่รู้ว่าทางออกที่ถูกต้องคืออะไร แต่ในชุมชนส่วนใหญ่ การเขียนเอกสารที่ยอดเยี่ยมลงในข้อความคอมมิต น่าเศร้าที่เกือบจะเป็นการเสียเวลา เพราะมันค้นหายากเกินไป
git blame,git log,git showในเทอร์มินัลตลอด การไล่ตามประวัติไฟล์นั้นง่าย และใช้git log -Gหาได้ภายในไม่กี่วินาทีว่าเพิ่มหรือลบบางอย่างเมื่อไรสิ่งที่ยากคือพอหาคอมมิตเจอแล้ว แต่ข้อความมีแค่ “bleh” หรือ “add a thing” ทั้งที่ถ้านักพัฒนาใช้เวลา 60 วินาทีเขียนว่าเหตุใดจึงทำแบบนั้นก็คงพอแล้ว
ในทางกลับกัน เวลาเจอข้อความคอมมิตที่อธิบายอย่างละเอียดว่าทำไมการเปลี่ยนแปลงนั้นจึงเกิดขึ้น ก็รู้สึกดีมาก ข้อความคอมมิตที่ดีเพียงอันเดียวช่วยประหยัดงานไปได้หลายชั่วโมงหรือหลายวัน
GitHub ก็มีส่วนทำให้ปัญหาข้อความคอมมิตแย่ลงด้วย ถ้าโชคดีก็อาจมีรายละเอียดอยู่ในคำอธิบาย PR แต่ไม่ได้อยู่ข้าง ๆ commit log โดยตรง และส่วนใหญ่ PR ก็โยงไปลิงก์ Jira, Jira ก็โยงไปบทสนทนาใน Slack, Slack ก็โยงไป Google document อีกที
วงการนี้ทำเอกสารได้แย่มาก แต่คนอย่าง Jeff King ก็กำลังต่อสู้อย่างถูกทาง ท้ายที่สุดมันไม่ใช่ปัญหาทางเทคนิค แต่เป็นปัญหาของคน การเขียนเอกสารไม่มีรางวัลทันที จึงให้ความรู้สึกเหมือนงานเพิ่ม และผลตอบแทนจะมาปรากฏหลังจากนั้นหลายวัน หลายสัปดาห์ หรือหลายเดือน
ได้โปรดเขียนข้อความคอมมิตดี ๆ กันเถอะ แค่ใช้เวลา 1 นาทีเขียนว่าทำไปทำไม ก็จะช่วยให้ทุกคอมมิตไม่กลายเป็นการอธิบายรั้วของ Chesterton แบบบ้าบอ ถ้าใส่ไว้ในข้อความคอมมิตที่หาเจอง่าย ทั้งตัวคุณในอนาคตและผมจะขอบคุณ
เพิ่มเติมคือ ผมก็ไม่เห็นด้วยกับคำกล่าวที่ว่าข้อความคอมมิตหายาก ผมแทบไม่เคยลำบากในการตามประวัติของบรรทัดโค้ด ฟังก์ชัน หรือไฟล์ และถึงข้อความคอมมิตจะไม่ถูกกลับมาอ่านอีก มันก็ยังมีคุณค่าตั้งแต่ตอนเขียน เพราะการเขียนข้อความดี ๆ ทำให้ผมตรวจสอบได้ว่าผมเขียนโค้ดตรงตามที่ตั้งใจจริงหรือไม่ และมันก็มีคุณค่าต่อผู้รีวิวโค้ดด้วย
ที่บอกว่าหาตัวเลือกของ
git blameยาก ก็ฟังเหมือนมุกตลก IDE ที่ดีควรแสดงข้อมูล blame ติดไว้กับแต่ละบรรทัด และกดปุ่มเดียวเพื่อดู diff ได้ รวมถึงควร recursive blame ต่อได้จากบรรทัดบริบทหรือบรรทัดที่ถูกลบใน diff นั้น เครื่องมืออย่าง Tig ก็ทำแบบนั้นได้พอดียอมรับว่า GitHub ทำให้การดูข้อความคอมมิตยากขึ้น
เอกสารที่แนบมากับคอมมิตไม่ได้เขียนขึ้นมาเพื่อความสนุก แต่มันช่วยลดความเสี่ยงในการรับแพตช์จากคนที่ภายหลังอาจไม่อยู่แล้ว และช่วยเปิดเผยแนวคิดที่เกี่ยวข้องเพื่อให้คนอื่นทำงานต่อยอดได้ ถ้าซ่อนความคิดไว้ ก็จะสะสมความเป็นเจ้าของโค้ดแบบผูกขาด ซึ่งโดยมากไม่ใช่เรื่องดี ข้อความคอมมิตยังทำหน้าที่เป็นหลักฐานของงานที่ทำ และอาจสำคัญขึ้นเมื่อมีแพตช์จำนวนมาก สำหรับโปรเจ็กต์เชิงพาณิชย์ ความสำคัญบางส่วนอาจน้อยลง
จริง ๆ แล้วก็แทบไม่มีที่อื่นให้เก็บเอกสารแบบนี้ มันไม่เหมาะจะอยู่ในคอมเมนต์โค้ด แต่ตอนนี้คนจำนวนหนึ่งกลับคิดว่า Git ก็คือ GitHub และจุดประสงค์เดียวของ Git คือเอาการเปลี่ยนแปลงขึ้น GitHub
Git เองก็ไม่ได้ดีนัก แต่ก็ยังแย่น้อยกว่าสิ่งอื่นมาก เราควรกลับไปสู่พื้นฐานและเข้าใจ จุดประสงค์ที่แท้จริงของ version control อีกครั้ง
เพราะแบบนั้นมันอาจไม่ได้ช่วยชุมชนปัจจุบันมากนัก แต่จะช่วยคนที่ต้องดีบักในอีกหลายปีข้างหน้าได้
โดยรวมเห็นด้วยกับเจตนาหลัก แต่ถ้าวาง BLUF ที่ชัดเจนกว่านี้ไว้ข้างหน้าจะดีกว่า เช่นเขียนว่า “Fix test issues caused by non-breaking space character \xa0”
จะได้รู้ทันทีว่าปัญหาคืออะไร และถ้าอยากรู้เพิ่มก็ยังเลือกอ่านด้านล่างต่อได้
เพราะงั้นสำหรับการค้นย้อนหลังในประวัติ แค่มี ข้อความบรรทัดแรก ที่ดีก็เพียงพอแล้ว เรื่องสั้น ๆ ว่าตามหาต้นตอของบั๊กจนไปถึงนาร์เนียแล้วกลับมา ผมว่าไม่ค่อยเกี่ยวเท่าไร แต่อย่างน้อยก็ไม่ได้คัดค้านถ้าจะระบายไว้ในคำอธิบาย PR หรือข้อความขยายของคอมมิต
ผมเคยรู้สึกภูมิใจกับการเขียนคอมมิตเมสเสจที่ยอดเยี่ยม แต่ไม่ค่อยมั่นใจเท่าไรในคุณค่าที่มันมอบให้คนอื่น เวลาเจอข้อความ error แปลก ๆ หรือเพิ่มฟีเจอร์ใหม่ หรือจริง ๆ แล้วแทบทุกกรณี ผมไม่คิดว่าคนส่วนใหญ่จะค้นคอมมิตเมสเสจ
ฟังดูเศร้านิดหน่อย แต่ยิ่งสงสัยมากขึ้นว่าคอมมิตเมสเสจที่สวยงามนั้นใกล้เคียงกับ ความหลงตัวเอง ของโปรแกรมเมอร์อยู่พอสมควร คนที่ชื่นชมมันมากที่สุดก็มักเป็นคนเขียนเอง ส่วนคนอื่นก็ผ่านไปโดยไม่ทันสังเกต
บางครั้งก็มีพื้นที่สำหรับความประณีตแบบนั้นอยู่ แต่ผมไม่แน่ใจว่ามันมีคุณค่าเชิงปฏิบัติมากนัก ถ้าคนอื่นคอมมิตว่า “fix whitespace issue” ตอนนี้ผมก็ไม่ค่อยใส่ใจแล้ว และคิดว่านั่นทำให้ผมเป็นเพื่อนร่วมงานที่ดีขึ้น
โปรเจกต์อย่าง Git หรือ Linux ที่มีทีมกระจายตัวขนาดใหญ่และคอมมิตจำนวนมหาศาลอาจต่างออกไป โปรเจกต์ที่ผมคุ้นเคยมีผู้ร่วมพัฒนา 1 ถึง 100 คน และส่วนใหญ่อยู่ในองค์กรเดียวกัน
เวลา Google หรือ Stack Overflow ไม่มีคำตอบ ผมก็จะไปหาบน GitHub ว่ามี PR หรือคอมมิตเมสเสจที่พูดถึงเรื่องคล้ายกันไหม รวมถึงรีโพส่วนตัวที่ผมเข้าถึงได้ด้วย ซึ่งช่วยผมมานับครั้งไม่ถ้วน คอมมิตเมสเสจที่ดีมีคุณค่ามากกว่าความหลงตัวเองอย่างแน่นอน ถ้านักพัฒนาหลายคนไม่อ่าน ก็เป็นการเสียโอกาสของพวกเขาเอง และหวังว่าเมื่อมีประสบการณ์มากขึ้น วันหนึ่งพวกเขาจะเข้าใจ จะสอนนักพัฒนาจูเนียร์เรื่องวิธีค้นหา หรือส่งบทความต้นฉบับให้พวกเขาอ่านก็ได้
หลังจากนั้นผมก็พยายามเขียนคอมมิตเมสเสจอย่างน้อยให้ตัวผมในอนาคตนึกออกได้ว่าทำไมตอนนั้นถึงต้องเปลี่ยน
git blameก่อนจะเปลี่ยนโค้ดสักบรรทัด ก็แปลว่าคุณกำลังทำผิดอยู่หลายครั้งผมกำลังจะแก้บั๊กที่ดูชัดเจน แต่พอก่อนคอมมิตได้กลับไปดูคอมมิตก่อนหน้า ก็พบว่า “บั๊ก” นั้นใส่มาโดยตั้งใจ และงาน JIRA ที่ลิงก์ไว้ก็อธิบายไว้อย่างดีว่าทำไมการแก้ที่ดูชัดเจนของผมจะไปทำให้บั๊กเมื่อ 2 ปีก่อนกลับมาอีก
git blameใน IDE บ่อยมากเพื่อดูว่าเกิดอะไรขึ้น พอเจอคอมมิตเมสเสจดี ๆ ก็รู้สึกขอบคุณบรรทัดแรกของคอมมิตเมสเสจสำคัญที่สุด เพราะ
git logใช้มันเพื่อรับมือกับ รั้วของเชสเตอร์ตัน ได้ ซึ่งในกรณีนี้ผมคิดว่าผู้เขียนพลาดเต็ม ๆประเด็นสำคัญคือบรรทัดแรกควรใส่เหตุผลว่าทำไปทำไม ไม่ใช่ใส่ว่าทำอะไรไปบ้าง คนที่สนใจก็ไปดูโค้ดหรือ diff เองได้ว่าอะไรเปลี่ยน
เช่นจะเขียนว่า “nginx .conf files must be in us-ascii” แล้วตามด้วย “changed blahblah.erb to remove nonbreaking space character” จากนั้นค่อยต่อด้วยคอมมิตเมสเสจส่วนที่เหลือที่ค่อนข้างดีอยู่แล้วก็ได้
ควรคิดแบบเขียนข่าว สมมุติว่าผู้อ่านอาจหยุดอ่านตรงไหนก็ได้ แล้วเรียงลำดับจากสิ่งที่สำคัญที่สุดไปหาสิ่งที่สำคัญน้อยลง พร้อมเพิ่มรายละเอียดมากขึ้นเรื่อย ๆ
แม้แต่พาดหัวข่าวก็อธิบายว่าเกิดอะไรขึ้น ไม่ใช่ว่าทำไม
ในกรณีนี้ บรรทัดแรกของต้นฉบับเหมาะแล้ว พอไล่ดู
git logก็พอจะข้ามคอมมิตนี้ไปได้ เพราะมีแนวโน้มสูงว่ามันไม่ได้เปลี่ยนพฤติกรรมเชิงฟังก์ชันของการทดสอบ“nginx .conf files must be in us-ascii” อาจเหมาะเป็นหัวข้อบั๊กหรือชื่อ PR แต่ก็อาจสอดคล้องกับหลายคอมมิตที่ทำคนละอย่างกัน และไม่ได้บอกจริง ๆ ว่าเกิดอะไรขึ้น อาจเป็นการแปลงไฟล์ให้เป็น US-ASCII, การสร้างเครื่องมือสำหรับแปลง, การอัปเดตเอกสาร, การเขียนเทสต์ หรือหลายอย่างรวมกันก็ได้ ถ้าเริ่มจาก อะไร แทนที่จะเป็น ทำไม ก็จะลดความสับสนนั้นได้
จะเป็น “The files must be in us-ascii” หรือ “Changed the files to us-ascii” ก็ไม่ได้ต่างกันมาก ทั้งสองแบบต่างก็สื่อชัดว่ามีการเปลี่ยนไฟล์ให้เป็น US-ASCII
ข้อเสียของการทำเอกสารแบบนี้คือ ข้อความคอมมิต ที่เขียนไปแล้วแทบจะแก้ไม่ได้อีก
แน่นอนว่าทำได้ด้วย
rebaseแต่ถ้าเป็นสิ่งที่เขียนไว้เมื่อ 1 ปีก่อนและถูกรวมเข้าmainไปแล้ว จะถึงขั้นแก้มันจริง ๆ แล้วสร้างความลำบากให้ feature branch ของทุกคนหรือถ้าเทียบกับเอกสารที่เก็บไว้ในไฟล์
.md, Wiki, หรือ Confluence เนื้อหาที่เพื่อนร่วมงานเขียนสามารถให้ฉันปรับปรุงได้ และสิ่งที่ฉันเขียนก็ให้เพื่อนร่วมงานคนอื่นมาปรับปรุงได้เช่นกันในกรณีนี้บั๊กอาจถูกแก้แล้วและอาจไม่เกิดขึ้นอีก แต่เวลาคอมมิตคอมโพเนนต์ใดสักตัวก็มักมีแรงจูงใจให้อธิบายการออกแบบของมัน ซึ่งตอนนี้ฉันหลีกเลี่ยงแล้ว ถ้าคอมโพเนนต์นั้นเปลี่ยนไปในภายหลังเพราะข้อกำหนดทางธุรกิจเปลี่ยนล่ะ เอกสารในคอมมิตจะเหลือแค่อธิบายความต่างหรือไม่ ถ้าเป็นอย่างนั้น สมาชิกทีมใหม่ที่ต้องการเข้าใจระบบก็ต้องไปอ่านข้อความคอมมิตหลายอันแล้วรวมความเข้าใจเองในหัว
การเอาไปเทียบกับไฟล์
.md, Wiki, หรือ Confluence ก็เหมือนเอาจักรยานไปเทียบกับห่านข้อพิจารณาหรือการแลกเปลี่ยนที่มีตอนสร้างคอมโพเนนต์นั้น หรือแม้แต่ข้อเท็จจริงที่ว่าไม่มีสิ่งเหล่านั้นเลย มักมีประโยชน์ต่อการทำความเข้าใจข้อบกพร่องดั้งเดิม วิวัฒนาการหลังจากนั้น และข้อบกพร่องที่เกิดจากกรณีการใช้งานที่เปลี่ยนไป
ถ้าสมาชิกทีมใหม่ต้องการเข้าใจระบบ ก็แค่ดูแลเอกสาร “สถานะปัจจุบัน” แยกไว้ เอกสารนั้นไม่จำเป็นต้องลงรายละเอียดถึงการแลกเปลี่ยนเชิง implementation หรือความจริงที่ว่าฉบับร่างแรกถูกเขียนขึ้นภายใต้แรงกดดันด้านเวลา
การ squash คอมมิตทำให้บันทึกดีขึ้นในฐานะเรื่องเล่าของการเพิ่มฟีเจอร์ ขณะที่ merge รักษา log ที่ไม่เปลี่ยนแปลงของการเปลี่ยนโค้ดจริงไว้ และ reorder ก็ทำทั้งสองอย่างอย่างละครึ่ง
ไม่มีเหตุผลว่าทำไมจะมีทั้งสองแบบพร้อมกันไม่ได้ ก็เราเป็นคนที่เขียนโปรแกรมคอมพิวเตอร์กันอยู่แล้ว จะสร้างให้เป็นแบบที่ต้องการก็ได้
ถ้าผมจะเขียน Git ใหม่ ผมจะแยกคอมมิตออกเป็นสองส่วน ประวัติการเปลี่ยนแปลงจะคงความไม่เปลี่ยนแปลงไว้ในโครงสร้างแบบ Merkle DAG เหมือน Git ส่วนข้อความคอมมิตจะเก็บไว้ใน data store ที่เกี่ยวข้องแยกต่างหาก เพื่อให้เป็น log ที่สมเหตุสมผลและแก้ไขได้สำหรับอธิบาย workflow จะจัดกลุ่มคอมมิตตามแท็กฟีเจอร์ แก้คำผิด และเปลี่ยนข้อความได้ตามต้องการ โดยยังคงเก็บ log ด้านล่างนั้นไว้เหมือนเดิม นั่นคือ “สิ่งที่เปลี่ยนจริงในโค้ด”
git notesก็ได้ เพียงแต่ถ้าข้อความยาวขนาดนั้นก็ดูไม่น่ามีใครสังเกตเห็นมีอยู่จุดหนึ่งที่ผมไม่เห็นด้วย คือประโยคที่ว่า “ผมไม่ได้คาดหวังรายละเอียดระดับนี้จากทุกคอมมิต โดยเฉพาะคอมมิตขนาดประมาณนี้”
จากประสบการณ์ของผม ตรงกันข้ามเลย ของเล็ก ๆ ที่ดูไม่มีพิษมีภัยมักต้องการคำอธิบายที่ยาวกว่าเมื่อเทียบกัน
เมื่อวานผมเขียนไว้สามย่อหน้าว่าทำไมถึงเพิ่ม
--limit=999ให้gh pr listเพราะมันชวนสับสน ภายในอาร์กิวเมนต์--jqก็มีlimit(อยู่แล้ว และถ้าถือว่า PR ทั้งหมดมีจำนวนอนันต์ ยิ่งค่ามาก ผลลัพธ์สุดท้ายก็ยิ่งน้อยลงจริง ๆผมยังเขียน code comment ไว้ด้วย และน่าจะใช้เวลาคิดกับเกลามันมากกว่าตอนลงมือเขียนเสียอีก เวลามีใครบอกเป็นนัยว่างานนี้คือการปั๊มโค้ดออกมามั่ว ๆ ก็อยากให้จำตัวอย่างนี้ไว้เป็นตัวอย่างถัดไป
แค่ “This was a non-ascii whitespace character that caused
ArgumentError: invalid byte sequence in US-ASCIIwhen runningbundle exec rake” ก็น่าจะพอแล้ว มีทั้งคีย์เวิร์ดสำหรับค้นหาปัญหาคล้ายกันในภายหลัง มีสาเหตุรากของปัญหา และไม่ยาวเกินไปจนคนมักจะไถผ่านผมไม่คิดว่านี่เป็นคอมมิต Git ที่ยอดเยี่ยม
เมื่อเทียบกับข้อความจำนวนมากนั้น บรรทัดแรก “Convert template to US-ASCII to fix error” น่าจะทำให้ดีขึ้นได้ แค่เพิ่มอีกไม่กี่คำว่าช่องว่างแบบไหนเป็นตัวก่อปัญหา และ error คืออะไร
เอาจริง ๆ ที่เหลือแทบไม่มีประโยชน์ ไม่ได้เป็นโทษ แต่ก็ไม่ได้มีคุณค่ามาก ผู้เขียนบันทึกเส้นทางที่ใช้ตามหาบั๊กนี้ไว้ ซึ่งก็อดคิดไม่ได้ว่าใครจะสนใจ
ในบทความยังมีลิงก์ผลการค้นหาที่แสดงคอมมิตหลายอันจากคนที่ได้เรียนรู้อะไรบางอย่างจากการแก้นั้น
ข้อความคอมมิตนั้นคือ ขุมทรัพย์แห่งความรู้
ถ้าอยากดูข้อความคอมมิตที่ยอดเยี่ยม ให้ไปดู Git history ของ Linux kernel ที่นั่นนี่คือมาตรฐาน
บรรทัดแรกจะพูดถึง subsystem ที่ได้รับผลกระทบจากการเปลี่ยนแปลงเสมอ แล้วตามด้วยสรุปหนึ่งบรรทัดในรูปคำสั่ง จากนั้นจะตอบสามคำถามให้ละเอียดที่สุดเท่าที่ทำได้
ตัวอย่างเช่นอาจเขียนว่า “โค้ดปัจจุบันทำ X เมื่อรัน test case T พบพฤติกรรมที่ไม่คาดคิด U ซึ่งเกิดจากเหตุผล R จึงแก้โดยทำ F”
เมื่อไม่นานมานี้มีผู้ร่วมพัฒนาบอกว่าวิธีเขียนข้อความ Git ของฉัน หรือพูดอีกอย่างคือข้อกำหนดของฉันนั้น “แปลกเฉพาะตัว” ดูเหมือนภูมิหลังจาก Linux kernel จะโผล่ออกมา แต่ข้อความคอมมิตทั้งหมดของฉันก็หน้าตาเป็นแบบที่แสดงไว้ที่นี่
ถ้าเป็นเรื่องเกี่ยวกับโค้ดเดิม คำอธิบายก็ควรอยู่ไปพร้อมกับโค้ด ส่วนเรื่องที่เกี่ยวกับกระบวนการ เช่น โค้ดที่ถูกลบออกไปหรือโค้ดที่เคยไม่ทำงาน ควรอยู่ในคอมมิต
สิ่งที่สำคัญที่สุดคือ ถึงแม้ข้อความคอมมิตจะอ้างอิง issue เพื่อความสะดวกได้ แต่ก็ต้อง ระบุรายละเอียดแกนหลักซ้ำไว้ให้ครบ GitHub เป็นของชั่วคราว แต่ข้อความ Git ไม่ใช่
ข้อความคอมมิตที่อัดแน่นด้วยบริบทอยู่ที่นี่[1]
เรื่องแบบนี้เกิดขึ้นบ่อยมากจนผู้ดูแลรักษาต้องเขียนบทความนี้[2]
[1] https://github.com/git/git/commit/d70f554cdf38b0b05cfaa8e8eb...
[2] https://lore.kernel.org/git/xmqqedevo8ps.fsf@gitster.g/