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):

  • main branch 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.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir