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:

terminal
+ 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:
terminal
- 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:

terminal
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?

terminal
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.

terminal
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.

commit grafiği
# 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)
reset pointer'ı oynatır, revert commit ekler. İşte "geçmişi koruma" dediğimiz şey budur.

Git Revert En Sık Kullanılan Parametreler

--no-edit Parametresi

terminal
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

terminal
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.

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

terminal
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

terminal
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.

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

terminal
error: commit is a merge but no -m option was given

Çözüm olarak -m parametresi eklenir.

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

style.css
<<<<<<< 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:

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

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

terminal
git revert --skip       # bu commit'i atla, sıradakiyle devam et
Üç anahtar: --continue tamamla, --abort tümüyle vazgeç, --skip bu commit'i atla. Merge conflict çözmeyi biliyorsanız mantık birebir aynıdır; tek fark, işlemi bitiren komutun git revert --continue olması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

terminal
# 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.

terminal
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.