ข้าม​ไป​ยัง​เนื้อหา

The 50/72 Rule of Git

กฎ​เขียน commit message ให้​ชัดเจน​และ​อ่าน​ง่าย

กฎ 50/72 เป็น​ข้อ​ตกลง​ที่​ไม่​เป็น​ทางการ (convention) สำหรับ​จัด​รูปแบบ Git commit message ให้​อ่าน​ง่าย​ทั้ง​ใน terminal, git log, และ​เว็บ interface ของ Git repository ตัวเลข​ทั้ง​สอง​คือ:

  • หัวเรื่อง (subject line) ไม่​เกิน 50 ตัว​อักษร: บรรทัด​แรก​ของ commit message ควร​สรุป​การ​เปลี่ยนแปลง​อย่าง​กระชับ เขียน​ด้วย imperative mood เช่น Add, Fix, Refactor (ไม่ใช่ Added หรือ Fixes) เพื่อ​ให้​สอดคล้อง​กับ​ข้อความ​ที่ Git เอง​สร้าง​ให้​อัตโนมัติ เช่น​ตอน git merge หรือ git revert
  • เนื้อความ (body) แต่ละ​บรรทัด​ไม่​เกิน 72 ตัว​อักษร: ส่วน​เนื้อความ​เป็น​ทาง​เลือก แต่​ถ้า​มี ควร​คั่น​จาก​หัวเรื่อง​ด้วย​บรรทัด​ว่าง​เสมอ เพราะ​เครื่องมือ​อย่าง git rebase -i และ git format-patch ใช้​บรรทัด​ว่าง​นี้​แยก​ส่วน​หัวเรื่อง​ออก​จาก​เนื้อความ

ตัวเลข 50 และ 72 ไม่ใช่​ข้อ​บังคับ​ทาง technical ของ Git แต่​มา​จาก​ธรรมเนียม​ที่ Tim Pope เผยแพร่​ใน​บทความ “A Note About Git Commit Messages” (2008) และ​ภายหลัง Chris Beams ขยาย​ความ​ใน​บทความ “How to Write a Git Commit Message” จน​กลาย​เป็น​มาตรฐาน​พฤตินัย (de facto) ของ​อุตสาหกรรม ที่มา​ของ​ตัวเลข 72 คือ: เทอร์มินัล​มาตรฐาน​กว้าง 80 column และ​เมื่อ Git แสดง​เนื้อความ commit มัน​มัก indent ด้วย 4 ช่องว่าง​ทั้ง​สอง​ด้าน (80 - 4 - 4 = 72) ทำให้​ข้อความ​ยัง​คง​พอดี​ใน​บรรทัด​เดียว​แม้​ถูก​เยื้อง ส่วน 50 ตัว​อักษร​มา​จาก​การ​สังเกต​ว่า​เป็น​ความ​ยาว​หัวเรื่อง​ที่​พบ​บ่อย​ที่สุด​ใน commit ของ Linux kernel และ​บังคับ​ให้​ผู้​เขียน​คิด​ทบทวน​ก่อน​สรุป​สั้น ๆ

  1. เขียน​หัวเรื่อง​แบบ imperative และ​กระชับ — ตอบ​คำถาม​ว่า “ถ้า apply commit นี้ มัน​จะ…” เช่น “Add user authentication feature” ไม่ใช่ “Added user authentication feature” หรือ “Adding user auth”
  2. เว้น​บรรทัด​ว่าง​หนึ่ง​บรรทัด​ระหว่าง​หัวเรื่อง​กับ​เนื้อความ​เสมอ แม้​เนื้อความ​จะ​สั้น​ก็ตาม
  3. ห่อ (wrap) เนื้อความ​ที่ 72 ตัว​อักษร​ต่อ​บรรทัด ด้วย​ตนเอง​หรือ​ให้ editor ทำให้ (เช่น​ตั้ง​ค่า textwidth ใน Vim หรือ​ใช้ git commit แบบ​เปิด editor ที่ config ไว้)
  4. ใช้​เนื้อความ​อธิบาย “ทำไม” ไม่ใช่​แค่ “ทำ​อะไร” เพราะ diff บอก “อะไร” เปลี่ยน​ได้​อยู่​แล้ว แต่​เหตุผล​เบื้องหลัง​การ​ตัดสิน​ใจ​มัก​หาย​ไป​ถ้า​ไม่​บันทึก​ไว้
  5. อ้างอิง issue หรือ ticket ที่​เกี่ยวข้อง เมื่อ​มี เพื่อ​โยง​บริบท​กลับ​ไป​ยัง requirement หรือ bug report
  6. ตั้ง​ค่า Git ให้​ช่วย​เตือน​ความ​ยาว เช่น​ใช้ git config core.editor ผูก​กับ editor ที่​มี ruler แสดง​ตำแหน่ง column ที่ 50 และ 72 หรือ​ใช้ commit-msg hook ตรวจสอบ​ความ​ยาว​อัตโนมัติ​ก่อน​อนุญาต​ให้ commit สำเร็จ
flowchart TD
    Start[เริ่มเขียน commit message]
    Subject[หัวเรื่อง imperative ไม่เกิน 50 ตัวอักษร]
    NeedBody{ต้องอธิบายเพิ่มไหม}
    Blank[เว้นบรรทัดว่าง]
    Body[เนื้อความ wrap ที่ 72 ตัวอักษรต่อบรรทัด]
    Done[commit]
    Start --> Subject --> NeedBody
    NeedBody -- ไม่ --> Done
    NeedBody -- ใช่ --> Blank --> Body --> Done

ตัวอย่าง commit message ที่​จัด​รูปแบบ​ตาม​กฎ 50/72 — หัว​เรื่องสั้น กระชับ ตาม​ด้วย​บรรทัด​ว่าง แล้ว​จึง​เป็น​เนื้อความ​ที่​ห่อ​บรรทัด​ไว้​ไม่​เกิน 72 ตัว​อักษร:

Add user authentication feature
- Implemented user login functionality
- Added password hashing using bcrypt
- Integrated user session management
- Updated tests to cover new authentication logic
This commit introduces a new user authentication feature, allowing
users to securely log in and manage their sessions. Motivation: the
previous session handling stored plaintext tokens in cookies, which
failed our security review. Bcrypt hashing closes that gap.
Refs: #482

ตั้ง​ค่า commit template ให้​ทีม​เห็น​โครง​ร่าง 50/72 ทุก​ครั้ง​ที่​เปิด editor เขียน commit ได้​ผ่าน git config:

// ตัวอย่าง file .gitmessage.txt ที่ใช้เป็น commit template
// หัวเรื่อง: ไม่เกิน 50 ตัวอักษร เขียนแบบ imperative
//
// เนื้อความ: ห่อบรรทัดที่ 72 ตัวอักษร อธิบาย "ทำไม" ไม่ใช่แค่ "ทำอะไร"
// - รายการที่เปลี่ยนแปลง
//
// Refs: #ticket-number
// ตั้งค่าให้ Git ใช้ file นี้เป็น template เริ่มต้นทุกครั้งที่ commit:
// $ git config --global commit.template ~/.gitmessage.txt
// ตัวอย่างใน code C#: การตรวจสอบความยาวหัวเรื่องด้วย pre-commit hook (เขียนเป็น script
// แยกต่างหาก ไม่ใช่ C# โดยตรง) แต่แนวคิดเดียวกันนำไปใช้ตรวจสอบ string บรรทัดแรกได้ เช่น
// การจำกัดความยาวชื่อ field ใน DTO ที่จะ serialize เป็น commit-like log entry
public sealed class ChangeLogEntry
{
private const int SubjectMaxLength = 50;
private const int BodyLineMaxLength = 72;
public string Subject { get; }
public IReadOnlyList<string> BodyLines { get; }
public ChangeLogEntry(string subject, IReadOnlyList<string> bodyLines)
{
if (subject.Length > SubjectMaxLength)
{
throw new ArgumentException(
$"Subject exceeds {SubjectMaxLength} characters.", nameof(subject));
}
foreach (var line in bodyLines)
{
if (line.Length > BodyLineMaxLength)
{
throw new ArgumentException(
$"Body line exceeds {BodyLineMaxLength} characters.", nameof(bodyLines));
}
}
Subject = subject;
BodyLines = bodyLines;
}
}

ประโยชน์

  • ความ​ชัดเจน: การ​จำกัด​หัวเรื่อง​ไว้​ที่ 50 ตัว​อักษร​บังคับ​ให้​ผู้​เขียน​สรุป​การ​เปลี่ยนแปลง​อย่าง​รวบรัด ทำให้​คน​อื่น​เข้าใจ​จุด​ประสงค์​หลัก​ของ commit ได้​ใน​พริบตา​เมื่อ​ดู​ผ่าน git log --oneline
  • ความ​อ่าน​ง่าย: ขีด​จำกัด 72 ตัว​อักษร​สำหรับ​เนื้อความ​ทำให้​ข้อความ​อ่าน​ง่าย​ใน​หลาย interface ทั้ง terminal และ​เว็บ​ของ Git repository โดย​ไม่มี​การ​ตัด​บรรทัด​ที่​ผิด​ตำแหน่ง
  • ความ​สอดคล้อง: การ​ใช้​รูปแบบ​มาตรฐาน​เดียวกัน​ช่วย​รักษา​ประวัติ (history) ให้​สม่ำเสมอ ทำให้​ไล่​ดู​วิวัฒนาการ​ของ project ได้​ง่าย และ​เข้า​กัน​ได้​กับ​เครื่องมือ​ที่​พึ่งพา convention นี้ เช่น git format-patch, git shortlog, หรือ GitHub UI ที่​ตัด​ข้อความ​หัวเรื่อง​ยาว​เกิน 72 ตัว​อักษร​ด้วย​จุด​ไข่ปลา
  • บังคับ​ให้​คิด​ก่อน​เขียน: ขีด​จำกัด​ความ​ยาว​เป็น​กลไก​เชิง​พฤติกรรม​ที่​ทำให้​ผู้​เขียน​ต้อง​กลั่นกรอง​ว่า​อะไร​คือ​แก่น​ของ​การ​เปลี่ยนแปลง​จริง ๆ แทนที่​จะ​พรรณนา​ยืดยาว

ข้อ​ควร​ระวัง

  • 50 และ 72 ไม่ใช่ hard limit ทาง technical — Chris Beams เอง​ก็​ระบุ​ว่า 50 เป็น “rule of thumb” ไม่ใช่​ขีด​จำกัด​ที่ Git บังคับ การ​ยึด​ตัวเลข​อย่าง​เคร่งครัด​เกิน​ไป​อาจ​ทำให้​บาง​หัวเรื่อง​ดู​ห้วน​หรือ​คลุมเครือ
  • อย่า​ใช้​เป็น​ข้อ​อ้าง​ละเลย​เนื้อหา — จัด​บรรทัด​สวย​แต่​ไม่มี​เนื้อความ​อธิบาย “ทำไม” เลย ก็​ยัง​ทำให้​ประวัติ commit อ่าน​ยาก​อยู่ดี รูปแบบ​เป็น​เพียง​เปลือก เนื้อหา​สำคัญ​กว่า
  • ต้อง​มี​เครื่องมือ​หรือ​วินัย​ช่วย​บังคับ — ถ้า​ไม่มี editor ที่​ตั้ง ruler หรือ commit-msg hook คอย​เตือน ทีม​มัก​ลืม​และ​ปล่อย​ให้​หัวเรื่อง​ยาว​เกิน​โดย​ไม่รู้ตัว
  • ใช้​คู่​กับ Conventional Commits ได้ แต่​ต้อง​ตกลง​กัน​ใน​ทีม — ถ้า​ทีม​ใช้ prefix เช่น feat:, fix: ต้อง​คำนวณ​ความ​ยาว prefix รวม​เข้า​กับ​ขีด​จำกัด 50 ตัว​อักษร​ด้วย ไม่​เช่น​นั้น​หัวเรื่อง​จริง​จะ​สั้น​เกิน​ไป​จน​สื่อ​ความ​ไม่​ครบ