← Kursa Dön
📄 Text · 30 min

Geri Alma İşlemleri

Giriş: Neden Geri Alma Bu Kadar Önemli?

Yazılım geliştirirken hata yapmak kaçınılmaz. Yanlış dosyayı değiştirirsin, hatalı bir commit atarsın, bir özelliği geri almak istersin. Git'in en büyük vaatlerinden biri de bu: her zaman geri dönebilirsin.

Ama Git'te geri almanın birden fazla yolu var ve hangisini ne zaman kullanacağını bilmek kritik. Yanlış geri alma komutu, durumu daha da karmaşık hale getirebilir.

Bu derste Git'in üç geri alma aracını öğreneceğiz:

  • git restore — dosya düzeyinde geri alma

  • git reset — commit düzeyinde geri alma (tehlikeli olabilir!)

  • git revert — güvenli geri alma (yeni commit ile)

Her birinin ne zaman kullanılacağını, risklerini ve aralarındaki farkları netleştireceğiz.


🎬 Analoji: Word Belgesinde Geri Alma

Bir Word belgesinde çalışırken:

  • Ctrl+Z (Undo): Son yaptığını geri al → git restore

  • Belgenin eski bir versiyonuna dön: "Bu versiyonu geri yükle" → git reset

  • Değişikliği tersine çevir ama geçmişi koru: "Yaptığım değişikliğin tersini uygula" → git revert

Ama Git'teki farklılık şu: Word'de Ctrl+Z basit, Git'te ise geri almanın kapsamı ve etkisi farklı.

Geri Alma Spektrumu:

GÜVENLİ ◄────────────────────────────────► TEHLİKELİ
                                            
git restore    git revert    git reset      git reset
(dosya geri    (yeni commit  --soft         --hard
 al)           ile geri al)  (commit geri,  (her şey
                             dosyalar       kaybolur)
                             staging'de)    

git restore — Dosya Düzeyinde Geri Alma

git restore Git 2.23'te eklendi. Dosyaları önceki durumlarına geri yüklemek için kullanılır. En güvenli geri alma aracı.

Senaryo 1: Değişiklikleri Geri Al (Working Directory)

Bir dosyada değişiklik yaptın ama beğenmedin. Son commit'teki haline geri dönmek istiyorsun:

# style.css'de değişiklik yaptın
$ echo "h1 { color: red; font-size: 100px; }" >> style.css

$ git status
Changes not staged for commit:
        modified:   style.css

# Değişikliği geri al — son commit'teki haline dön
$ git restore style.css

$ git status
nothing to commit, working tree clean

# style.css son commit'teki haline geri döndü

Birden fazla dosya:

# Tüm değişiklikleri geri al
$ git restore .

# Belirli dosyaları geri al
$ git restore style.css app.js

⚠️ Dikkat: git restore ile geri alınan değişiklikler kalıcı olarak kaybolur. Commit'lenmemiş değişiklikler Git'in kayıt sistemi dışındadır — geri getirmenin yolu yoktur. Bu komutu kullanmadan önce gerçekten geri almak istediğinden emin ol.

Senaryo 2: Staging'den Çıkarma

Bir dosyayı yanlışlıkla git add ile staging'e aldın:

# Yanlışlıkla tüm dosyaları staging'e aldın
$ git add .

$ git status
Changes to be committed:
        modified:   index.html
        modified:   style.css    ← Bunu staging'den çıkarmak istiyorsun

# Staging'den çıkar (dosya değişikliği korunur)
$ git restore --staged style.css

$ git status
Changes to be committed:
        modified:   index.html

Changes not staged for commit:
        modified:   style.css    ← Değişiklik duruyor, sadece staging'den çıktı

--staged bayrağı ile dosyayı staging'den çıkarırsın ama dosyadaki değişiklik korunur. Sadece "commit'e dahil etme" demeksin.

Senaryo 3: Belirli Bir Commit'ten Dosya Geri Yükleme

# 3 commit önceki index.html'i geri yükle
$ git restore --source HEAD~3 index.html

# Belirli bir commit'ten geri yükle
$ git restore --source a1b2c3d style.css

$ git status
Changes not staged for commit:
        modified:   index.html
        modified:   style.css
# Dosyalar working directory'de değişti (staging'de değil)

--source ile herhangi bir commit'teki dosya versiyonunu working directory'ye getirebilirsin.

restore Komut Haritası

# Working directory → son commit'e geri al
git restore dosya.txt

# Staging → unstage (dosya değişikliği korunur)
git restore --staged dosya.txt

# Hem staging'den çıkar hem değişikliği geri al
git restore --staged --worktree dosya.txt

# Belirli commit'ten geri yükle
git restore --source=HEAD~3 dosya.txt

# Tüm dosyaları geri al
git restore .

# Tüm dosyaları staging'den çıkar
git restore --staged .

git reset — Commit Düzeyinde Geri Alma

git reset daha güçlü ama daha tehlikeli bir araç. Commit geçmişini yeniden yazar. Üç modu var ve her biri farklı kapsamda çalışır.

Üç Modu Anlamak

                    Working Dir    Staging    Commit History
                    ───────────    ───────    ──────────────
git reset --soft       ✅           ✅          ❌ Geri alır
git reset --mixed      ✅           ❌          ❌ Geri alır  (varsayılan)
git reset --hard       ❌           ❌          ❌ Geri alır

✅ = Korunur (dokunulmaz)
❌ = Geri alınır / sıfırlanır

Daha görsel bir şekilde:

Başlangıç durumu:
                                     
[Commit A] ← [Commit B] ← [Commit C]    HEAD → main → C
                                
Working Directory: C + değişiklikler
Staging Area: değişiklikler stage'de

--soft: Sadece Commit'i Geri Al

$ git reset --soft HEAD~1
Sonuç:

[Commit A] ← [Commit B]                  HEAD → main → B
                    
Working Directory: C'nin içeriği + kendi değişikliklerin (korundu)
Staging Area: C'nin değişiklikleri burada (commit'e hazır)

C commit'i gitti ama içeriği staging'de bekliyor.

Ne zaman kullanılır?

  • Son commit'in mesajını veya içeriğini tamamen değiştirmek istiyorsun

  • Birden fazla commit'i tek bir commit'te birleştirmek istiyorsun (squash)

# Son 3 commit'i tek commit'te birleştir
$ git reset --soft HEAD~3
# Artık 3 commit'in tüm değişiklikleri staging'de
$ git commit -m "feat: Tüm login özelliği tamamlandı"

--mixed (Varsayılan): Commit ve Staging'i Geri Al

$ git reset HEAD~1
# veya açıkça:
$ git reset --mixed HEAD~1
Sonuç:

[Commit A] ← [Commit B]                  HEAD → main → B

Working Directory: C'nin değişiklikleri hâlâ dosyalarda (korundu)
Staging Area: BOŞ (sıfırlandı)

C commit'i gitti, staging temizlendi, ama dosya değişiklikleri duruyor.

Ne zaman kullanılır?

  • Commit'i geri almak ama değişiklikleri kaybetmemek istiyorsun

  • Değişiklikleri yeniden düzenleyip farklı commit'ler oluşturmak istiyorsun

# Son commit'i geri al, değişiklikleri yeniden düzenle
$ git reset HEAD~1

$ git status
Changes not staged for commit:
        modified:   login.js
        modified:   auth.js
        modified:   style.css

# Şimdi bunları farklı commit'lere ayır
$ git add login.js auth.js
$ git commit -m "feat: Login sistemi"

$ git add style.css
$ git commit -m "style: Login sayfası stilleri"

--hard: Her Şeyi Geri Al (Tehlikeli!)

$ git reset --hard HEAD~1
Sonuç:

[Commit A] ← [Commit B]                  HEAD → main → B

Working Directory: B'nin durumuna geri döndü (DEĞİŞİKLİKLER SİLİNDİ!)
Staging Area: BOŞ

C commit'i gitti. C'nin değişiklikleri gitti. 
Commit'lenmemiş değişiklikler de gitti.
HER ŞEY GİTTİ.

⚠️ Dikkat: git reset --hard en tehlikeli Git komutlarından biridir. Commit'lenmemiş değişiklikler geri getirilemez. Commit'lenmiş değişiklikler reflog ile kurtarılabilir ama commit'lenmemiş olanlar kayıp. Bu komutu kullanmadan önce iki kere düşün.

Ne zaman kullanılır?

  • Yerel değişikliklerini tamamen çöpe atmak istiyorsun

  • Projeyi bilinen iyi bir duruma geri getirmek istiyorsun

  • "Her şeyi sil, baştan başla" dediğin an

# SON ÇARE: Her şeyi son commit'e geri al
$ git reset --hard HEAD

# Veya belirli bir commit'e geri dön
$ git reset --hard a1b2c3d

Reset Karşılaştırma Tablosu

┌─────────────────┬──────────┬──────────┬──────────────┐
│     Mod         │ Working  │ Staging  │ Commit       │
│                 │ Dir      │ Area     │ History      │
├─────────────────┼──────────┼──────────┼──────────────┤
│ --soft          │ Korunur  │ Korunur  │ Geri alınır  │
│ --mixed (def.)  │ Korunur  │ Sıfırlar │ Geri alınır  │
│ --hard          │ Sıfırlar │ Sıfırlar │ Geri alınır  │
└─────────────────┴──────────┴──────────┴──────────────┘

Reset ile Belirli Dosyayı Unstage Etmek

git reset ayrıca tek bir dosyayı staging'den çıkarmak için de kullanılır:

# Bu ikisi aynı şeyi yapar:
$ git reset HEAD dosya.txt
$ git restore --staged dosya.txt

Modern Git'te git restore --staged tercih ediliyor çünkü niyeti daha açık ifade ediyor.


git revert — Güvenli Geri Alma

git revert, bir commit'in değişikliklerini tersine çeviren yeni bir commit oluşturur. Geçmişi yeniden yazmaz — üzerine ekler.

Nasıl Çalışır?

Öncesi:
[A] ← [B] ← [C] ← [D]     HEAD → main → D

$ git revert C

Sonrası:
[A] ← [B] ← [C] ← [D] ← [C']     HEAD → main → C'

C' = C'nin tersini uygulayan yeni commit
C hâlâ geçmişte var. Geçmiş değişmedi.
D'nin değişiklikleri de korundu.
Sadece C'nin eklediği şeyler geri alındı.

Pratik Kullanım

# Son commit'i geri al
$ git revert HEAD
# Editör açılır, revert commit mesajını düzenle
# Varsayılan mesaj: "Revert 'feat: İletişim formu eklendi'"

[main e6f7g8h] Revert "feat: İletişim formu eklendi"
 2 files changed, 0 insertions(+), 25 deletions(-)

# Mesajı kendim yazayım
$ git revert HEAD --no-edit
# Varsayılan mesajı kabul et, editör açılmasın

# Belirli bir commit'i geri al
$ git revert a1b2c3d

# Log'a bak
$ git log --oneline
e6f7g8h (HEAD -> main) Revert "feat: İletişim formu eklendi"
d4e5f6g feat: İletişim formu eklendi
a1b2c3d feat: Hakkımda sayfası
h7i8j9k feat: Proje başlatıldı

Birden Fazla Commit'i Revert Etmek

# Son 3 commit'i tek tek revert et (en sondan başla)
$ git revert HEAD~2..HEAD
# veya
$ git revert HEAD HEAD~1 HEAD~2

# Commit yapmadan sadece dosyaları değiştir (birden fazla revert'i birleştirmek için)
$ git revert --no-commit HEAD~2..HEAD
$ git commit -m "revert: Son 3 commit geri alındı"

💡 İpucu: Revert sırasında conflict çıkabilir — özellikle geri alınan commit'ten sonra aynı dosyalarda başka değişiklikler yapıldıysa. Conflict çözümünü ileriki derslerde öğreneceğiz.


Revert vs Reset: Ne Zaman Hangisi?

Bu en çok sorulan sorulardan biri. Basit kural:

┌──────────────────────────────────────────────────────────────┐
│                                                              │
│  Commit'i PUSH ETTİN Mİ?                                   │
│                                                              │
│  HAYIR (sadece yerel) ──────► git reset kullanabilirsin      │
│                                (geçmişi yeniden yaz, temiz)  │
│                                                              │
│  EVET (başkaları gördü) ────► git revert kullan              │
│                                (geçmişi koru, yeni commit)   │
│                                                              │
└──────────────────────────────────────────────────────────────┘

Neden push'landıktan sonra reset kullanmıyoruz?

Çünkü Ali ve Ayşe senin commit'ini çoktan pull etmiş olabilir. Sen geçmişi yeniden yazarsan, onların geçmişiyle senin geçmişin uyumsuz hale gelir. Karmaşa çıkar.

Revert ise yeni bir commit olduğu için herkesin geçmişiyle uyumlu kalır.

Reset ile:
Ali:   [A] ← [B] ← [C] ← [D]
Sen:   [A] ← [B] ← [C]          ← D'yi sildim!
Ayşe:  [A] ← [B] ← [C] ← [D]
→ Uyumsuzluk! Ali ve Ayşe'nin D'si var, senin yok.

Revert ile:
Ali:   [A] ← [B] ← [C] ← [D]
Sen:   [A] ← [B] ← [C] ← [D] ← [D']   ← D'nin tersini ekledim
Ayşe:  [A] ← [B] ← [C] ← [D]
→ Ayşe pull edince D' gelir, sorunsuz.

Kurtarma: git reflog — Son Çare

git reset --hard yaptın ve commit'lerin kayboldu? Panik yapma. reflog hayat kurtarır.

Reflog, HEAD'in son 30 gündeki tüm hareketlerini kaydeder:

$ git reflog
e6f7g8h (HEAD -> main) HEAD@{0}: reset: moving to HEAD~2
d4e5f6g HEAD@{1}: commit: feat: İletişim formu eklendi
a1b2c3d HEAD@{2}: commit: feat: Hakkımda sayfası
h7i8j9k HEAD@{3}: commit (initial): feat: Proje başlatıldı

Kayıp commit'i gördün mü? d4e5f6g! Geri getirelim:

# O commit'e geri dön
$ git reset --hard d4e5f6g
HEAD is now at d4e5f6g feat: İletişim formu eklendi

# Veya yeni bir branch olarak kurtarma
$ git branch kurtarma d4e5f6g

💡 İpucu: Reflog sadece yerel repo'da çalışır ve sadece commit'lenmiş değişiklikleri kurtarabilir. git add bile yapmadığın değişiklikler kaybolursa, reflog bile kurtaramaz. Sık commit at — güvenlik ağın olsun.


Karşılaştırma: Tüm Geri Alma Yöntemleri

┌───────────────────┬──────────────┬──────────────┬───────────────┐
│ Yöntem            │ Ne yapar?    │ Güvenli mi?  │ Ne zaman?     │
├───────────────────┼──────────────┼──────────────┼───────────────┤
│ git restore       │ Dosyayı geri │ ⚠️ Commit-   │ Dosya düzeyi  │
│                   │ al           │ lenmemiş     │ geri alma     │
│                   │              │ kaybolur     │               │
├───────────────────┼──────────────┼──────────────┼───────────────┤
│ git reset --soft  │ Commit geri, │ ✅ Güvenli   │ Commit'i      │
│                   │ staging'de   │              │ yeniden yaz   │
├───────────────────┼──────────────┼──────────────┼───────────────┤
│ git reset --mixed │ Commit geri, │ ✅ Güvenli   │ Commit'i      │
│                   │ unstaged     │ (dosyalar    │ yeniden       │
│                   │              │  korunur)    │ düzenle       │
├───────────────────┼──────────────┼──────────────┼───────────────┤
│ git reset --hard  │ Her şey geri │ ❌ Tehlikeli │ Son çare      │
│                   │              │              │               │
├───────────────────┼──────────────┼──────────────┼───────────────┤
│ git revert        │ Ters commit  │ ✅ Güvenli   │ Push'lanmış   │
│                   │ oluşturur    │              │ commit'ler    │
├───────────────────┼──────────────┼──────────────┼───────────────┤
│ git commit --amend│ Son commit'i │ ✅ Güvenli   │ Küçük         │
│                   │ değiştirir   │ (yerel)      │ düzeltmeler   │
└───────────────────┴──────────────┴──────────────┴───────────────┘

Pratik Senaryo: Gerçek Hayat

# Senaryo: Yanlışlıkla .env dosyasını commit'ledin!

# 1. Durumu gör
$ git log --oneline -3
c3d4e5f (HEAD -> main) feat: Yeni özellik
b2c3d4e chore: Config dosyaları  ← .env burada!
a1b2c3d feat: Proje başlatıldı

# 2. Henüz push etmediysen → reset
$ git reset --soft HEAD~2
# Son 2 commit geri alındı, değişiklikler staging'de

$ git reset HEAD .env        # .env'yi staging'den çıkar
$ echo ".env" >> .gitignore  # .gitignore'a ekle

$ git add .gitignore
$ git add .                  # .env hariç her şey
$ git commit -m "feat: Yeni özellik ve config dosyaları (.env hariç)"

# 3. Zaten push ettiysen → revert + yeni commit
$ git rm --cached .env
$ echo ".env" >> .gitignore
$ git add .gitignore
$ git commit -m "security: .env dosyası izlemeden çıkarıldı"
$ git push

Özet

  • `git restore` dosya düzeyinde geri alma yapar — working directory'yi veya staging'i etkiler, commit geçmişine dokunmaz

  • `git reset --soft` commit'i geri alır ama değişiklikler staging'de kalır — commit'leri birleştirmek için ideal

  • `git reset --mixed` (varsayılan) commit ve staging'i geri alır, değişiklikler working directory'de kalır

  • `git reset --hard` her şeyi geri alır — commit'lenmemiş değişiklikler kaybolur, son çare olarak kullan

  • `git revert` güvenli geri alma yapar — yeni commit oluşturur, geçmişi değiştirmez, push'lanmış commit'ler için kullan

  • `git reflog` kayıp commit'leri kurtarmak için son çaredir — HEAD'in 30 günlük hareketlerini kaydeder


*Tebrikler! Git'in temel komutlarını tamamladın. Bir sonraki bölümde dallanma (branching) dünyasına gireceğiz — Git'in en güçlü özelliği!*