Conventional Commits

ข้อกำหนดในการทำให้มนุษย์และเครื่องจักรเข้าใจความหมายของข้อความ commit

Conventional Commits 1.0.0

ข้อสรุป

ข้อกำหนดของ Conventional Commits คือข้อตกลงอย่างง่ายที่สร้างขึ้นสำหรับข้อความที่ commit ข้อกำหนดนี้จะรวมข้อกำหนดในการสร้างข้อความในการ commit อย่างชัดเจน ซึ่งจะช่วยให้สามารถเขียนชุดเครื่องมืออัตโนมัติต่อยอดได้ง่ายขึ้น ข้อตกลงนี้จะใช้รูปแบบเดียวกับ SemVer โดยมีการอธิบายถึงฟีเจอร์ การแก้ไขต่าง ๆ และการเปลี่ยนแปลงที่ขัดต่อเวอร์ชั่นก่อนหน้าลงไปในข้อความที่ commit

ข้อความที่ commit ควรจะมีโครงสร้างตามนี้


<ชนิด>[ละได้ ขอบเขต]: <รายละเอียด>

[ละได้ เนื้อหา]

[ละได้ ข้อความลงท้าย]

โดย commit จะมีหน่วยโครงสร้างย่อย ๆ ตามนี้ เพื่อใช้ในการสื่อสารถึงความตั้งใจให้กับคนที่นำไลบรารี่ของคุณไปใช้งาน

  1. fix: commit ที่มี ชนิด fix หมายถึงมีการแก้ไขบักในโค้ดของคุณ (จะสอดคล้องกับ PATCH ใน Semantic Versioning)
  2. feat: commit ที่มี ชนิด feat หมายถึงมีการเพิ่มฟีเจอร์ใหม่เข้าไปในโค้ด (จะสอดคล้องกับ MINOR ใน Semantic Versioning)
  3. BREAKING CHANGE: commit ที่ลงท้ายด้วย BREAKING CHANGE: ในข้อความลงท้าย หรือ ต่อท้ายด้วย ! หลังจาก type หรือ scope จะหมายถึงมีการเพิ่มการเปลี่ยนแปลงที่กระทบกับ API เดิม (จะสอดคล้องกับ MAJOR ใน Semantic Versioning) โดยที่ BREAKING CHANGE สามารถเป็นส่วนหนึ่งของ commit ชนิด ไหนก็ได้
  4. ชนิด อื่น ๆ ที่ไม่ใช่ fix: and feat: สามารถใช้ได้เช่นกัน เช่น @commitlint/config-conventional (อ้างอิงจาก ข้อตกลงของ Angular) ได้แนะนำชนิด build:, chore:, ci:, docs:, style:, refactor:, perf:, test: และอื่น ๆ
  5. ข้อความลงท้าย ที่นอกเหนือจาก BREAKING CHANGE: <รายละเอียด> สามารถใช้ได้ และเขียนตามข้อตกลงเดียวกันกับ git trailer format

ชนิดอื่น ๆ เพิ่มเติมไม่ได้อยู่ในขอบเขตตามข้อกำหนดของ Conventional Commits นี้ และไม่ได้มีผลกระทบอะไรใน Semantic Versioning (ถ้าไม่ได้ระบุใน BREAKING CHANGE) ขอบเขตอาจจะถูกระบุไปกับชนิดของ commit เพื่อบอกข้อมูลของบริบทเพิ่มเติม โดยจะระบุอยู่ในเครื่องหมายวงเล็บ เช่น feat(parser): add ability to parse arrays

ตัวอย่าง

ข้อความ commit ที่มีการระบุรายละเอียด และลงท้ายด้วย breaking change ในข้อความลงท้าย

feat: allow provided config object to extend other configs

BREAKING CHANGE: `extends` key in config file is now used for extending other config files

ข้อความ commit ที่มี ! เพื่อบ่งบอก breaking change

feat!: send an email to the customer when a product is shipped

ข้อความ commit ที่ระบุขอบเขต และมี ! เพื่อบ่งบอก breaking change

feat(api)!: send an email to the customer when a product is shipped

ข้อความ commit ที่มีทั้ง ! และ BREAKING CHANGE ลงท้าย

chore!: drop support for Node 6

BREAKING CHANGE: use JavaScript features not available in Node 6.

ข้อความ commit ที่ไม่มีเนื้อหา

docs: correct spelling of CHANGELOG

ข้อความ commit ที่ระบุขอบเขต

feat(lang): add polish language

ข้อความ commit ที่มีเนื้อหาหลายย่อหน้า และมีข้อความลงท้ายหลายข้อความ

fix: prevent racing of requests

Introduce a request id and a reference to latest request. Dismiss
incoming responses other than from latest request.

Remove timeouts which were used to mitigate the racing issue but are
obsolete now.

Reviewed-by: Z
Refs: #123

ข้อกำหนด

คำสำคัญ “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, และ “OPTIONAL” ในเอกสารฉบับนี้จะถูกแปลตามที่อธิบายไว้ใน RFC 2119

  1. ข้อความ commit จะต้องขึ้นต้นด้วย ชนิด ซึ่งประกอบด้วยคำนาม feat, fix, ฯลฯ และตามด้วยขอบเขตซึ่งอาจจะละไว้ได้ และตามด้วย ! ซึ่งอาจจะละไว้ได้ และเครื่องหมายโคล่อน (:) และเว้นวรรค
  2. ชนิด feat จะถูกใช้เมื่อใน commit นั้นมีการเพิ่มฟีเจอร์ใหม่เข้าไปในแอพพลิเคชั่น หรือไลบรารี่ของคุณ
  3. ชนิด fix จะถูกใช้เมื่อ commit นั้นเป็นการแก้ไขบักสำหรับแอพพลิเคชั่นของคุณ
  4. ขอบเขตอาจจะถูกเขียนหลังจากชนิด โดยขอบเขตจะต้องอธิบายได้ถูกส่วนของโค้ด และอยู่ภายใต้วงเล็บ เช่น fix(parser):
  5. คำอธิบายจะต้องอยู่ต่อจากเครื่องหมายโคล่อนและเว้นวรรคที่อยู่หลังจากชนิดและขอบเขตในตอนแรกทันที คำอธิบายจะเป็นข้อความสรุปอย่างสั้นสำหรับการเปลี่ยนแปลงของโค้ด เช่น fix: array parsing issue when multiple spaces were contained in string
  6. เนื้อหา commit ที่ยาวกว่าสามารถใส่เพิ่มหลังจากข้อความ commit แบบสั้นแล้วได้ โดยให้ใส่ข้อมูลในบริบทเพิ่มเติมที่เกี่ยวข้องกับความเปลี่ยนแปลงของโค้ด โดยเนื้อหานี้จะต้องเริ่มด้วยการเว้นบรรทัดว่างหนึ่งบรรทัดหลังจากรายละเอียดของ commit ในบรรทัดแรก
  7. เนื้อหา commit ใส่ได้ตามอิสระ และอาจจะมีหลายย่อหน้าก็ได้
  8. ข้อความลงท้ายอาจจะมีมากกว่าหนึ่ง และจะต้องอยู่หลังจากเนื้อหาโดยการเว้นบรรทัดว่างหนึ่งบรรทัด โดยข้อความลงท้ายแต่ละข้อความจะต้องประกอบด้วย กลุ่มคำ และตามด้วย :<เว้นวรรค> หรือ <เว้นวรรค># เป็นตัวคั่น และตามด้วยข้อความ (ส่วนนี้ได้แรงบันดาลใจมาจาก git trailer convention)
  9. กลุ่มคำในข้อความลงท้ายจะต้องใช้ - แทนช่องว่าง เช่น Acked-by (ซึ่งจะช่วยแยกแยะส่วนที่เป็นข้อความลงท้ายกับเนื้อหาที่มีหลายย่อหน้าออกจากกัน) ข้อยกเว้นเดียวคือ BREAKING CHANGE ซึ่งอาจจะถูกใช้เป็นกลุ่มคำได้เช่นกัน
  10. ข้อความในข้อความลงท้ายอาจจะมีเว้นวรรค และมีการขึ้นบรรทัดใหม่ก็ได้ การแยกข้อความลงท้ายหนึ่งข้อความจะสิ้นสุดเมื่อเจอกลุ่มคำและตัวคั่นในข้อความลงท้ายถัดไป
  11. การเปลี่ยนแปลงที่มีผลกระทบจะต้องมีการบ่งชี้ให้เห็นในส่วนของชนิด หรือขอบเขตในตอนต้น หรือเป็นส่วนหนึ่งของข้อความลงท้าย
  12. ถ้าการเปลี่ยนแปลงที่มีผลกระทบเป็นส่วนหนึ่งของข้อความลงท้าย การเปลี่ยนแปลงนั้นจะต้องขึ้นต้นด้วยคำว่า BREAKING CHANGE (ตัวอักษรตัวใหญ่ทั้งหมด) และตามด้วยเครื่องหมายโคลอน : เว้นวรรค และรายละเอียด เช่น BREAKING CHANGE: environment variables now take precedence over config files
  13. ถ้าการเปลี่ยนแปลงที่มีผลกระทบเป็นส่วนหนึ่งของชนิดหรือขอบเขตในตอนต้น จะต้องใส่ ! ต่อท้ายทันที ก่อนเครื่องหมายโคลอน : และเมื่อใช้ ! อาจจะไม่ต้องใส่ BREAKING CHANGE: ในข้อความลงท้ายก็ได้ และรายละเอียดของ commit จะถูกใช้เพื่ออธิบายถึงสิ่งที่กระทบนั้น ๆ
  14. ชนิดของ commit อื่น ๆ นอกเหนือจาก feat และ fix อาจจะถูกใช้ในข้อความ commit ได้ เช่น docs: updated ref docs.
  15. ส่วนประกอบอื่น ๆ ใน Conventional Commits จะไม่ไม่ให้ความสำคัญกับตัวอักษรใหญ่หรือเล็ก ยกเว้นแต่คำว่า BREAKING CHANGE ซึ่งจะต้องเป็นตัวใหญ่เสมอ
  16. BREAKING-CHANGE จะมีความหมายเดียวกันกับ BREAKING CHANGE เมื่อถูกใช้เป็นกลุ่มคำในข้อความลงท้าย

ทำไมถึงควรใช้ Conventional Commits

คำถามที่พบบ่อย

ฉันจะจัดการกับข้อความ commit ในช่วงเริ่มต้นของการพัฒนาได้อย่างไร?

เราแนะนำให้คุณทำเหมือนกับคุณได้รีลีสผลิตภัณฑ์ของคุณแล้ว โดยปกติ บางคน ถึงแม้จะหมายถึงเพื่อนร่วมทีมพัฒนาซอฟต์แวร์ของคุณก็ตาม มาใช้ซอฟต์แวร์ของคุณ เขาก็อยากที่จะรู้ว่าส่วนไหนถูกแก้ไขแล้ว ส่วนไหนที่มีการเปลี่ยนแปลง และรายละเอียดส่วนอื่น ๆ

ชนิดของ commit ควรจะเป็นตัวใหญ่ หรือตัวเล็ก?

จะเป็นตัวใหญ่หรือตัวเล็กก็ได้ แต่มันจะเยี่ยมมากถ้ามันสอดคล้องกันทั้งหมด

ฉันควรจะทำอย่างไรถ้า commit นั้นเป็นไปได้มากกว่าหนึ่งชนิด​?

กลับไปแก้ไขและพยายามแบ่งออกให้เป็นหลาย commit เท่าที่จะเป็นไปได้ ประโยชน์ส่วนหนึ่งของ Conventional Commits คือการที่มันช่วยให้เราสามารถจัดการกับ commit และ PR ได้ดีกว่าเดิม

นี่มันจะไม่ทำให้การพัฒนาและรอบการทำงานช้าลงกว่าเดิมหรือ?

มันทำให้การทำงานแบบไม่มีการจัดการช้าลง แต่มันจะช่วยให้คุณทำงานได้เร็วขึ้นในระยะยาวกับหลาย ๆ โปรเจกต์ที่มีส่วนร่วมจากหลาย ๆ คน

Conventional Commits จะทำให้นักพัฒนาจำกัดจำนวนของชนิดที่พวกเขาทำเพราะจะทำให้พวกเขาติดอยู่กับชนิดที่มีอยู่หรือไม่?

Conventional Commits สนับสนุนเราให้สามารถสร้างชนิดได้มากกว่านั้น เช่น fixes นอกจากนั้นแล้ว ความยืดหยุ่นของ Conventional Commits ยังอนุญาตให้ทีมของคุณสร้างชนิดของพวกเขาขึ้นมาเอง และปรับเปลี่ยนมันได้ตลอดเวลาอีกด้วย

นี่เกี่ยวข้องกับ SemVer อย่างไร?

commit ที่มีชนิดเป็น fix จะถูกมองเป็น PATCH ใน release ส่วน commit ชนิดที่เป็น feat จะถูกมองเป็น MINOR release และ commits ที่เป็น BREAKING CHANGE ไม่ว่าจะเป็นชนิดใดก็ตาม จะถูกมองเป็น MAJOR release

ฉันควรจะใส่เวอร์ชั่นของส่วนขยายให้กับข้อกำหนดของ Conventional Commits อย่างไร เช่น @jameswomack/conventional-commit-spec?

เราแนะนำให้ใช้ SemVer ในการที่จะรีลีสส่วนขยายของคุณให้กับข้อกำหนดนี้ (และสนับสนุนให้คุณสร้างส่วนขยายนี้ด้วย!)

ฉันจะทำอย่างไรถ้าฉันใส่ชนิดของ commit ผิดโดยไม่ได้ตั้งใจ?

เมื่อคุณใช้ชนิดที่เป็นส่วนหนึ่งในข้อตกลง แต่ผิดชนิด เช่น ใช้ fix แทนที่จะเป็น feat

ก่อนที่จะรวม หรือรีลีสความผิดพลาดนั้น เราแนะนำให้ใช้ git rebase -i เพื่อแก้ไขข้อความใน commit ย้อนหลัง แต่ถ้าทำหลังจากที่รีลีสไปแล้ว การแก้ไขจะแตกต่างกันไปขึ้นอยู่กับเครื่องมือและวิธีการที่คุณใช้

เมื่อคุณใช้ชนิดที่ ไม่ได้ เป็นส่วนหนึ่งในข้อตกลง เช่น ใช้ feet แทนที่จะเป็น feat

ในสถานการณ์ที่แย่ที่สุด มันไม่ใช่วันสิ้นโลกถ้าคุณจะใส่ commit ที่ไม่สอดคล้องกับข้อกำหนดของ Conventional Commits มันมีความหมายง่าย ๆ คือ commit นั้นจะถูกมองข้ามไปถ้าใช้เครื่องมือที่อ้างอิงตามข้อกำหนดนี้เท่านั้นเอง

คนที่มีส่วนร่วมในโปรเจกต์ทั้งหมดจะต้องใช้ข้อกำหนดของ Conventional Commits นี้หรือไม่?

ไม่! ถ้าคุณใช้ลำดับการทำงานแบบที่ต้องยุบรวม commit บน Git คนที่เป็นผู้ดูแลจะสามารถจัดการกับข้อความ commit ในขณะที่รวม commit เข้ามาโดยที่ไม่เป็นภาระกับผู้ที่ไม่ค่อยได้ commit ลำดับการทำงานโดยทั่วไปสำหรับแบบนี้คือต้องทำให้ระบบ git ของคุณทำการยุบรวม commit ที่มาจาก pull request โดยอัตโนมัติ และแนะนำฟอร์มให้กับผู้ดูแลเพื่อใส่ข้อความ commit ที่เหมาะสมในการรวม commit เข้ามา

Conventional Commits จะจัดการกับการย้อนกลับ commit ได้อย่างไร?

การย้อนกลับโค้ดอาจจะซับซ้อนได้: คุณกำลังย้อนกลับหลาย ๆ commit หรือไม่? ถ้าคุณกำลังย้อนกลับฟีเจอร์ ในการรีลีสซอฟต์แวร์ครั้งถัดไปจะกลายเป็นเพียงการ patch หรือไม่?

Conventional Commits ไม่ได้บอกถึงวิธีการอย่างชัดเจนว่าจะต้องทำอย่างไรเมื่อเกิดการย้อนกลับ แต่เราปล่อยให้เป็นการจัดการของนักพัฒนาเครื่องมือเป็นผู้ใช้ความยืดหยุ่นของ ชนิด และ ข้อความลงท้าย ในการพัฒนาตรรกะในการจัดการการย้อนกลับ

คำแนะนำหนึ่งคือการใช้ชนิด revert และข้อความลงท้ายที่มีการอ้างถึงหมายเลข commit ที่จะถูกย้อนกลับ

revert: let us never again speak of the noodle incident

Refs: 676104e, a215868