GitHub Branch Koruma Kuralları ve Merge Stratejileri ile Güvenli Ekip Çalışması
Ekip olarak yazılım geliştirirken “kim ne zaman neyi değiştirdi” sorusunun cevabı Git ile kolayca bulunabiliyor. Ama asıl mesele şu: Yanlış bir commit main branch’e geçmeden önce nasıl durdurursun? İşte bu yazıda tam olarak bunu konuşacağız. GitHub’ın branch koruma kurallarını doğru yapılandırmak ve merge stratejilerini ekip ihtiyacına göre seçmek, production ortamını kurtarabilir.
Branch Koruma Kuralları Neden Önemli?
Diyelim ki 5 kişilik bir backend ekibiniz var. Herkes kendi feature branch’inde çalışıyor, iyi güzel. Ama bir gün yeni katılan birisi yanlışlıkla main branch’e direkt push yapıyor ve üstelik bir konfigürasyon dosyasını bozuyor. Production patlar, herkes uyanır, o gece kimse uyumaz.
Bu senaryo gerçek dünyada defalarca yaşandı. Branch koruma kuralları tam olarak bu tür kazaları önlemek için var. GitHub’da main veya production gibi kritik branch’leri belirli kurallarla koruyabiliyorsun. Bu kurallar şunları yapabilir:
- Direkt push’u engellemek
- PR review zorunlu kılmak
- CI/CD testlerinin geçmesini şart koşmak
- Force push ve branch silmeyi yasaklamak
- Linear commit history şart koşmak
Hadi bunları tek tek GitHub CLI ve API üzerinden nasıl yapılandıracağımıza bakalım.
GitHub CLI ile Branch Koruma Kurulumu
GitHub CLI (gh) komutu, arayüze girmeden terminal üzerinden her şeyi yapmanı sağlıyor. Önce gh’yi yükleyelim ve auth işlemini halledelim.
# Ubuntu/Debian
sudo apt install gh
# macOS
brew install gh
# Auth işlemi
gh auth login
# Mevcut repo'nun branch koruma kurallarını görüntüle
gh api repos/{owner}/{repo}/branches/main/protection
Şimdi bir branch koruma kuralı oluşturalım. Bu işlem için GitHub REST API’yi kullanacağız:
# main branch için kapsamlı koruma kuralı oluştur
gh api
--method PUT
-H "Accept: application/vnd.github+json"
/repos/myorg/myrepo/branches/main/protection
-f required_status_checks='{"strict":true,"contexts":["ci/tests","ci/lint"]}'
-f enforce_admins=true
-f required_pull_request_reviews='{"required_approving_review_count":2,"dismiss_stale_reviews":true,"require_code_owner_reviews":true}'
-f restrictions=null
-F allow_force_pushes=false
-F allow_deletions=false
Bu komutta birkaç kritik parametre var:
- required_status_checks: Hangi CI job’larının başarıyla geçmesi gerektiğini belirler
- strict: true olunca branch, merge edilmeden önce base branch ile güncel olmak zorunda
- enforce_admins: Admin kullanıcılar da bu kurallardan muaf değil, önemli!
- required_approving_review_count: Kaç kişinin approve etmesi gerektiği
- dismiss_stale_reviews: Yeni commit gelince eski approve’lar geçersiz sayılır
- require_code_owner_reviews: CODEOWNERS dosyasındaki sahiplerden approval zorunlu
CODEOWNERS Dosyası ile Sorumluluk Dağılımı
CODEOWNERS dosyası, hangi dosya veya dizinin kimin sorumluluğunda olduğunu tanımlar. Bu sayede ilgili kişi otomatik olarak review’a atanır.
# .github/CODEOWNERS dosyasını oluştur
cat > .github/CODEOWNERS << 'EOF'
# Global sahip - her şey için varsayılan
* @myorg/senior-devs
# Backend takımı
/backend/ @myorg/backend-team
/api/ @myorg/backend-team @ali-yilmaz
# Frontend takımı
/frontend/ @myorg/frontend-team
/src/components/ @myorg/frontend-team
# DevOps kritik dosyalar
/.github/workflows/ @myorg/devops-team
/Dockerfile @myorg/devops-team
/docker-compose.yml @myorg/devops-team
/kubernetes/ @myorg/devops-team @mehmet-kaya
# Güvenlik açısından kritik
/config/security.yml @myorg/security-team
/src/auth/ @myorg/security-team @myorg/senior-devs
# Veritabanı migration'ları her iki takım onaylasın
/migrations/ @myorg/backend-team @myorg/dba-team
EOF
git add .github/CODEOWNERS
git commit -m "chore: add CODEOWNERS configuration"
git push
Bu yapılandırma sayesinde birisi /kubernetes/ dizininde değişiklik yaptığında, devops ekibi otomatik olarak reviewer olarak atanır. Unutkan insanların bile review’dan kaçması zorlaşır.
Merge Stratejileri: Hangisi Ne Zaman Kullanılır?
GitHub üç farklı merge stratejisi sunuyor ve bunların her biri farklı senaryolar için uygun. Yanlış stratejiyi seçmek, commit history’yi berbat hale getirebilir.
Merge Commit (–no-ff)
Klasik merge yöntemi. Feature branch’teki tüm commit’ler olduğu gibi korunur ve ek bir merge commit oluşturulur.
# Local'de merge commit stratejisi
git checkout main
git merge --no-ff feature/user-authentication
# Sonuçta history şuna benzer:
# * Merge branch 'feature/user-authentication'
# |
# | * feat: add JWT token validation
# | * feat: add user login endpoint
# | * feat: add password hashing
# |/
# * previous main commit
Bu stratejinin avantajı, feature branch’in ne zaman başlayıp bittiğini açıkça görmek. Dezavantajı ise büyük projelerde history’nin karmaşık bir ağaca dönüşmesi.
Ne zaman kullan: Uzun süreli feature branch’leri, release pipeline’ları veya ekibin her feature’ı ayrı olarak görmek istediği durumlarda.
Squash and Merge
Tüm commit’leri tek bir commit’e sıkıştırır. “WIP”, “fix typo”, “deneme” gibi commit’lerin history’ye girmesini önler.
# Local'de squash merge
git checkout main
git merge --squash feature/user-authentication
git commit -m "feat: add user authentication module
- JWT token validation
- Login/logout endpoints
- Password hashing with bcrypt
- Session management
Closes #123"
# Ya da interactive rebase ile squash
git checkout feature/user-authentication
git rebase -i main
# Editörde açılan listede 'pick' yerine 'squash' veya 's' yaz
# pick abc1234 feat: add JWT token validation
# squash def5678 fix: typo in validation
# squash ghi9012 WIP: working on login
Squash merge en çok sevdiğim strateji. Özellikle PR bazlı çalışan ekiplerde history temiz kalıyor. Her PR bir commit oluyor ve ne değiştiğini git log --oneline ile tek bakışta görebiliyorsun.
Ne zaman kullan: Çoğu feature PR’ı için ideal. Özellikle ekipte commit kalitesi tutarsızsa.
Rebase and Merge
Commit’leri tek tek alıp main’in üzerine yeniden uygular. Merge commit oluşmaz, linear bir history elde edilir.
# Local'de rebase
git checkout feature/user-authentication
git rebase main
# Conflict varsa çöz
git add resolved-file.py
git rebase --continue
# Rebase tamamlanınca main'e fast-forward merge
git checkout main
git merge --ff-only feature/user-authentication
git push
# History kontrolü
git log --oneline --graph
# * ghi9012 feat: add session management
# * def5678 feat: add login endpoint
# * abc1234 feat: add JWT validation
# * xyz0000 previous main commit (linear!)
Rebase güzel ama tehlikeli. Commit hash’leri değiştiği için paylaşılan branch’lerde asla rebase yapma. Sadece kendi local branch’inde, henüz push etmediğin commit’lerde kullan.
Ne zaman kullan: Temiz linear history isteyen ekipler için, özellikle küçük takımlarda veya kısa yaşam sürekli hotfix branch’lerinde.
GitHub Actions ile Otomatik Kalite Kontrol
Branch koruma kurallarının “status check” kısmı işe yarıyor çünkü arkasında bir CI pipeline var. Basit ama etkili bir workflow yazalım:
# .github/workflows/pr-checks.yml
cat > .github/workflows/pr-checks.yml << 'EOF'
name: PR Quality Checks
on:
pull_request:
branches: [ main, develop ]
jobs:
lint:
name: Code Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: pip install flake8 black isort
- name: Run flake8
run: flake8 src/ --max-line-length=100
- name: Check formatting
run: black --check src/
- name: Check imports
run: isort --check-only src/
test:
name: Unit Tests
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run tests with coverage
run: |
pytest tests/
--cov=src
--cov-report=xml
--cov-fail-under=80
- name: Upload coverage
uses: codecov/codecov-action@v3
security-scan:
name: Security Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Bandit security scan
run: |
pip install bandit
bandit -r src/ -ll -ii
- name: Check dependencies for vulnerabilities
run: |
pip install safety
safety check -r requirements.txt
EOF
Bu workflow’da üç aşamalı kontrol var. Lint geçmeden test çalışmıyor, her ikisi de geçmeden PR merge edilemiyor. Security scan bağımsız çalışıyor ama o da geçmek zorunda.
Git Hooks ile Local Koruma Katmanı
Sunucu tarafındaki koruma önemli ama local’de de engel koymak, ekip üyelerinin hata yapmasını daha erken aşamada önler. pre-commit ve commit-msg hook’ları bu iş için biçilmiş kaftan.
# pre-commit hook - commit öncesi kontroller
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
echo "Running pre-commit checks..."
# Protected branch'e direkt commit engeli
current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/(.*),1,')
protected_branches=("main" "master" "production" "develop")
for branch in "${protected_branches[@]}"; do
if [ "$current_branch" = "$branch" ]; then
echo "ERROR: Direkt commit '$branch' branch'ine yapilamaz!"
echo "Lutfen bir feature branch olusturun: git checkout -b feature/your-feature"
exit 1
fi
done
# Trailing whitespace kontrolü
if git diff --cached --check; then
echo "Whitespace check passed"
else
echo "ERROR: Trailing whitespace bulundu. Duzeltip tekrar deneyin."
exit 1
fi
# Debug statement kontrolü (Python için)
if git diff --cached | grep -E "^+(.*)(pdb.set_trace|breakpoint()|print(debug)" > /dev/null; then
echo "WARNING: Debug statement bulundu! Devam etmek istiyor musunuz? (y/n)"
read -r response
if [ "$response" != "y" ]; then
exit 1
fi
fi
echo "Pre-commit checks passed!"
exit 0
EOF
chmod +x .git/hooks/pre-commit
# commit-msg hook - commit mesajı formatı kontrolü
cat > .git/hooks/commit-msg << 'EOF'
#!/bin/bash
commit_msg=$(cat "$1")
pattern="^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)((.+))?: .{10,}"
if ! echo "$commit_msg" | grep -qE "$pattern"; then
echo "ERROR: Commit mesaji Conventional Commits formatina uymuyor!"
echo ""
echo "Dogru format: <type>(<scope>): <description>"
echo "Ornek: feat(auth): add JWT token refresh mechanism"
echo ""
echo "Gecerli tipler: feat, fix, docs, style, refactor, test, chore, perf, ci, build, revert"
exit 1
fi
exit 0
EOF
chmod +x .git/hooks/commit-msg
Hook’ları ekip genelinde paylaşmak için scripts/install-hooks.sh gibi bir setup scripti yazabilir ve yeni katılan ekip üyelerinin bunu çalıştırmasını isteyebilirsin. .git/ dizini paylaşılmadığı için hook’lar otomatik gelmez, bu yüzden kurulum scriptinin varlığı önemli.
Gerçek Dünya Senaryosu: Hotfix Süreci
Cuma akşamı production’da kritik bir bug çıktı. Normal PR sürecini bekleyemezsiniz. Bu durumda nasıl hareket etmeli?
# 1. Production branch'inden hotfix branch'i aç
git checkout production
git pull origin production
git checkout -b hotfix/critical-payment-bug
# 2. Düzeltmeyi yap ve commit et
git add .
git commit -m "fix(payment): fix null pointer in payment processing
Production'da odeme islemi sirasinda null user_id geldiginde
sistem cokuyordu. Null check eklendi ve hata loglanarak
graceful handling yapildi.
Fixes #456"
# 3. PR aç ama urgent label ile
gh pr create
--base production
--title "hotfix: fix critical payment processing bug"
--body "## Problem
Production'da odeme islemi bozuldu.
## Cozum
Null check eklendi.
## Test
- [ ] Local test gecti
- [ ] Staging'de dogrulandi
**Bu PR urgently review gerektiriyor!**"
--label "hotfix,urgent"
--reviewer "ali-yilmaz,mehmet-kaya"
# 4. Merge sonrası aynı fix'i develop'a da uygula
git checkout develop
git pull origin develop
git cherry-pick <hotfix-commit-hash>
git push origin develop
Bu süreçte bile branch koruma kuralları devrede. Sadece minimum 1 review ile CI’ın temel testlerinin geçmesi yeterli kabul edilebilir. GitHub’da bunu “branch protection override” yaparak değil, ayrı bir emergency policy tanımlayarak yapabilirsin.
Branch Stratejisi Seçimi
Ekip büyüklüğüne ve release sıklığına göre doğru branch stratejisi farklılık gösterir.
Trunk Based Development (küçük ekipler, sık deployment):
- Tek main/trunk branch
- Feature flag’lar ile tamamlanmamış feature’lar gizlenir
- Branch yaşam süresi maksimum 1-2 gün
- Her commit deploy edilebilir durumda olmalı
GitHub Flow (web uygulamaları, continuous deployment):
mainbranch her zaman production-ready- Feature branch açılır, PR ile merge edilir
- Merge sonrası direkt deploy
- Basit, anlaşılır, küçük-orta ekipler için ideal
Git Flow (versiyonlu yazılımlar, planlı release):
# Git Flow kurulumu
apt install git-flow # veya brew install git-flow
git flow init
# Feature başlat
git flow feature start user-notifications
# Feature bitir (develop'a merge eder)
git flow feature finish user-notifications
# Release başlat
git flow release start 2.1.0
# Release bitir (main ve develop'a merge, tag atar)
git flow release finish 2.1.0
Git Flow daha karmaşık ama develop, release, hotfix gibi ayrı branch tipleri ile büyük ekiplerde paralel çalışmayı kolaylaştırır.
PR Template ile Tutarlı Süreç
Her PR’ın aynı kalitede olmasını sağlamak için template kullanmak şart.
# .github/pull_request_template.md
cat > .github/pull_request_template.md << 'EOF'
## Değişiklik Özeti
<!-- Ne değişti? Neden değişti? -->
## Değişiklik Türü
- [ ] Bug fix (geriye dönük uyumlu hata düzeltmesi)
- [ ] Yeni feature (geriye dönük uyumlu yeni işlevsellik)
- [ ] Breaking change (mevcut işlevselliği bozan değişiklik)
- [ ] Dokümantasyon güncellemesi
## Test Edildi Mi?
- [ ] Unit testler eklendi/güncellendi
- [ ] Mevcut testler geçiyor
- [ ] Manuel test yapıldı
## Ekran Görüntüsü / Video
<!-- UI değişikliği varsa ekle -->
## İlgili Issue
Closes #(issue numarası)
## Reviewer Notları
<!-- Reviewer'ın dikkat etmesi gereken özel bir durum var mı? -->
## Deployment Notları
<!-- Migration, env değişkeni, config değişikliği var mı? -->
EOF
Bu template sayesinde her PR belirli standartları karşılamak zorunda. Reviewer’lar da neye bakacaklarını biliyor ve review süreci hızlanıyor.
Sonuç
Branch koruma kuralları ve merge stratejileri bir kerede kurulan, sonra unutulan şeyler değil. Ekip büyüdükçe, iş akışı değiştikçe bunları gözden geçirmek gerekiyor.
Pratikte işe yarayan yaklaşım şu şekilde özetlenebilir: main ve production branch’leri için katı koruma kuralları koy, en az 2 review şart koş, CI testleri olmadan merge’e izin verme. Feature branch’leri için özgür bırak ama local hook’larla commit kalitesini garanti altına al. Squash merge stratejisini varsayılan yap, history temiz kalsın.
Ekip olarak bu araçları kullanmak başlangıçta “niye bu kadar prosedür var” tepkisi yaratabilir. Ama ilk kez o kritik branch koruma kuralı yanlış bir kodu durdurunca, o cuma gecesi yaşanmayan production krizi ekibin bakış açısını değiştirir. Güvenli çalışma ortamı, ekip verimliliğini artırır; engel değil, güvence sağlar.
