Git Hooks
Giriş — Otomatik Kalite Kontrol
Bir fabrikayı düşün. Üretim bandında her ürün ilerlerken, belirli kontrol noktalarından geçer: boyut doğru mu? Renk tutarlı mı? Kusur var mı? Bu kontroller otomatik — bir sensör tetiklenir, ürün standartlara uyuyorsa geçer, uymuyorsa durur.
Git hooks, Git işlemlerinin belirli noktalarında otomatik çalışan scriptlerdir. Commit öncesinde kodun lint'ten geçmesini, commit mesajının belirli bir formata uymasını, push öncesinde testlerin çalışmasını sağlayabilirsin. Manuel kontrol etmen gerekmez — Git senin yerine kontrol eder.
Bu derste Git'in hook mekanizmasını, yaygın hook türlerini, Husky ile modern hook yönetimini ve lint-staged ile verimli lint akışını öğreneceksin.
Hook Nedir?
Analoji — Kapı Sensörleri
Bir binanın giriş kapısında sensörler var:
Giriş öncesi: Kartını okut, kimliğin doğrulanır → geçebilirsin
Giriş sonrası: Sistem kaydı tutar, ışıklar yanar
Çıkış öncesi: Eşya kontrolü
Çıkış sonrası: Kapı otomatik kilitlenir
Git hooks de aynı mantıkta çalışır. Her Git işlemi (commit, push, merge...) öncesinde ve sonrasında tetiklenen "sensörler":
┌──────────────────────────────────────────────────────────┐
│ GIT HOOK TETİKLEME │
├──────────────────────────────────────────────────────────┤
│ │
│ git commit: │
│ pre-commit ──► commit-msg ──► post-commit │
│ ↑ ↑ ↑ │
│ Lint/test Mesaj kontrol Bildirim │
│ │
│ git push: │
│ pre-push ──► (server tarafı) ──► post-receive │
│ ↑ ↑ │
│ Test çalıştır Deploy tetikle │
│ │
│ git merge: │
│ pre-merge-commit ──► post-merge │
│ ↑ │
│ npm install │
│ │
└──────────────────────────────────────────────────────────┘Hook'lar Nerede?
ls .git/hooks/
# applypatch-msg.sample pre-commit.sample
# commit-msg.sample pre-merge-commit.sample
# fsmonitor-watchman.sample pre-push.sample
# post-update.sample pre-rebase.sample
# pre-applypatch.sample prepare-commit-msg.sample
# pre-auto-gc.sample push-to-checkout.sample
# .sample uzantılı dosyalar → aktif DEĞİL
# .sample'ı kaldırınca aktif olurClient-Side Hooks (İstemci Tarafı)
pre-commit — Commit Öncesi Kontrol
En çok kullanılan hook. Commit yapılmadan hemen önce çalışır. Hook 0 dışı bir değer döndürürse commit iptal edilir.
# .git/hooks/pre-commit dosyası oluştur
cat > .git/hooks/pre-commit << 'HOOK'
#!/bin/sh
# Pre-commit hook: Lint ve format kontrolü
echo "🔍 Pre-commit kontrolleri çalışıyor..."
# 1. ESLint kontrolü
echo "📋 Lint kontrolü..."
npx eslint --quiet .
if [ $? -ne 0 ]; then
echo "❌ Lint hataları var! Düzeltip tekrar commit edin."
exit 1
fi
# 2. Prettier format kontrolü
echo "🎨 Format kontrolü..."
npx prettier --check .
if [ $? -ne 0 ]; then
echo "❌ Format hataları var! 'npm run format' çalıştırın."
exit 1
fi
# 3. Hassas bilgi kontrolü
echo "🔒 Hassas bilgi kontrolü..."
if git diff --cached --name-only | xargs grep -l "API_KEY\|SECRET\|PASSWORD" 2>/dev/null; then
echo "❌ Hassas bilgi tespit edildi! Commit iptal."
exit 1
fi
echo "✅ Tüm kontroller geçti!"
exit 0
HOOK
chmod +x .git/hooks/pre-commit# Test et:
git add .
git commit -m "Test commit"
# 🔍 Pre-commit kontrolleri çalışıyor...
# 📋 Lint kontrolü...
# ❌ Lint hataları var! Düzeltip tekrar commit edin.
# Hook'u atlamak (acil durumlarda):
git commit --no-verify -m "Emergency fix"
# veya
git commit -n -m "Emergency fix"commit-msg — Commit Mesajı Kontrolü
Commit mesajının belirli bir formata uymasını zorunlu kılar:
cat > .git/hooks/commit-msg << 'HOOK'
#!/bin/sh
# Commit mesajı format kontrolü: Conventional Commits
commit_msg_file=$1
commit_msg=$(cat "$commit_msg_file")
# Conventional Commits pattern:
# type(scope): description
# type: feat, fix, docs, style, refactor, test, chore, ci, perf, build
pattern="^(feat|fix|docs|style|refactor|test|chore|ci|perf|build)(\(.+\))?: .{1,}"
if ! echo "$commit_msg" | grep -qE "$pattern"; then
echo "❌ Commit mesajı Conventional Commits formatına uymuyor!"
echo ""
echo "Doğru format: <type>(<scope>): <description>"
echo ""
echo "Örnekler:"
echo " feat: Add user authentication"
echo " fix(auth): Resolve login redirect issue"
echo " docs: Update API documentation"
echo " refactor(core): Simplify error handling"
echo ""
echo "Geçerli tipler: feat, fix, docs, style, refactor, test, chore, ci, perf, build"
exit 1
fi
# Mesaj uzunluğu kontrolü
first_line=$(echo "$commit_msg" | head -1)
if [ ${#first_line} -gt 72 ]; then
echo "❌ Commit mesajının ilk satırı 72 karakterden uzun!"
echo " Mevcut: ${#first_line} karakter"
exit 1
fi
echo "✅ Commit mesajı formatı doğru!"
exit 0
HOOK
chmod +x .git/hooks/commit-msgprepare-commit-msg — Mesaj Hazırlama
Commit mesajı editörde açılmadan önce çalışır. Otomatik mesaj ekleme için:
cat > .git/hooks/prepare-commit-msg << 'HOOK'
#!/bin/sh
# Branch adından issue numarasını çıkar ve commit mesajına ekle
commit_msg_file=$1
branch_name=$(git symbolic-ref --short HEAD)
# Branch adı "feature/PROJ-123-login" formatındaysa
issue_id=$(echo "$branch_name" | grep -oE '[A-Z]+-[0-9]+')
if [ -n "$issue_id" ]; then
# Mesajın sonuna issue referansı ekle
echo "" >> "$commit_msg_file"
echo "Ref: $issue_id" >> "$commit_msg_file"
fi
HOOK
chmod +x .git/hooks/prepare-commit-msgpre-push — Push Öncesi Kontrol
cat > .git/hooks/pre-push << 'HOOK'
#!/bin/sh
# Push öncesi test çalıştır
echo "🧪 Push öncesi testler çalışıyor..."
npm test
if [ $? -ne 0 ]; then
echo "❌ Testler başarısız! Push iptal."
exit 1
fi
echo "✅ Testler geçti, push devam ediyor..."
exit 0
HOOK
chmod +x .git/hooks/pre-pushpost-merge — Merge Sonrası
cat > .git/hooks/post-merge << 'HOOK'
#!/bin/sh
# Merge sonrası bağımlılıkları güncelle
# package.json değişti mi?
changed_files=$(git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD)
if echo "$changed_files" | grep -q "package.json"; then
echo "📦 package.json değişti, npm install çalıştırılıyor..."
npm install
fi
if echo "$changed_files" | grep -q "requirements.txt"; then
echo "🐍 requirements.txt değişti, pip install çalıştırılıyor..."
pip install -r requirements.txt
fi
HOOK
chmod +x .git/hooks/post-mergepost-checkout — Branch Değiştirdikten Sonra
cat > .git/hooks/post-checkout << 'HOOK'
#!/bin/sh
# Branch değiştirince .env dosyasını kontrol et
prev_head=$1
new_head=$2
branch_checkout=$3
# Sadece branch değişikliğinde çalış (dosya checkout değil)
if [ "$branch_checkout" = "1" ]; then
if [ ! -f .env ]; then
echo "⚠️ .env dosyası yok! .env.example'dan kopyala:"
echo " cp .env.example .env"
fi
fi
HOOK
chmod +x .git/hooks/post-checkoutServer-Side Hooks (Sunucu Tarafı)
Server-side hook'lar remote repository'de çalışır. GitHub/GitLab gibi platformlarda bunlar genellikle platform ayarlarıyla yönetilir.
┌─────────────────┬────────────────────────────────────────┐
│ Hook │ Kullanım │
├─────────────────┼────────────────────────────────────────┤
│ pre-receive │ Push kabul edilmeden önce çalışır │
│ │ Politika kontrolü, format kontrolü │
│ │ Reddederse push başarısız olur │
├─────────────────┼────────────────────────────────────────┤
│ update │ Her branch güncellemesi için ayrı çalışır│
│ │ Branch bazlı izin kontrolü │
├─────────────────┼────────────────────────────────────────┤
│ post-receive │ Push kabul edildikten sonra çalışır │
│ │ CI/CD tetikleme, bildirim, deploy │
│ │ Reddetme şansı yok (bilgi amaçlı) │
└─────────────────┴────────────────────────────────────────┘💡 İpucu: GitHub'da server-side hook'ları doğrudan yazamazsın. Bunun yerine GitHub Actions, branch protection rules ve webhooks kullanırsın. GitLab ise self-hosted sürümde server hook'larını destekler.
Hook'ların Sorunu — Paylaşım
.git/hooks/ dizini Git tarafından track edilmez. Yani hook'lar repo ile paylaşılmaz. Her geliştirici kendi hook'larını kurmalıdır.
❌ Sorun:
- Ahmet hook'u kurdu, her commit'te lint çalışıyor ✅
- Ayşe hook'u kurmadı, lint hatalarıyla commit ediyor ❌
- Ali hook'un varlığından habersiz
Bu, ekip genelinde tutarsızlığa yol açar.Çözüm Yolları
1. core.hooksPath ile paylaşılan dizin kullan
2. Husky (Node.js projeler için) ← En yaygın
3. pre-commit (Python projeler için)
4. lefthook (Go tabanlı, dil bağımsız)core.hooksPath
# Hook'ları repo'nun içinde bir dizine koy
mkdir -p .githooks
cp .git/hooks/pre-commit .githooks/pre-commit
# Tüm ekip için hook dizinini ayarla
git config core.hooksPath .githooks
# .githooks dizini repo ile paylaşılır!
git add .githooks/
git commit -m "Add shared Git hooks"Husky — Modern Hook Yönetimi
Husky, Node.js projelerinde Git hook'larını yönetmenin en popüler yoludur. npm install yaptığında hook'lar otomatik kurulur — ekipteki herkes aynı hook'lara sahip olur.
Husky Kurulumu
# 1. Husky'yi kur
npm install --save-dev husky
# 2. Husky'yi başlat
npx husky init
# Bu komut:
# - .husky/ dizinini oluşturur
# - package.json'a "prepare" scripti ekler
# - Örnek pre-commit hook'u oluştururProje yapısı:
my-project/
├── .husky/
│ ├── _/ ← Husky internal
│ │ ├── .gitignore
│ │ └── husky.sh
│ └── pre-commit ← Hook dosyası (düzenle!)
├── package.json
└── ...Husky Hook'ları Tanımlama
# pre-commit hook'u
cat > .husky/pre-commit << 'HOOK'
npm run lint
npm test
HOOK
# commit-msg hook'u
cat > .husky/commit-msg << 'HOOK'
npx --no -- commitlint --edit $1
HOOK
# pre-push hook'u
cat > .husky/pre-push << 'HOOK'
npm run build
npm run test:e2e
HOOKpackage.json Entegrasyonu
{
"name": "my-project",
"scripts": {
"prepare": "husky",
"lint": "eslint .",
"format": "prettier --write .",
"format:check": "prettier --check .",
"test": "jest",
"build": "tsc"
},
"devDependencies": {
"husky": "^9.0.0",
"eslint": "^8.0.0",
"prettier": "^3.0.0",
"jest": "^29.0.0"
}
}Akış:
Yeni ekip üyesi:
1. git clone ...
2. npm install
→ "prepare" scripti çalışır
→ husky hook'ları otomatik kurulur ✅
3. git commit ...
→ pre-commit hook çalışır
→ lint + test otomatik çalışırlint-staged — Sadece Değişen Dosyaları Kontrol Et
Büyük bir projede eslint . komutu tüm dosyaları kontrol eder — bu dakikalar sürebilir. Ama sen sadece 2 dosya değiştirdin. Tüm projeyi lint etmek gereksiz.
lint-staged, sadece staged (git add edilmiş) dosyaları kontrol eder. Hızlı ve verimli.
Kurulum
npm install --save-dev lint-stagedYapılandırma
// package.json'a ekle:
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{css,scss}": [
"prettier --write"
],
"*.md": [
"prettier --write"
],
"*.json": [
"prettier --write"
]
}
}Veya ayrı bir .lintstagedrc.json dosyası:
{
"*.{js,ts}": ["eslint --fix", "prettier --write"],
"*.css": ["stylelint --fix", "prettier --write"],
"*.md": ["prettier --write"]
}Husky + lint-staged Birlikte
# .husky/pre-commit
npx lint-stagedAkış:
1. git add src/auth.js src/login.js
2. git commit -m "feat: Update auth"
3. pre-commit hook tetiklenir
4. lint-staged çalışır
5. SADECE src/auth.js ve src/login.js lint edilir
6. Hata varsa → commit iptal
7. Hata yoksa → commit başarılı ✅
Tüm projeyi lint etmek: 45 saniye ⏱️
Sadece değişen dosyaları: 2 saniye ⚡lint-staged Terminal Çıktısı
✔ Preparing lint-staged...
✔ Running tasks for staged files...
✔ Running tasks for *.{js,ts}
✔ eslint --fix
✔ prettier --write
✔ Running tasks for *.css
✔ prettier --write
✔ Applying modifications from tasks...
✔ Cleaning up temporary files...Commitlint — Commit Mesajı Standardı
Commitlint, commit mesajlarının belirli bir standarda uymasını zorunlu kılar:
# Kurulum
npm install --save-dev @commitlint/cli @commitlint/config-conventional
# Yapılandırma dosyası
cat > commitlint.config.js << 'EOF'
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [2, 'always', [
'feat', 'fix', 'docs', 'style', 'refactor',
'test', 'chore', 'ci', 'perf', 'build', 'revert'
]],
'subject-max-length': [2, 'always', 72],
'body-max-line-length': [2, 'always', 100],
}
};
EOF
# Husky hook'u
echo 'npx --no -- commitlint --edit $1' > .husky/commit-msg# Test:
git commit -m "fixed stuff"
# ❌ ✖ subject may not be empty [subject-empty]
# ✖ type may not be empty [type-empty]
git commit -m "fix: Resolve login redirect issue"
# ✅ Commit başarılı!Tam Kurulum: Profesyonel Hook Pipeline
# 1. Gerekli paketleri kur
npm install --save-dev \
husky \
lint-staged \
@commitlint/cli \
@commitlint/config-conventional \
eslint \
prettier
# 2. Husky'yi başlat
npx husky init
# 3. pre-commit hook (lint-staged)
echo 'npx lint-staged' > .husky/pre-commit
# 4. commit-msg hook (commitlint)
echo 'npx --no -- commitlint --edit $1' > .husky/commit-msg
# 5. package.json ayarları{
"scripts": {
"prepare": "husky",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"format": "prettier --write .",
"test": "jest"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{css,scss,md,json,yml,yaml}": [
"prettier --write"
]
}
}# 6. commitlint yapılandırması
cat > commitlint.config.js << 'EOF'
module.exports = {
extends: ['@commitlint/config-conventional']
};
EOF
# 7. Commit et
git add .
git commit -m "chore: Setup linting and commit hooks"Pipeline Diyagramı
Developer: git commit -m "feat: Add login"
│
▼
pre-commit hook
│
├── lint-staged
│ ├── eslint --fix (sadece değişen .js/.ts dosyaları)
│ ├── prettier --write (format düzelt)
│ └── Hata varsa? → ❌ Commit iptal
│
▼
commit-msg hook
│
├── commitlint
│ ├── Mesaj formatı doğru mu? (Conventional Commits)
│ └── Hata varsa? → ❌ Commit iptal
│
▼
✅ Commit başarılı!
│
▼
git push
│
▼
pre-push hook (opsiyonel)
│
├── npm test (birim testleri)
├── npm run build (build kontrolü)
└── Hata varsa? → ❌ Push iptalYaygın Hatalar
1. Hook'u Atlamak
# ❌ Acil diye her zaman --no-verify kullanmak
git commit --no-verify -m "quick fix"
# Bu, hook'ların amacını ortadan kaldırır!
# ✅ Gerçekten acil mi? O zaman:
# 1. --no-verify kullan
# 2. Sonra düzelt ve temiz commit yap
# 3. Ekibe bildir2. Yavaş Hook'lar
# ❌ pre-commit'te tüm projeyi lint + test etmek
# 5 dakika süren commit → kimse commit yapmak istemez!
# ✅ lint-staged ile sadece değişen dosyaları lint et
# ✅ Ağır testleri pre-push veya CI'a bırak
# ✅ pre-commit: hızlı kontroller (lint, format)
# pre-push: orta kontroller (unit test)
# CI: ağır kontroller (integration test, e2e)3. Hook'ları Commit Etmemek
# ❌ Hook'lar sadece .git/hooks/'ta — paylaşılmıyor
# Yeni ekip üyesi hook'suz çalışıyor
# ✅ Husky kullan — npm install ile otomatik kurulum
# veya core.hooksPath ile paylaşılan dizin kullanÖzet
Bu derste Git hook'larının tüm boyutlarını öğrendik:
Git hooks, Git işlemlerinin belirli noktalarında otomatik çalışan scriptlerdir — commit öncesi lint, mesaj formatı kontrolü, push öncesi test gibi kalite kontrolleri otomatize eder
Client-side hooks (pre-commit, commit-msg, pre-push) geliştirici makinesinde çalışır; server-side hooks (pre-receive, post-receive) remote'ta çalışır
Husky Node.js projelerinde hook yönetiminin standart aracıdır —
npm installile hook'lar otomatik kurulur, tüm ekip aynı hook'lara sahip olurlint-staged sadece staged dosyaları kontrol eder — tüm projeyi lint etmek yerine saniyeler içinde biter
Commitlint commit mesajlarının Conventional Commits standardına uymasını zorunlu kılar
pre-commit → commit-msg → pre-push pipeline'ı ile aşamalı kalite kontrol uygula: hızlı kontrolleri commit'te, ağır kontrolleri push'ta veya CI'da yap
Bir sonraki bölümde GitHub'ın CI/CD platformunu göreceğiz: GitHub Actions — push yaptığında otomatik test, build ve deploy!
AI Asistan
Sorularını yanıtlamaya hazır