Git revert, belirli bir commit'i geri almak (geçmişi bozmadan) için kullandığımız komuttur. Tam olarak ilgili commit'in tam tersini yapan yeni bir commit oluşturur.
Geçmişi silmez, geçmişin üzerine yeni bir sayfa açarak hatayı düzeltir.
Git'te her commit bir snapshot'tır. git revert komutu o snapshot'ı silmez. İlgili commit'in tam tersini yapan yeni bir commit oluşturur. Bu sayede geçmiş bozulmaz, üstüne ekleme yaparak ilerler.
Bunu şuna benzetebiriz. Muhasebe defterinde bir hata yaptık diyelim. Hata yaptığımız satırı silmeyiz. "Bu kaydı iptal ediyorum" diye yeni bir satır atarız. Böylece defter bütünlüğü korunur, karalama "görünmeyen" bir satır olmaz.
Git Revert Ne Zaman Kullanılır?
Bir commit'i push edip remote repoya gönderdiğimizde geçmişi değiştirmek artık risklidir. Çünkü localdeki bir commit'i sildiğimizde/değiştirdiğimizde localimiz ile remote uyuşmazlığı ortaya çıkar. Takım arkadaşlarımız pull ettiğinde kırılmış bu "commit zincirini" alacağı için takım içinde küçük bir kaos çıkar.
Özetle, git revert komutu push edilmiş commit'leri geri almanın güvenilir ve kabul görmüş yoludur.
Neden Git Reset Yerine Git Revert Kullanılır?
git reset ve git revert komutları ilk bakışta benzer görünse de çalışma mantıkları tamamen farklıdır. git reset commit geçmişini değiştirirken, git revert geçmişi koruyarak geri alma işlemi yapar. Bu yüzden özellikle push edilmiş commit'lerde genellikle git revert tercih edilir.
| Komut | Geçmişi Değiştirir mi? | Güvenli mi? | Push edilmiş commit'lerde kullanılır mı? |
|---|---|---|---|
git reset |
Evet | Riskli olabilir | Genelde hayır |
git revert |
Hayır | Evet | Evet |
Özetle; eğer commit push edilmişse ve ekip içinde çalışıyorsak en güvenli yöntem çoğu zaman git revert kullanmaktır.
Örnek Kullanım Senaryosu
Diyelim ki bir dosyaya şu satırı ekledik ve commit ettik:
+ background-color: red;
Bu commit artık geçmişte a1b2c3d olarak yer alıyor. Hızlıca ilgili commit'i bulmak için git log --oneline yazabilirsiniz. (commit geçmişi hakkında daha fazlasını öğrenmek için git log yazımızı okuyabilirsiniz). Bu durumda;
- A)- git reset yaparsak; Git o commit'i sanki hiç yapılmamış gibi tarihten siler.
- B)- git revert yaparsak; git o commit'e bakıp ne eklendiyse çıkarır, ne çıkarıldıysa ekler. Yani "tersine commit" atmış gibi oluruz. Örnek:
- background-color: red;
Yukarıdaki kodu işleten bir "geri alma" commit'i oluşturmuş oluruz. Eski commit git tarihçesinde kalır.
Eski kayıt silinmez, üstüne bunu bilinçli olarak geri aldım demiş oluruz.
Artık git log çıktımız şöyle olur:
d4e5f6a Revert "Add red background color"
a1b2c3d Add red background color
9f8e7d6 Initial commit
Git Revert Commit Hash'i Nasıl Bulunur?
Geri almak istediğiniz commit'in hash değerini hızlıca git log --oneline komutu ile bulabilirsiniz. Eğer son commit ise git revert HEAD ile almak çok pratiktir. Eğer bir önceki veya iki önceki commit'i geri alacak olursak kullanmamız gereken kod: git revert HEAD~1 ve git revert HEAD~2.
Git Revert Nasıl Kullanılır?
git revert <commit-hash>
Bu komut çağrıldığında;
- O commit'te neler değiştiyse tersini hesaplar.
- Yeni bir commit oluşturur.
- Varsayılan olarak commit mesajı editörü açar: Revert "orijinal mesaj"
Son Commit'i Hash Bilmeden Geri Alma
Commit hash'ini her zaman bilmeyebiliriz. Son commit'i ya da birkaç commit öncesini geri almak istiyorsak HEAD kullanabiliriz.
git revert HEAD # son commit'i geri al
git revert HEAD~1 # bir önceki commit'i geri al
git revert HEAD~3 # 3 commit öncesini geri al
HEAD her zaman bulunduğumuz konumu gösterir.
~ işareti ise kaç adım geriye gideceğimizi belirtir.
Kural olarak şöyle düşünebiliriz:HEAD= şu an,HEAD~1= bir önceki,HEAD~3= üç önceki.
Git Revert İçeride Ne Yapar?
Git'te her commit bir snapshot olsa da, git revert aslında diff (fark) üzerinden çalışır. Hedef commit ile bir önceki commit'i karşılaştırır, aradaki farkı ters yönde working tree'ye uygular ve sonucu yeni bir commit olarak kaydeder. Teknik olarak bu bir üç-yollu birleştirmedir (three-way merge): mevcut HEAD bir taraf, hedef commit'in parent'ı diğer taraftır.
Kritik fark şudur: git reset branch pointer'ını geriye taşır (commit'ler "geride kalır"). git revert ise hiçbir pointer'ı geriye almaz; tıpkı normal bir commit gibi HEAD'i bir adım ileri taşır. Geçmiş bu yüzden bozulmaz.
# Başlangıç — B commit'ini geri almak istiyoruz
A --- B --- C (HEAD, main)
# git revert B → B'nin tersini yapan yeni commit (B') eklenir
A --- B --- C --- B' (HEAD, main)
# ↑ ↑
# B duruyor B'nin değişiklikleri geri alındı
# Karşılaştırma: git reset --hard B yapsaydık
A --- B (HEAD, main) # C tarihten silinirdi (tehlikeli)
resetpointer'ı oynatır,revertcommit ekler. İşte "geçmişi koruma" dediğimiz şey budur.
Git Revert En Sık Kullanılan Parametreler
--no-edit Parametresi
git revert <hash> --no-edit
Şeklinde kullanımı vardır. Editörü açmadan direkt commit atar. Mesaj düzenlemek istemiyorsak kullanırız. Pratikte çok kullanılır.
--no-commit Parametresi
git revert <hash> --no-commit
Bu komut revert işlemi yapar ama commit atmaz, onun yerine staging area'ya gönderir. Neden kullanılır? Birden fazla commit'i tek seferde geri alıp hepsini tek commit olarak atmak istediğimizde kullanırız.
git revert A --no-commit
git revert B --no-commit
git revert C --no-commit
git commit -m "Revert A, B, C"
İşlem Yönetimi Parametreleri: --continue, --abort, --skip
Revert sırasında conflict çıkarsa işlem ortada durur ve repo "revert in progress" durumuna geçer. Bu üç parametre o durumu yönetir:
git revert --continue # conflict'i çözdükten sonra revert'i tamamla
git revert --abort # işlemi iptal et, repoyu revert öncesi haline döndür
git revert --skip # (range revert'te) bu commit'i atla, sıradakine geç
Bu parametrelerin gerçek bir conflict akışı içinde nasıl kullanıldığını Git Revert Conflict Nasıl Çözülür? bölümünde adım adım anlatıyoruz.
Git Revert ile Birden Fazla Commit'i Geri Alma
git revert A..D
Bu komut A'dan D'ye kadar olan aralığı geri alır. A dahil değil, D dahil. Her commit için ayrı revert commit oluşturulur.
git revert A^..D
A'yı da dahil etmek istersek ^ işaretini kullanabiliriz.
Merge Commit'i Revert Yapma (Geri Alma)
Merge ile birleştirilerek commit edilen commit'leri geri alma işlemi daha uzundur çünkü merge edilmiş commit'in iki parenti vardır. Git vcs sistemi hangisini anahat olarak bilemeyeceğinden aşağıdaki hatayı verir:
error: commit is a merge but no -m option was given
Çözüm olarak -m parametresi eklenir.
git revert <merge-hash> -m 1
-m 1 birinci parenti (genellikle main branch) anahat kabul et, merge'den gelen değişiklikleri geri al demektir.
-m 2 de kullanabiliriz ama nadiren kullanılır.
Git Revert Conflict Nasıl Çözülür?
Geri almak istediğiniz commit'ten sonra aynı satırlar başka commit'lerde değiştiyse, Git ters değişikliği temiz uygulayamaz ve revert işlemini o noktada durdurur. Bu noktada repo "revert in progress" durumundadır.
Önce git status ile durumu görmekte fayda var sonra conflict marker'larını elle düzeltebiliriz:
<<<<<<< HEAD
background-color: blue;
=======
background-color: green;
>>>>>>> parent of abc1234 (Add red background)
İstediğiniz hali bırakıp marker'ları silip, ardından dosyayı staging'e ekleyip revert'i tamamlayabiliriz:
git add style.css
git revert --continue # düzeltilen haliyle revert commit'ini oluştur
İşlemden tamamen vazgeçmek isterseniz repoyu revert öncesi haline döndürürsünüz:
git revert --abort # her şeyi revert başlamadan önceki haline al
Birden fazla commit'i aynı anda revert ederken (örneğin git revert A..D) sıradaki bir commit'i atlamak isterseniz:
git revert --skip # bu commit'i atla, sıradakiyle devam et
Üç anahtar:--continuetamamla,--aborttümüyle vazgeç,--skipbu commit'i atla. Merge conflict çözmeyi biliyorsanız mantık birebir aynıdır; tek fark, işlemi bitiren komutungit revert --continueolmasıdır.
Git Revert vs Git Reset Arasındaki Farklar Nelerdir?
| Revert | Reset | |
|---|---|---|
| Geçmiş | korunur, üstüne eklenir | değiştirilir / yeniden yazılır |
| Push sonrası | güvenli | tehlikeli |
| Takım çalışması | uygun | uygun değil |
| Kullanım amacı | "bunu geri aldım" kaydı bırak | "bu hiç olmadı" de |
Kısaca: Commit push edildiyse -> git revert. Sadece localdeyse -> git reset düşünülebilir. Takım varsa her zaman git revert.
Ne Zaman Revert KULLANILMALI?
- Commit zaten push edilmişse.
- Takım ile çalışılıyorsak.
- Geri alma işleminin izini bırakmak istiyorsak.
- Production'da bir şeyi acil olarak geri almak istiyorsak.
Ne Zaman Revert KULLANILMAMALIDIR?
- Commit sadece localde ise reset daha temizdir.
- Geri almak istediğimiz commit çok eski ise arada onlarca commit varsa aşırı conflict çıkabilir.
- Revert'in kendisini revert etmek istersek ek karışıklık çıkar (özellikle merge revertlerde).
Gerçek Hayat Senaryosu
# bir özellik geliştirdik ve push ettik
git push origin main
# sonra fark ettik ki production patladı
# geri almak için
git revert abc1234 --no-edit
git push origin main
# Bu durumda takım arkadaşlarımız pull yaptığında hiçbir sorun yaşamaz.
Revert Edilmiş Commit Tekrar Revert Edilirse Ne Olur?
Bir revert commit'i de aslında sıradan bir commit'tir. Dolayısıyla onu da revert edebiliriz. Bunu yaptığımızda orijinal değişiklik geri gelir.
9f8e7d6 Initial commit
a1b2c3d Add red background ← orijinal değişiklik
d4e5f6a Revert "Add red..." ← geri aldık
e5f6b7a Revert "Revert "Add..." ← geri almanın geri alması = orijinal geri döndü
Yani revert'i revert etmek, o değişikliği yeniden uygulamak anlamına gelir. Geçmiş yine bozulmaz, üstüne bir commit daha eklenir.
Özellikle merge commit'lerini revert ettikten sonra "aslında bu feature lazımdı" dediğimizde bu yönteme başvururuz.