Tek başına geliştirilen küçük projelerde yayın süreci genellikle şöyledir: dosyaları FTP ile sunucuya at, bir şey bozulursa hızlıca düzelt. Bu yöntem bir gün, yarım kalan bir yükleme ya da yanlış dosyanın üzerine yazılması yüzünden sitenin saatlerce kapalı kalmasına kadar işe yarar.

Bu siteyi geliştirirken zamanla oturttuğum akış aslında çok basit: her yayının bir sürüm numarası, bir değişiklik notu, bir yedeği ve bir geri alma yolu var. Bu yazıda o akışı adım adım, kendi projelerinize uyarlayabileceğiniz komutlarla anlatıyorum.

1. Sürüm numarası: anlamlı üç sayı

Anlamsal sürümleme (Semantic Versioning, kısaca SemVer) BÜYÜK.KÜÇÜK.YAMA biçimindeki üç sayıdan oluşur. Kütüphaneler için tanımlanmış olsa da bir web sitesine de rahatça uyarlanabilir:

  • Yama (2.4.0 → 2.4.1): Hata düzeltmesi, görünümde küçük bir iyileştirme. Ziyaretçi için davranış değişmez.
  • Küçük (2.4.1 → 2.5.0): Yeni bir özellik ya da sayfa. Eski her şey çalışmaya devam eder.
  • Büyük (2.5.0 → 3.0.0): Adres yapısı, veritabanı şeması ya da yönetim paneli gibi geriye dönük uyumu bozan değişiklikler.

Sürüm numarasını tek bir yerde tutun (bir ayar, bir VERSION dosyası ya da bir sabit) ve yönetim panelinin bir köşesinde gösterin. Bir hata bildirimi geldiğinde ilk soru hep aynıdır: "Hangi sürümde?"

2. Değişiklik günlüğü: insanlar için yazın

CHANGELOG.md dosyası, commit geçmişinin insanlar için özetlenmiş hâlidir. Her sürüm bir başlık, altında da değişiklikler türüne göre gruplanır. Ben "Keep a Changelog" yaklaşımındaki gruplamayı Türkçe kullanıyorum:

## [2.5.0] - 2026-10-29
### Eklendi
- RSS beslemesi (/feed.xml) ve yapay zekâ araçları için llms-full.txt
### Değişti
- robots.txt: yapay zekâ botları tek listede toplandı
### Düzeltildi
- Güvenlik iletişim adresi panelden kaydedilmiyordu

## [2.4.1] - 2026-10-28
### Düzeltildi
- Proje ikonlarının yüklendikten sonra kırpılması

Burada önemli olan teknik ayrıntı değil, etkidir. "PostsController::fields() düzenlendi" yerine "Yazı kaydedilirken SEO alanları siliniyordu" yazmak, altı ay sonra dosyayı açan size çok daha fazla şey anlatır.

3. Git: commit ve etiket

Günlük çalışmada anlamlı commit mesajları yazmak (bunu Git ile takım çalışması yazısında ayrıntılı anlattım) tek başına çalışırken de işe yarar. Yayına çıkan her sürümü de bir etiketle işaretleyin:

git tag -a v2.5.0 -m "Sürüm 2.5.0: RSS, llms-full.txt, SEO içerikleri"
git push origin v2.5.0

# Son sürümden bu yana değişen dosyalar
git diff --name-only --diff-filter=ACMR v2.4.1 HEAD

Etiketin asıl faydası son satırda: iki sürüm arasında hangi dosyaların değiştiğini tek komutla görebilirsiniz. Yükleme paketi de doğrudan bu listeden hazırlanır.

4. Yayından önce: kısa bir kontrol listesi

  • Değişen PHP dosyalarında sözdizimi kontrolü: php -l dosya.php
  • CSS ve JavaScript derleme adımı varsa çalıştırıldı mı?
  • Yerelde, canlıya mümkün olduğunca benzeyen verilerle sayfalar gezildi mi; tarayıcı konsolunda hata var mı?
  • Veritabanı değişikliği var mı? Varsa geri dönüşü nasıl olacak?
  • CHANGELOG yazıldı mı?
# Değişen bütün PHP dosyalarında sözdizimi kontrolü
git diff --name-only --diff-filter=ACMR v2.4.1 HEAD -- '*.php' | xargs -r -n1 php -l

5. Paketle, yedekle, tek seferde yükle

Dosyaları tek tek FTP ile göndermenin en büyük riski, yükleme yarıda kaldığında sitenin yarısının yeni, yarısının eski sürümde kalmasıdır. Bunun yerine değişen dosyaları tek bir arşive koyup sunucuda bir kerede açın. Açmadan hemen önce de iki şeyi yedekleyin: veritabanını ve üzerine yazılacak dosyaların eski hâlini.

# Yerelde: yalnız değişen dosyaları paketle ve özetlerini çıkar
git diff --name-only --diff-filter=ACMR v2.4.1 HEAD > degisenler.txt
tar -czf paket.tar.gz -T degisenler.txt
md5sum $(cat degisenler.txt) > paket.md5

scp paket.tar.gz paket.md5 yukle.sh kullanici@sunucu:~/
#!/usr/bin/env bash
set -euo pipefail

KOK="$HOME/public_html"
YEDEK="$HOME/yukleme-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$YEDEK"

# 1) Veritabanı yedeği (kimlik bilgileri ~/.my.cnf dosyasından okunur)
mysqldump --single-transaction veritabani_adi | gzip > "$YEDEK/vt.sql.gz"

# 2) Üzerine yazılacak dosyaların eski hâli
cd "$KOK"
tar -tzf "$HOME/paket.tar.gz" | while read -r f; do [ -f "$f" ] && echo "$f"; done > "$YEDEK/liste.txt"
tar -czf "$YEDEK/eski.tar.gz" -T "$YEDEK/liste.txt"

# 3) Yeni dosyalar tek seferde
tar -xzf "$HOME/paket.tar.gz" -C "$KOK"

# 4) Doğrulama: her dosya yereldekiyle birebir mi?
md5sum -c "$HOME/paket.md5" --quiet && echo "Tüm dosyalar doğrulandı."

# 5) Sayfa önbelleğini temizle
rm -f "$KOK"/storage/cache/pages/*.html

echo "Geri almak için: tar -xzf $YEDEK/eski.tar.gz -C $KOK"

Veritabanı parolasını betiğin içine ya da komut satırına yazmayın; komut geçmişinde ve süreç listesinde görünür. mysqldump kimlik bilgilerini yalnız sizin okuyabildiğiniz (chmod 600) bir ~/.my.cnf dosyasından okuyabilir.

md5sum -c adımı göründüğünden daha değerlidir. Yarım aktarılmış, bozulmuş ya da yanlış klasöre açılmış bir dosya varsa bunu ziyaretçiden önce siz görürsünüz.

6. Geri alma planı

İyi bir yayın akışının ölçüsü, bir şey ters gittiğinde ne kadar hızlı geri dönebildiğinizdir. Yukarıdaki betik her yüklemede iki şey bırakıyor: eski.tar.gz ve vt.sql.gz. Geri dönmek için:

# Dosyaları önceki hâline döndür
tar -xzf ~/yukleme-20261029-221500/eski.tar.gz -C ~/public_html

# Gerekirse veritabanını da
gunzip -c ~/yukleme-20261029-221500/vt.sql.gz | mysql veritabani_adi

Bu iki komutu, ihtiyaç duymadan önce bir kez deneme ortamında çalıştırın. Hiç denenmemiş bir yedek, yedek değil umuttur.

Yeni sürümde eklenen dosyalar eski.tar.gz içinde olmadığı için geri almada silinmez; genellikle zararsızdırlar ama tam temizlik istiyorsanız paket listesiyle eski listeyi karşılaştırıp fazlalıkları silebilirsiniz.

7. Yayından sonra

  • Ana sayfayı, değişen sayfaları ve yönetim panelini açın; tarayıcı konsoluna ve sunucu hata günlüğüne bakın.
  • Önbellek kullanıyorsanız temizlendiğinden emin olun (eski CSS ile yeni HTML kötü bir ikilidir).
  • Sürüm numarasını güncelleyin ve değişiklik günlüğündeki tarihi kesinleştirin.
  • Her şey yolundaysa birkaç gün sonra eski yükleme klasörlerini silin; son birkaç tanesini saklamak yeterlidir.

Özet

Bu akışın hiçbir adımı karmaşık değil ve hepsi birkaç dakika sürüyor: sürüm numarası, değişiklik günlüğü, etiket, kontrol listesi, yedek, tek parça yükleme, doğrulama ve geri alma yolu. Ama birlikte uygulandığında yayın günü stres günü olmaktan çıkıyor. Bir şey bozulduğunda paniğe kapılmak yerine tek bir komut çalıştırıyorsunuz.