Skip to main content

เขียน Git commits อย่างไรไม่ให้มั่ว... มาดูวิธีที่ถูกต้อง (Best Practices)

· 5 min read
Kongvut Sangkla

Intro

สวัสดีครับ บทความนี้จะเขียนอธิบายแนวทางปฏิบัติที่ดีที่สุดสำหรับการเขียน Git commits โดยจะอ้างอิงกับ https://www.conventionalcommits.org/en/v1.0.0/ เป็นหลัก

เคยไหมพบปัญหาสมาชิกในทีมพัฒนาเขียน Git commits มั่ว 😄 ไม่ว่าจะเป็นรูปแบบโครงสร้างไม่ดี หรือใส่รายละเอียดไม่ดี ทำให้การเรียกดูประวัติย้อนหลังเข้าใจยาก ลองมาดูตาม Convention นี้ซึ่งมีรายละเอียดที่เข้าใจง่ายที่ช่วยให้การสื่อสารกับทีมมีความเข้าใจง่ายขึ้นได้

Imgur

ข้อดีของการทำตาม git commit conventions

  • เพื่อสร้าง CHANGELOGs ให้อัตโนมัติ
  • ความง่ายในการดูประวัติของประเภท Commits และใช้สื่อสารถึงการเปลี่ยนแปลงต่าง ๆ กับเพื่อนร่วมทีม
  • เพื่อใช้ Commit type เป็นทริกเกอร์เพื่อบอกในกระบวนการ Deploy หรือ Publish

โครงสร้างของ Commit messages

<type>[optional scope]: <subject>

[optional body]

[optional footer(s)]

ประเภทของ type (จำเป็น)

An emoji guide for your commit messages https://gitmoji.dev

  • 👷 build: เมื่อปรับปรุง build config หรือ development tools (เช่น: เกี่ยวข้องกับ npm หรือการเพิ่ม dependencies)
  • ✨ feat: เมื่อเพิ่มคุณสมบัติใหม่ (feature)
  • 🔧 chore: เมื่อมีการเปลี่ยนแปลงค่า Ignore หรือค่า Settings ที่ไม่กระทบกับ Code โดยตรง (เช่นที่: .gitignore หรือ .prettierrc)
  • 🐛 fix: เมื่อแก้ไขข้อผิดพลาด (bug fix)
  • 📝 docs: เมื่อเปลี่ยนแปลงที่เกี่ยวข้องกับเอกสาร
  • ♻️ refactor: เมื่อมีการ Refactor code (เช่น การเปลี่ยนชื่อตัวแปร/ ชื่อฟังก์ชัน)
  • ⚡️ perf: เมื่อทำการเพิ่มประสิทธิภาพ (performance)
  • 💄 style: เมื่อเกี่ยวข้องกับ styling เช่น การจัดรูปแบบใหม่
  • ✅ test: เมื่อเกี่ยวข้องกับการเขียน Testing เพิ่ม หรือ Refactoring tests โดยที่ไม่เกี่ยวข้องกับ Production code

เกี่ยวกับ scope (optional)

เป็นส่วนที่เป็น Optional (คือไม่จำเป็นต้องระบุก็ได้) โดย Scope คือขอบเขต หรือ Section บางทีอาจจะหมายถึงโมดูล โดยต้องเป็นคำนาม

note

<scope> สามารถว่างได้ เช่น บางทีการเปลี่ยนแปลงอะไรที่เป็น Global หรืออะไรที่เป็น Single component ที่ยากในการกำหนด

ตัวอย่าง
- init
- runner
- watcher
- config
- web-server
- proxy

เกี่ยวกับ subject (จำเป็น)

  • เป็นส่วนที่ควรระบุ และควรเขียนเป็นภาษาอังกฤษ โดยใช้ Present tense (ตย. ใช้ "add" แทน "added" ก็ไม่เช่นกัน "adds")
  • ไม่จำเป็นต้องใช้ dot(.) เมื่อจบประโยค
  • ไม่จำเป็นต้องใช้ตัวอักษรพิมพ์ใหญ่สำหรับขึ้นต้นประโยค

เกี่ยวกับ body (optional)

เป็นส่วนที่เป็น Optional โดย Body คือส่วนเนื้อหา ที่อธิบายถึงแรงจูงใจ (Motivation) เบื้องหลังการเปลี่ยนแปลง หรือเพียงแค่อธิบายรายละเอียดเพิ่มเติมเล็กน้อย

เป็นส่วนที่เป็น Optional โดย Footer จะกล่าวถึงผลที่เกิดจากการเปลี่ยนแปลง เช่น การประกาศการเปลี่ยนแปลงที่จะเกิดขึ้น (breaking) การเชื่อมโยงประเด็นที่ปิด (issues) การกล่าวถึงผู้ร่วม (contributors) และอื่น ๆ โดยมีรายละเอียดดังนี้

Referencing issues

เพิ่ม Keyword คำว่า Closes (บางคนใช้ Refs ก็แล้วแต่จะตกลงกันในทีม) ที่ Footer จากนั้นตามด้วยรหัส Issues ที่ปิดแล้ว เช่น

Close #123

ถ้ามีหลาย Issues ก็ประมาณนี้

Closes #123, #456, #789

Breaking changes

สำหรับทุก Breaking changes สามารถเขียนไว้ที่ Footer และอธิบายและให้เหตุผลของการเปลี่ยนแปลง

note

ทุก Commit ที่มี Breaking change จะทริกเกอร์เมื่อมีการทำ MAJOR release และจะแสดงบน Changelogs ตามแต่ละ Commit type

ตัวอย่าง

กรณี type + scope + body + footer
fix(core): remove deprecated and defunct wtf* apis (#33949)

These apis have been deprecated in v8, so they should stick around till v10, but since they are defunct we are removing them early so that they don't take up payload size.

PR Close #33949

ประเภท build

ประเภท build
build(npm): update fsevents to 1.0.14 (#11686)
build(tsc-wrapped): use tsickleCompilerHost for initial file Load
build(docs-infra): enable ServiceWorker in cli config (#25997)
build(common): don't generate .d.ts & .metadata.json files for 118n locales
build(aio): run the upload server as a non-previleged user
build(gulp): use gulp-watch instead of gulp.watch for watching files
build(docs-infra): upgrade webpack-cli to 3.1.2 (#26202)

ประเภท docs

ประเภท docs
docs(changelog): update change log to rc.5
docs(zone.js): update DEVELOPER.md for changelog instruction (#32016)
docs(core): fix API docs for ContentChild and ViewChildren (#13656)
docs(MockConnection) add mockError usage example (#8888)
docs(router): clarify scroll position wording (#25077)
docs(readme): remove incorrect download count badge
docs(aio): fix typo (#20193)
docs(router): improve docs for Instruction and related classes

ประเภท feat

ประเภท feat
feat(zone.js): support Promise.allSettled (#31849)
feat(ivy): resolve references to vars in .d.ts files (#25775)
feat(aio): implement `GithubTeams`
feat(facade): add bool type
featCforms): add NgForm method that resets submit state (#10715)
feat(parser): improve error handling
feat(bazel): add additional parameters to `ts_api_guardian_test` def (#25694)

ประเภท fix

ประเภท fix
fix(ivy): correctly resolve shorthand property declarations (#28936)
fix(bazel): incorrectly always uses ngc-wrapped from "npm" workspace (#28137)
fix(di): injecting null causes a cyclic dependency
fix(ivy): not throwing error for unknown properties on container nodes (#29691)
fix(router): make router provides work with cli and offline compilation
fix(ivy): missing schematics field in localize package (#33025)
fix(forms): avoid producing an error with hostBindingTypeCheck

ประเภท perf

ประเภท perf
perf(ivy): don't store public input names in two places (#33798)
perf(ivy): split hooks processing into init and check phases (#32131)
perf(ivy): remove check for function type in renderStringify (#30838)
perf(ivy): removes generation of comments (#21638)
perf(change detection): minimized amount of code in protective try-catch
perf(docs-infra): avoid unnecessary I/0 operation in `ng-packages-installer` (#28510)
perf(dom): only send values for existing properties to js interior
perf(core): make `PlatformLocation` tree-shakable (#32154)

ประเภท refactor

ประเภท refactor
refactor(compiler): rename decorator directives into directive
refactor(ivy): remove need for LContainer.template (#24335)
refactor(DirectiveResolver): cleanup
refactor(forms): remove facade (#12558)
refactor(core): remove deprecated `bootstrap` (#10831)
refactor(ShadowCss): cleanup
refactor(core): simplify & cleanup reflection

ประเภท style

ประเภท style
style(aio): add space between `.home` and `.hamburger` (#23624)
style(bazel): fix 2 unformatted `.bzl` files
style(core): fix max line Length to pass Linting (#20441)
style(nodeTree): fix formatting
style(compiler): fix Lint issues (#23480)
style(aio): fix indentation on location service spec
style(changelog): improving readability (#18949) PR Close #18949
style(playground): use single quotes consistently

ประเภท test

ประเภท test
test(common): add PercentPipe round and trim tests (#27365)
test(compiler-cli): add test for missingTranslation parameter
test(upgrade): re-enable tests that have been fixed (#27305)
test(ivy): update root causes for @angular/core TestBed failures (#27650)
test(docs-infra): fix tests (#26202)
test(ivy): add attribute interpolation test (#30503)
test(ivy): add canonical compiler spec for class/style (#22719)
test(ivy): mark jit_summaries_integration_spec as obsolete in Ivy (#28027)
test(ivy): split out provider tests (#27069)

ตัวอย่างอื่น ๆ เพิ่มเติม

เครื่องมืออื่น ๆ

ใส่ Emojis

เพิ่ม Emojis ใน Commit messages ได้ซึ่งอาจจะช่วยให้อ่านได้ง่ายขึ้น สวย และง่ายในการค้นหาประวัติ Commits 🚀

เช่น:

CLI Tool

https://github.com/commitizen/cz-cli คือเครื่องมือที่เป็นแบบบังคับใช้รูปแบบ Commit messages ผ่าน Command line (CLI)

img

Linter

https://github.com/conventional-changelog/commitlint คือเครื่องมือ Linter ที่ช่วยตรวจสอบเพื่อเป็นการหลักประกันว่า Commit messages นั้นจะเป็นไปตาม Conventions ที่ถูกต้อง

img

VS Code Extension

มี VS Code extension ด้วยถ้าสนใจก็ตามนี้เลย https://github.com/nitayneeman/vscode-git-semantic-commit

img

Jetbrains IDE

ใครที่ใช้ IDE ของ Jetbrains เช่น IntelliJ IDEA WebStorm หรือ PHPStorm สามารถใช้ Plugin นี้ Git Commit Message Helper ช่วยได้

https://plugins.jetbrains.com/plugin/13477-git-commit-message-helper

การปรับแต่งเพิ่มเติม

ถ้าต้องการเพิ่ม Type อื่น ๆ:

Configuration path: File -> Settings -> Other Settings -> GitCommitMessageHelper -> type

สรุป

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

แต่ก็ยังมีประเด็นที่น่าสนใจอื่น ๆ ของ Spec กับ FAQ ของคำถามที่ว่าเมื่อไหร่ควรใช้แบบไหน อย่างไร ที่น่าสนใจแนะนำให้อ่านเพื่อเพิ่มความเข้าใจที่ https://www.conventionalcommits.org/en/v1.0.0/#summary

References

Loading...