Git log açıp son 100 commit’e bakın. Ne kadarını hatırlıyorsunuz? “fix bug”, “update”, “wip”, “stuff” gibi commit’ler tarih kaybı. İyi commit mesajları kod tabanının hafızası.
19 yıllık developer olarak çeşitli takımlarda bu disciplin’i kurmaya çalıştım. Bu yazıda pratik yaklaşımı paylaşacağım.
Commit mesajı neden önemli?
1. Future debugging. 6 ay sonra “bu satır neden böyle” sorusunun cevabı commit mesajında.
2. Code review context. Reviewer sadece diff’i değil, commit mesajını da okuyor. “Bu değişikliği neden yaptın” cevabı.
3. Release notes generation. Commit’lerden release notes auto-generate edilebiliyor.
4. Bisect debugging. git bisect ile bug’ın ne zaman girdiğini bulurken commit mesajları yol gösteriyor.
5. Yeni developer onboarding. Git log kod tabanının evolution hikayesi.
Kötü commit mesajları bu 5 fayda’yı kaybediyor.
Conventional commits format
En yaygın standart: Conventional Commits.
<type>(<scope>): <subject>
<body>
<footer>Types:
– feat: yeni feature
– fix: bug fix
– docs: documentation change
– style: code style (whitespace, formatting, no logic change)
– refactor: code restructure, no behavior change
– perf: performance improvement
– test: adding/updating tests
– chore: maintenance task (dependency update, config)
Example:
feat(checkout): add Apple Pay option
Implement Apple Pay as alternative payment method alongside
credit card. Uses Stripe's PKPaymentRequest API.
Closes #234Bu format machine-parseable. Changelog generation, semantic versioning automation.
Subject line rules
First line (subject) en kritik. Rules:
- Max 72 karakter. Git tool’ları bunu truncate ediyor.
- Imperative mood. “add feature” değil “added feature”.
- No period at end.
- Capitalize first letter after type. Actually lowercase is preferred in conventional commits.
- Concise but descriptive.
Good subjects:
feat(auth): add two-factor authentication
fix(api): prevent duplicate order creation on network retry
refactor(db): extract query builder into separate class
perf(list): memoize expensive filter computationBad subjects:
update (ne update?)
fix bug (hangi bug?)
wip (kimin umrunda)
misc changes (vague)Body: why, not what
Body’de “ne değiştirdim” yazmak gereksiz. Diff zaten gösteriyor. Body “niye değiştirdim” için.
Bad body:
Changed line 45 in UserService.swift.
Updated the validation logic.
Added a new parameter.Good body:
The existing validation allowed empty emails to pass through,
causing NULL values in the database. This led to the bug #412
where notification emails failed silently.
Now requires @ symbol and non-empty domain.Body “why” + “impact” ile reviewer context kazanıyor.
Atomic commits
Bir commit tek bir logical change. Mixed commits disiplinsiz.
Bad (mixed):
feat: add user profile, fix login bug, update depsÜç farklı thing tek commit’te. Revert zor (sadece login fix’i revert edilemiyor). Review zor.
Good (atomic):
commit 1: feat(profile): add user profile page
commit 2: fix(auth): prevent login loop after token expiry
commit 3: chore(deps): update lodash to 4.17.21Üç ayrı commit. Her biri self-contained, revertable, reviewable.
Branch naming
Commit disciplin branch naming ile birlikte:
feature/checkout-apple-pay
bugfix/email-validation-nil-check
hotfix/payment-timeout
chore/update-firebase-sdkBranch tipi prefix, kebab-case descriptive name. GitHub/GitLab issue integration için issue number ekle:
feature/234-apple-pay-checkoutAmend ve squash
git commit --amend son commit’i düzeltmek için. Mesaj typo, forgotten file.
git rebase -i HEAD~5 multiple commits’i interactive olarak düzenle:
– reword: commit mesajı değiştir
– squash: multiple commits’i birleştir
– fixup: squash ama mesajı atla
– drop: commit’i sil
Squash kullanım senaryosu: PR review sırasında 5 commit’le “fix typo”, “fix another typo”, “actually fix” gibi commitler birikti. Merge öncesi squash:
git rebase -i main
# "squash" marker ile birleştirResult: tek clean commit PR merge’de.
Git hook’larıyla enforce
Team disciplin için git hook’lar:
commit-msg hook: Commit mesajı format’ı check ediyor.
#!/bin/sh
# .git/hooks/commit-msg
commit_regex='^(feat|fix|docs|style|refactor|perf|test|chore)(\([a-z-]+\))?: .{1,72}'
if ! grep -qE "$commit_regex" "$1"; then
echo "Commit message format invalid."
echo "Format: type(scope): subject"
exit 1
fiHusky (Node.js projects) veya pre-commit (Python) gibi tool’lar hook management’ı kolaylaştırıyor.
Team onboarding
Yeni developer’a commit discipline açıklamak:
- README’de commit convention. Link: Conventional Commits spec.
- PR template. Body’de “How should reviewer judge this?” sorusu.
- Pair commit writing. İlk hafta senior review commit messages.
- Reject PR with bad commits. “Please squash into meaningful commits” feedback.
3-4 hafta sonra pattern internalize oluyor.
Multi-commit PR vs single-commit
PR approach:
Option A: One commit per PR. PR merge’de squash. Final history clean.
Option B: Multi-commit PR. Her commit mantıklı unit. Merge commit veya rebase merge.
Ben Option B tercih ediyorum büyük PR’larda. 5-10 commit logical breakdown easier to review. Small PR’larda (100 satır altı) Option A OK.
Tools: git log visualization
Git log’u okumanın yolları:
git log --oneline
git log --graph --oneline --all
git log --pretty=format:'%h %s (%an)' --abbrev-commitVisual tool’lar: GitLens (VS Code), Fork, Tower. Commit history’yi visualize.
Sonuç
Commit discipline uzun vadede team productivity’sinin core’u. İlk başta “fazla disciplin” gibi görünüyor, 6 ay sonra code archaeology yaparken değeri anlaşılıyor.
Conventional Commits + atomic commits + meaningful subject/body. Hook’larla enforce, PR review’da enforce, onboarding’de öğret. 1 ay disciplin’den sonra herkes için natural hale geliyor.