Git yanlış commit geri alma işleminde önce komut seçmek yerine commit’in yalnızca yerel bilgisayarda mı kaldığını, uzak depoya gönderilip gönderilmediğini ve ekip arkadaşları tarafından çekilip çekilmediğini belirlemek gerekir. Yalnızca yerelde bulunan ve henüz paylaşılmamış son commit için git reset geçmişi yeniden düzenlemek amacıyla kullanılabilir; paylaşılmış commit’lerde ise genellikle git revert daha güvenli yaklaşımdır.
Bu nedenle doğru sıra şudur: çalışma ağacını ve staging alanını kontrol et, aktif branch ile upstream bağlantısını incele, hatalı commit’i netleştir, paylaşım durumunu doğrula ve gerekirse yedek branch oluştur. Teşhis tamamlanmadan çalıştırılan özellikle git reset --hard veya bilinçsiz bir force push, korunması gereken değişikliklerin kaybolmasına ya da ekip geçmişinin karmaşıklaşmasına yol açabilir.
Önce Durumu Teşhis Et: Commit Nerede ve Kimde?
Yanlış commit’i geri alırken ilk soru “revert mi, reset mi?” değildir. İlk soru, bu commit’in kimlerin çalışma alanına ulaştığıdır. Commit yalnızca sizin yerel branch’inizde duruyorsa geçmişi yeniden düzenleme seçeneğiniz olabilir. Commit uzak depoya gönderildiyse veya bir ekip arkadaşı tarafından çekildiyse, aynı branch üzerinde geçmişi değiştirmek başkalarının çalışmalarını etkileyebilir.
Teşhise çalışma ağacından başlayın. git status, mevcut HEAD ile staging alanı ve çalışma ağacı arasındaki farkları gösterir: staged değişiklikler commit edilmeye hazırdır; unstaged değişiklikler dosyalarda bulunur ancak staging alanına alınmamıştır; untracked dosyalar ise Git tarafından henüz izlenmiyordur. Git’in git status dokümantasyonu bu ayrımı ve branch takip bilgilerini ayrıntılı biçimde açıklar.
git status
git status -sb
git status -sb kısa çıktıda aktif branch’i ve varsa upstream durumunu daha kolay görmenizi sağlar. Örneğin ## feature/login...origin/feature/login [ahead 1] benzeri bir ifade, yerel branch’in upstream branch’e göre ileride olduğunu gösterebilir. Böyle bir durumda commit’in henüz uzak depoya gönderilmemiş olma ihtimali vardır; ancak kesin karar vermeden önce remote referansını ve push geçmişini ayrıca kontrol etmek gerekir.
1. Çalışma ağacında korunması gereken değişiklik var mı?
İlk kontrol şudur: Commit’i geri alma işlemine başlamadan önce üzerinde çalıştığınız dosyalarda henüz commit edilmemiş değişiklik bulunuyor mu?
- Staged değişiklik:
git addile staging alanına alınmış, bir sonraki commit’e hazır içeriktir. - Unstaged değişiklik: Dosyada değiştirilmiş ancak staging alanına alınmamış içeriktir.
- Untracked dosya: Git’in henüz takip etmediği yeni dosyadır.
- Temiz çalışma ağacı: Git’in mevcut HEAD’den sonra fark göstermediği durumdur.
Örneğin yanlış commit’i geri almak isterken aynı dosyada yeni bir düzeltme yapıyorsanız, bu düzeltme yanlışlıkla geri alma işleminden etkilenebilir. Özellikle git reset --hard, çalışma ağacını hedef commit ile eşleştirmeye çalıştığı için korunması gereken yerel değişiklikler varken düşünmeden kullanılmamalıdır.
Çalışma ağacında önemli değişiklik varsa önce bunları ayrı bir commit ile korumak, güvenli bir geçici branch’e almak veya uygun bir stash akışı kullanmak daha kontrollüdür. Ancak stash kullanmak, değişikliğin hangi durumda saklandığını takip etmeyi zorlaştırabileceğinden, önemli işlerde açık isimlendirilmiş bir yedek branch daha görünür bir güvenlik katmanı sağlayabilir.
2. Hatalı commit gerçekten hangisi?
Bir sonraki adım commit geçmişini okunabilir hâle getirmektir:
git log --oneline --decorate --graph -n 8
--oneline her commit’i kısa hash ve mesajıyla gösterir. --decorate branch ve tag işaretlerini, --graph ise dallanma yapısını görmenizi sağlar. -n 8 yalnızca son birkaç commit’i listeler; sayı ihtiyaca göre değiştirilebilir.
Örneğin çıktı aşağıdaki gibi olabilir:
* 7c91f2a (HEAD -> feature/login) Yanlış yapılandırma eklendi
* 3a82bd1 Form doğrulaması tamamlandı
* 1f04c8e Başlangıç yapısı oluşturuldu
Bu örnekte hatalı görünen commit 7c91f2a ve HEAD’in gösterdiği son commit’tir. Ancak yalnızca commit mesajına bakarak karar vermek yeterli olmayabilir. Hatalı değişikliğin hangi dosyalara dokunduğunu görmek için şu inceleme komutlarından yararlanabilirsiniz:
git show --stat 7c91f2a: Commit’in değiştirdiği dosyaları ve özet istatistikleri gösterir.git show 7c91f2a: Commit’in gerçek diff içeriğini gösterir.git diff 7c91f2a^ 7c91f2a: Hatalı commit’in bir önceki commit’e göre farkını karşılaştırır.
Örneğin commit mesajı “API düzenlemesi” olsa da diff içinde üretim ayarlarını değiştiren tek bir satır bulunabilir. Ya da “README güncellemesi” adlı commit, fark edilmeden kaynak kodunda da değişiklik yapmış olabilir. Geri alma stratejisini commit mesajına değil, gerçek diff’e göre belirlemek gerekir.
3. Aktif branch ve upstream bağlantısı nedir?
Aynı commit farklı branch’lerde farklı sonuçlar doğurabilir. Önce hangi branch üzerinde olduğunuzu doğrulayın:
git branch --show-current
git branch -vv
git branch --show-current aktif branch adını gösterir. git branch -vv ise yerel branch’in hangi remote branch’i takip ettiğini ve iki branch arasında fark olup olmadığını görmenize yardımcı olur. Daha doğrudan bir upstream kontrolü için şu komut da kullanılabilir:
git rev-parse --abbrev-ref --symbolic-full-name @{u}
Bu komut bir upstream tanımlıysa örneğin origin/feature/login çıktısını verir. Upstream ayarlanmamışsa hata mesajı alınabilir; bu, commit’in mutlaka yerel olduğu anlamına gelmez. Sadece mevcut branch’in Git yapılandırmasında takip edilen bir uzak branch bulunmadığını gösterir.
Upstream bilgisini kontrol etmek önemlidir çünkü “yerel branch’imde duruyor” ifadesi ile “uzak depoya gönderilmedi” ifadesi aynı şey değildir. Bir branch’in upstream bağlantısı olmayabilir fakat commit daha önce başka bir remote’a veya farklı bir branch adına gönderilmiş olabilir. Bu nedenle ekip iş akışında kullanılan remote’ları da göz önünde bulundurun.
4. Hatalı commit uzak depoya gönderilmiş mi?
Remote referanslarını güncelledikten sonra yerel branch ile uzak branch arasındaki farkı inceleyebilirsiniz:
git fetch --prune origin
git log --oneline origin/feature/login..HEAD
git log --oneline HEAD..origin/feature/login
İlk git log komutu, yerelde olup uzak branch’te bulunmayan commit’leri listeler. Hatalı commit burada görünüyorsa, en azından karşılaştırılan remote branch’e henüz gönderilmemiş olabilir. İkinci komut ise uzakta olup yerelde bulunmayan commit’leri gösterir; bu çıktı, uzak branch’in sizden ileride olduğunu veya branch’lerin ayrıştığını gösterebilir.
Bu kontrolün sınırı vardır: Remote branch’in güncel olması gerekir ve doğru remote ile doğru branch’i karşılaştırmalısınız. Ayrıca bir commit’in başka bir branch’e, pull request’e veya farklı bir remote’a gönderilmiş olabileceğini unutmayın. Bu yüzden “git log çıktısında görünmedi, demek ki kimse görmedi” sonucuna doğrudan atlamayın.
5. Ekip arkadaşları commit’i çekmiş mi?
Bir commit’in uzak depoya gönderilmiş olması ile ekip arkadaşlarının onu yerel depolarına çekmiş olması farklı durumlardır:
- Yalnızca yerel: Commit sizin bilgisayarınızdadır; henüz paylaşılmamıştır.
- Remote’a gönderilmiş: Commit uzak branch’te görülebilir, fakat ekip arkadaşları henüz çekmemiş olabilir.
- Ekip tarafından çekilmiş: Commit başka çalışma alanlarında branch geçmişinin parçası hâline gelmiştir.
- Başka commit’lere temel olmuş: Ekip arkadaşları hatalı commit’in üzerine yeni commit’ler eklemiş olabilir.
Git, ekip arkadaşınızın commit’i yerel deposuna çekip çekmediğini her durumda tek başına kesin biçimde göstermez. Bu bilgi için ekip iletişimi, pull request etkinliği, branch güncellemeleri ve kullanılan uzak depo platformundaki kayıtlar incelenmelidir. Bir ekip arkadaşınız “bu branch’i çektim ve üzerine çalıştım” diyorsa, yalnızca kendi yerel log’unuza bakarak geçmişi resetlemek güvenli kabul edilmemelidir.
Hatalı commit başka commit’lerin temeli olduysa reset ile geçmişi geriye taşımak, ekip arkadaşlarının branch’lerini artık ortak geçmişten koparabilir. Bu noktada yeni bir geri alma commit’i oluşturmak, geçmişteki olayları koruyarak değişikliğin etkisini tersine çevirmek açısından daha öngörülebilirdir.
“Önce durumu teşhis et, sonra komut seç” kontrol listesi
- Değişiklik var mı?
git statusile staged, unstaged ve untracked dosyaları kontrol edin. Çünkü geri alma komutu, henüz commit edilmemiş çalışmanızı etkileyebilir. - Yanlış commit hangisi?
git log --oneline --decorate --graphve gerekirsegit showile commit hash’ini ve gerçek diff’i doğrulayın. Yanlış commit seçmek, doğru değişiklikleri de tersine çevirebilir. - Aktif branch hangisi?
git branch --show-currentile doğru branch’te olduğunuzdan emin olun. Yanlış branch’te reset yapmak, beklemediğiniz bir geçmişi değiştirebilir. - Commit yalnızca yerelde mi? Upstream ve remote farklarını inceleyin. Yerel ve uzak branch aynı noktadaysa geçmişi değiştirme kararı daha dikkatli değerlendirilmelidir.
- Commit paylaşılmış mı? Ekip arkadaşlarına, pull request kayıtlarına ve branch kullanımına bakın. Paylaşılmış geçmişte reset, başkalarının çalışma alanını bozabilir.
- Korunması gereken dosyalar var mı? Önemli çalışma varsa komuttan önce yedek branch veya ayrı bir koruma commit’i oluşturun. Böylece yanlış seçimde geri dönüş noktası kalır.
Komuttan önce yedek branch oluşturma
Çalışma ağacınız temizse mevcut HEAD’i yeni bir branch adıyla işaretlemek hızlı bir güvenlik önlemidir:
git switch -c before-undo
Bu komut, mevcut noktadan before-undo adlı yeni bir branch oluşturur ve sizi bu branch’e geçirir. Daha sonra asıl çalışma branch’ine dönüp geri alma işlemini orada yapabilirsiniz. Yedek branch, commit nesnesinin hemen silinmesini engelleyen sihirli bir arşiv değildir; ancak yanlışlıkla yapılan bir reset sonrasında eski commit’e isimli ve kolay erişilebilir bir referans sağlar.
Çalışma ağacında henüz commit edilmemiş değişiklik varsa branch oluşturma veya branch değiştirme işlemi dosyalar arasındaki çakışmaya göre durabilir. Böyle bir durumda Git’in uyarısını yok saymak yerine önce git status çıktısını okuyun. Değişiklikleri ayrı bir commit ile korumak veya dikkatli biçimde stash’lemek, geri alma işleminden önce daha güvenli bir hazırlık olur.
Revert ve Reset Arasındaki Farkı Nasıl Seçersiniz?

git revert ile git reset aynı “geri alma” ihtiyacına cevap veriyor gibi görünse de amaçları farklıdır. git revert, mevcut geçmişi koruyup önceki bir commit’in etkisini tersine çeviren yeni bir commit oluşturur. git reset ise branch’in işaret ettiği HEAD konumunu başka bir commit’e taşır; seçilen moda göre index ve çalışma ağacını da değiştirir.
Git’in resmi açıklamasında bu ayrım, revert’in yeni bir geri alma commit’i oluşturması, reset’in ise branch ucunu hareket ettirerek commit geçmişini değiştirmesi şeklinde ortaya konur. Güncel davranışları karşılaştırmak için Git’in reset, restore ve revert açıklamasına başvurabilirsiniz.
Git revert ne yapar?
git revert <commit> komutu, belirtilen commit’in getirdiği değişiklikleri ters yönde uygular ve sonucu yeni bir commit olarak kaydeder. Örneğin geçmiş şu şekildeyse:
A --- B --- C
Ve C hatalıysa, git revert C sonrasında geçmiş mantıksal olarak şu hâle gelir:
A --- B --- C --- C-revert
Burada C geçmişten silinmez. Git, C’nin varlığını korur ve C’nin etkisini kaldıran yeni bir commit ekler. Bu nedenle revert, uzak depoya gönderilmiş veya ekip tarafından çekilmiş commit’lerde genellikle daha uygun bir başlangıç noktasıdır.
Revert işlemi, çalışma ağacında HEAD’e göre commit edilmemiş değişiklikler varken sorun çıkarabilir. Bu nedenle işlemden önce git status ile çalışma ağacını kontrol edin. Ayrıca hatalı commit’ten sonra aynı satırlarda yeni değişiklikler yapılmışsa revert sırasında çakışma oluşabilir. Böyle bir durumda Git’in istediği dosyaları düzeltip ilgili dosyaları staging alanına aldıktan sonra git revert --continue ile süreci sürdürebilirsiniz.
Git reset ne yapar?
git reset, branch’in HEAD işaretçisini hedef commit’e taşır. Bu hareketin index ve çalışma ağacına nasıl yansıyacağı seçilen moda bağlıdır. Bu nedenle “reset geri alır” cümlesi tek başına eksiktir; mutlaka --soft, --mixed veya --hard seçeneğiyle birlikte düşünülmelidir.
git reset --soft <commit>: HEAD’i hedef commit’e taşır; index ve çalışma ağacını olduğu gibi bırakır. Hedef commit ile yeni HEAD arasındaki değişiklikler staged durumda kalır. Bu seçenek, yanlış commit’i kaldırıp içeriğini düzenleyerek yeniden commit etmek istediğinizde kullanışlıdır.git reset --mixed <commit>: HEAD’i ve index’i hedef commit’e taşır; çalışma ağacındaki dosyaları değiştirmez. Hedef commit’ten sonra gelen değişiklikler dosyalarda korunur ancak staging alanından çıkarılır, yani unstaged hâle gelir. Bu seçenek Git’te varsayılan reset modudur.git reset --hard <commit>: HEAD’i, index’i ve çalışma ağacını hedef commit ile eşleştirmeye çalışır. Hedef commit’ten sonra yapılan takip edilen dosya değişiklikleri kaybolabilir; bazı untracked dosyalar da üzerine yazılabilir veya silinebilir. Bu nedenle mevcut değişiklikleri doğrulamadan kullanılmamalıdır.
| Komut | Geçmişe etkisi | Index ve çalışma ağacına etkisi | Paylaşılmış commit’te uygunluk | Tipik kullanım |
|---|---|---|---|---|
git revert <commit> |
Yeni bir geri alma commit’i ekler; eski commit korunur. | Hedef commit’in değişikliklerini tersine çevirir ve normalde yeni commit oluşturur. | Genellikle uygundur; ekip geçmişini yeniden yazmaz. | Remote’a gönderilmiş veya ekipçe çekilmiş hatalı değişikliği geri almak. |
git reset --soft <commit> |
HEAD’i geriye taşır; branch geçmişi yeniden yazılır. | Index ve çalışma ağacı korunur; aradaki değişiklikler staged kalır. | Genellikle uygun değildir; yalnızca paylaşılmamış geçmişte düşünülmelidir. | Son commit’i kaldırıp içeriğini düzenleyerek yeniden commit etmek. |
git reset --mixed <commit> |
HEAD’i ve branch ucunu hedef commit’e taşır. | Index hedef commit’e uyar; çalışma ağacındaki değişiklikler unstaged kalır. | Genellikle uygun değildir; paylaşılmış branch’te geçmişi değiştirir. | Commit’i kaldırıp dosyaları seçerek yeniden staging alanına almak. |
git reset --hard <commit> |
HEAD’i geriye taşır ve geçmişi yeniden yazar. | Index ve çalışma ağacı hedef commit’e uydurulur; korunmayan değişiklikler kaybolabilir. | Paylaşılmış commit’lerde kaçınılmalıdır. | Çalışma alanını bilinen bir commit ile tamamen eşitlemek. |
Basit karar kuralı şöyledir: Eski commit geçmişte görünmeye devam etsin ve ekipteki diğer çalışma alanları bozulmasın istiyorsanız git revert düşünün. Commit henüz paylaşılmadıysa ve branch geçmişini bilinçli biçimde yeniden düzenlemek istiyorsanız git reset seçenekleri değerlendirilebilir.
Bu ayrım, commit’in içeriğini koruyup korumamakla aynı şey değildir. Örneğin reset --soft, commit kaydını branch geçmişinden çıkarırken değişikliklerin kendisini staged hâlde bırakır. reset --mixed de commit kaydını kaldırır ancak dosya değişikliklerini çalışma ağacında unstaged olarak korur. Buna karşılık reset --hard hem geçmiş işaretçisini hem index’i hem de çalışma ağacını hedef noktaya taşımaya çalışır.
Yalnızca Yerel Son Commit’i Güvenle Geri Almak
Şimdi küçük ve kontrollü bir senaryo ele alalım. Geçmişimiz üç commit’ten oluşsun:
A --- B --- C
- A: Başlangıç commit’i.
- B: Bir özelliğin eklendiği commit.
- C: Yanlışlıkla oluşturulan son commit.
Bu bölümde şu varsayımlar geçerlidir: C yalnızca yerel branch’tedir, uzak depoya gönderilmemiştir, ekip arkadaşları C’yi çekmemiştir ve çalışma ağacında korunması gereken bağımsız değişiklik bulunmamaktadır. Bu varsayımlar doğru değilse aynı reset akışını doğrudan uygulamayın; önceki teşhis adımlarına dönün.
Git’in reset modları için resmi dokümantasyonda belirtilen davranışa göre --soft HEAD’i taşırken index ve çalışma ağacını korur; --mixed index’i hedef commit’e uyarlar fakat çalışma ağacını korur; --hard ise çalışma ağacını da hedef commit’e eşleştirmeye çalışır. Bu nedenle aşağıdaki komutlar, aynı hedef commit’e dönse bile farklı koruma seviyeleri sağlar.
İlk güvenlik adımı: yedek branch oluşturun
Senaryonun çalışma ağacı temiz kabul edildiği için önce mevcut noktayı isimli bir branch ile koruyalım:
git switch -c before-undo
Bu işlemden sonra C commit’i before-undo branch’i tarafından işaretlenir. Artık asıl branch’e dönerek reset işlemini deneyebilirsiniz:
git switch feature/login
Branch adını kendi branch’inizle değiştirin. Yedek branch oluşturulmadan da işlem yapılabilir; ancak özellikle reset seçeneklerini yeni öğrenirken bu ek referans, yanlış hedef seçimi veya beklenmeyen çıktı sonrasında karşılaştırma yapmayı kolaylaştırır.
Son commit’i staged değişiklikleri koruyarak kaldırma
Son commit C’nin commit kaydını kaldırıp değişikliklerini bir sonraki commit için hazır durumda bırakmak istiyorsanız:
git reset --soft HEAD~1
Buradaki HEAD~1, mevcut HEAD’in bir önceki commit’i olan B’yi ifade eder. Komut sonrasında branch’in ucu C’den B’ye taşınır; C’nin içerdiği değişiklikler ise index’te staged olarak kalır. Beklenen mantıksal durum şöyledir:
A --- B (HEAD -> feature/login)
C değişiklikleri index'te staged
git log --oneline çalıştırıldığında C artık feature/login branch’inin son commit’i olarak görünmez. Ancak git status çıktısında C’nin değiştirdiği dosyalar staged değişiklik olarak listelenir. Bu noktada dosyaları inceleyebilir, hatalı bölümleri düzenleyebilir ve doğru içeriği yeni bir commit ile kaydedebilirsiniz.
Son commit’i çalışma ağacında unstaged tutma
Değişiklikleri kaybetmeden staging alanından da çıkarmak istiyorsanız mixed reset kullanın:
git reset --mixed HEAD~1
Bu komut da HEAD’i B’ye taşır. Fark şu ki index B’deki hâle getirilir; C’nin değişiklikleri çalışma ağacındaki dosyalarda korunur ancak staged olmaktan çıkar. Böylece değişiklikleri tek tek inceleyebilir, yalnızca doğru parçaları git add ile staging alanına alabilirsiniz.
Örneğin C commit’i hem doğru bir test güncellemesini hem de yanlış bir yapılandırma değişikliğini içeriyorsa mixed reset sonrasında dosyaları ayırarak yalnızca test güncellemesini yeniden commit edebilirsiniz. Bu, yanlış commit’i olduğu gibi yeniden oluşturmadan içeriği seçerek temizleme imkânı verir.
Doğrudan çalıştırılabilir terminal akışı
Aşağıdaki akış, temiz çalışma ağacına sahip ve C commit’i henüz paylaşılmamış bir branch üzerinde çalışır:
git status -sb
git log --oneline --decorate -n 3
git switch -c before-undo
git switch feature/login
git reset --soft HEAD~1
git status
git log --oneline --decorate -n 3
Beklenen sonuç, son commit’in branch geçmişinden çıkması ve C’nin değişikliklerinin staged olarak görünmesidir:
On branch feature/login
Changes to be committed:
modified: src/login.py
1f04c8e (HEAD -> feature/login) Özellik commit'i
9a31d20 Başlangıç commit'i
Hash değerleri ve dosya adları örnektir; kendi repository’nizde farklı görünür. Önemli olan iki gözlemdir: git log içinde yanlış C commit’i artık aktif branch’in ucunda değildir ve git status içinde C’nin değişiklikleri “Changes to be committed” altında yer alır.
Soft ve mixed arasında seçim
- Soft reset seçin: Commit’i kaldırdıktan sonra değişikliklerin tamamını hazır hâlde görmek ve hızlıca düzenleyip yeniden commit etmek istiyorsanız.
- Mixed reset seçin: Dosyaları ve değişiklik parçalarını yeniden incelemek, bazılarını seçerek staging alanına almak istiyorsanız.
- Hard reset konusunda durun: Çalışma ağacında korunması gereken bir dosya, yerel düzeltme veya untracked içerik varsa önce yedek alın.
Bu senaryoda git reset --soft HEAD~1 veya git reset --mixed HEAD~1 sonrasında commit geçmişi yerelde yeniden düzenlenmiştir. Uzak depoya gönderilmemiş bir commit için bu yaklaşım genellikle yönetilebilir durumdadır; fakat branch daha sonra paylaşılacaksa yeni commit’i oluşturmadan önce dosya farklarını, testleri ve branch hedefini tekrar kontrol edin.
Değişiklikleri Koruyup Düzenleyerek Yeniden Commit Oluşturma
Yanlış commit’i geri aldıktan sonra amaç her zaman değişiklikleri silmek değildir. Özellikle git reset --soft veya git reset --mixed kullandıysanız, dosyalardaki değişiklikleri inceleyip hatalı kısımları düzeltmek ve yalnızca doğru içerikleri yeni bir commit olarak kaydetmek mümkündür. Buradaki temel akış şudur: dosyayı düzenle, farkı incele, doğru parçaları stage et, staged içeriği tekrar kontrol et ve yeni commit oluştur.
Bu davranışta git reset --soft, branch işaretçisini önceki commit’e taşırken değişiklikleri hem çalışma ağacında hem de staging alanında tutar. git reset --mixed ise commit’i geri alır, fakat değişiklikleri çalışma ağacında tutup staging alanından çıkarır. Bu açıklama --soft ve --mixed senaryoları için geçerlidir; git reset --hard çalışma ağacındaki commit edilmemiş değişiklikleri de silebileceği için aynı varsayımla kullanılmamalıdır.
Örneğin başlangıç geçmişinizin şu şekilde olduğunu düşünelim:
A --- B --- HATALI
HATALI commit’inde hem doğru bir düzenleme hem de yanlış bir dosya değişikliği bulunduğunu varsayalım. Son commit’i geri alıp içeriği yeniden düzenlemek için önce çalışma durumunu kontrol edin:
git status
git log --oneline --decorate -3
Ardından son commit’i staging alanındaki değişiklikleri koruyarak geri alabilirsiniz:
git reset --soft HEAD~1
git status
Bu noktada branch artık B commit’ini gösterir. Ancak HATALI commit’inde bulunan dosya değişiklikleri staging alanında durmaya devam eder. Çalışma ağacını ve staging alanını daha kontrollü biçimde düzenlemek için değişiklikleri önce stage dışına çıkarabilirsiniz:
git reset
git status
Buradaki ikinci git reset, varsayılan olarak staging alanını mevcut commit’in içeriğiyle eşitler; dosyalardaki değişiklikleri silmez. Böylece yeniden commit etmek istediğiniz içerikler çalışma ağacında, yani dosyaların kendisinde kalır.
Önce dosyayı düzenleyin, sonra farkı okuyun
Şimdi hatalı dosyayı bir editörde açıp gerekli düzeltmeyi yapın. Örneğin config.py içinde yanlış bir sabit, README.md içinde eksik bir açıklama ve yanlışlıkla değişmiş debug.log dosyası olduğunu düşünelim. Önce tüm değişiklikleri okuyun:
git diff
git diff, henüz stage edilmemiş değişiklikleri gösterir. Bu çıktı yalnızca “hangi dosyalar değişti?” sorusunu değil, “hangi satırlar değişti ve bu satırlar gerçekten commit’e girmeli mi?” sorusunu yanıtlamak için kullanılır.
İnceleme sırasında şu soruları tek tek sorun:
- Değişiklik, yanlış commit’in düzeltilmiş hâlinin bir parçası mı?
- Dosyada yalnızca ilgili satırlar mı değişti?
- Geçici çıktı, log veya editör dosyası gibi istenmeyen bir dosya değişmiş mi?
- Bir satırın yanında fark edilmeden biçimlendirme veya boşluk değişikliği oluşmuş mu?
- Yeni commit tek bir amaca hizmet ediyor mu?
İstenmeyen bir dosyayı geri almak istiyorsanız, bunu yapmadan önce dosyanın gerçekten korunması gereken yerel bir değişiklik içermediğinden emin olun. Örneğin yanlışlıkla değiştirilmiş bir log dosyasını son commit’teki hâline döndürmek için modern Git akışında şu komut kullanılabilir:
git restore --worktree debug.log
git status
Bu komut, belirtilen dosyanın çalışma ağacındaki değişikliğini geri alır. Dosyada korunması gereken bir bölüm varsa, önce dosyanın kopyasını almak veya ilgili satırları başka bir yere kaydetmek daha güvenlidir.
Yalnızca doğru parçaları stage edin
Dosyanın tamamını stage etmek yerine yalnızca doğru satırları seçmek istediğinizde git add -p kullanabilirsiniz. Git bu komutla değişiklikleri parçalara ayırır ve her parça için stage edilip edilmeyeceğini sorar.
git add -p config.py
git add -p README.md
Karşınıza çıkan parçalar için genellikle şu seçeneklerle karşılaşırsınız:
y: Gösterilen parçayı stage eder.n: Gösterilen parçayı stage etmez.s: Parçayı daha küçük parçalara bölmeyi dener.e: Parçayı elle düzenlemenizi sağlar.q: İşlemi sonlandırır.
Örneğin config.py içindeki doğru düzeltmeyi stage edip, aynı dosyada bulunan deneysel satırı dışarıda bırakabilirsiniz. Bu yöntem özellikle yanlış commit’te birden fazla bağımsız değişiklik biriktiğinde yararlıdır.
Bir dosyanın tamamının commit’e girmesi gerektiğinden eminseniz dosya adını doğrudan belirtebilirsiniz:
git add config.py
git add README.md
Ancak git add . komutu bu aşamada gereğinden geniş olabilir. Çalışma klasöründe oluşturulmuş geçici dosyaları, test çıktısını veya başka bir göreve ait değişiklikleri fark etmeden stage etme riski taşır.
Commit öncesinde mutlaka git diff --cached çalıştırın
Stage işlemi tamamlandıktan sonra yalnızca commit’e girecek içeriği kontrol edin:
git diff --cached
git status
git diff --cached, staging alanındaki değişiklikleri gösterir. Bu nedenle git diff ile aynı çıktıyı vermesi beklenmez: ilki commit’e hazır içeriği, ikincisi henüz stage edilmemiş içeriği gösterir.
Bu kontrol, yanlış dosyanın stage edilmesini önleyen en önemli güvenlik adımlarından biridir. Örneğin beklemediğiniz bir dosya çıktıda görünüyorsa commit oluşturmayın. Dosyayı staging alanından çıkarmak için şu komutu kullanabilirsiniz:
git restore --staged debug.log
git diff --cached
git status
Bu işlem debug.log dosyasını staging alanından çıkarır; dosyanın çalışma ağacındaki değişikliği otomatik olarak silmez. Böylece değişikliği daha sonra inceleme, saklama veya geri alma kararını ayrı verebilirsiniz.
Yeni ve temiz commit’i oluşturun
Staged içerik beklediğiniz hâle geldiyse yeni commit’i açık bir mesajla oluşturun:
git commit -m "Config ve dokümantasyon düzeltmelerini uygula"
git log --oneline --decorate -3
Beklenen geçmiş şu yapıya dönüşür:
A --- B --- YENİ
Eski HATALI commit’i artık aktif branch’in izlediği geçmişte görünmez; çünkü git reset --soft HEAD~1 branch’in ucunu HATALI yerine B commit’ine taşımıştır. Daha sonra oluşturulan YENİ commit’i de B’nin devamına eklenmiştir. Bu, hatalı commit nesnesinin her durumda anında yok olduğu anlamına gelmez; yalnızca aktif branch geçmişinin artık onu takip etmediği anlamına gelir. Eski commit’e ihtiyaç duyulursa ilerleyen kurtarma işlemlerinde reflog gibi araçlar yardımcı olabilir.
Bu akışın tamamı örnek olarak şöyle görünebilir:
git reset --soft HEAD~1
git reset
# Dosyaları düzenleyin
git diff
git add -p config.py
git add -p README.md
git diff --cached
git commit -m "Config ve dokümantasyon düzeltmelerini uygula"
git log --oneline --decorate -3
Git’i bağımsız pratiklerle öğrenirken bu tür komutları küçük deneme depolarında tekrar etmek, çalışma ağacı, staging alanı ve commit geçmişi arasındaki farkı görmeyi kolaylaştırır. video eğitim çalışma formatı da Git alıştırmalarını farklı yazılım konularındaki düzenli pratiklerle birlikte sürdürmek isteyenler için kullanılabilir bir öğrenme düzeni sunar.
git commit --amend ne zaman kullanılır?
git commit --amend, mevcut branch’in yalnızca son commit’ini yeni bir commit ile değiştirir. Yazım hatasını düzeltmek, unutulan bir dosyayı eklemek veya son commit’in içeriğini küçük ölçekte düzenlemek için kullanılabilir.
# Son commit'e unutulan dosyayı ekle
git add README.md
git commit --amend --no-edit
--no-edit, mevcut commit mesajını korur. Commit mesajını da değiştirmek isterseniz:
git add README.md
git commit --amend -m "Dokümantasyon düzeltmesini tamamla"
Bu komut, son commit’in üzerine yeni bir değişiklik eklemekten ziyade son commit’i değiştirir. Bu nedenle yalnızca son commit üzerinde çalışır. Daha eski bir commit’i düzenlemek için farklı bir geçmiş yeniden yazma akışı, örneğin etkileşimli rebase, gerekir.
Henüz paylaşılmamış bir branch üzerinde --amend kullanmak genellikle daha kolay yönetilir. Çünkü başka kişilerin yerel branch’leri eski commit kimliğine bağlı değildir. Buna karşılık commit uzak depoya gönderildiyse veya ekip arkadaşları tarafından çekildiyse, amend işlemi yeni bir commit kimliği üretir ve ortak geçmişin yeniden yazılmasını gerektirebilir. Bu durum, sonraki bölümde ele alınan revert yaklaşımının neden ekip ortamında çoğu zaman daha uygun olduğunu açıklar. Git commit dokümantasyonu da yayımlanmış bir commit üzerinde geçmişi yeniden yazmanın sonuçlarının anlaşılması gerektiğini belirtir.
Uzak Depoya Gönderilmiş veya Ekipçe Çekilmiş Commit’lerde Neden Revert Tercih Edilir?

Bir commit uzak depoya gönderilmişse veya ekip arkadaşları tarafından kendi çalışma kopyalarına çekilmişse, geçmişi geriye taşımak yerine çoğu durumda git revert <commit> kullanılır. Revert, eski commit’i branch geçmişinden silmeye çalışmaz; onun yaptığı değişikliklerin tersini uygulayan yeni bir commit oluşturur.
Örnek geçmiş şu olsun:
A --- B --- HATALI origin/main
ekip arkadaşlarının yerel kopyaları
Hatalı commit’in hash değerini önce log üzerinden bulun:
git log --oneline --decorate --graph -5
Örnek çıktı şöyle olabilir:
8f31c2a Hatalı yapılandırma değişikliği
52c6e10 Kullanıcı doğrulamasını ekle
1a4d9b7 İlk çalışan sürüm
Burada geri alınacak commit 8f31c2a ise çalışma ağacının temiz olduğunu kontrol ettikten sonra revert işlemini başlatın:
git status
git revert 8f31c2a
Git çoğu durumda otomatik bir commit mesajı hazırlar. Editörü kaydedip kapattığınızda yeni geri alma commit’i oluşur. İsterseniz commit mesajını komut satırında da belirtebilirsiniz:
git revert 8f31c2a -m "Hatalı yapılandırma değişikliğini geri al"
Burada dikkat edilmesi gereken nokta, -m seçeneğinin revert commit mesajı anlamına gelmemesidir. Birleştirme commit’lerinde ana parent seçmek için kullanılan özel bir seçenektir. Normal, tek ebeveynli bir commit’i geri alırken çoğunlukla yalnızca commit hash’i yeterlidir. Mesajı doğrudan belirtmek için --no-edit veya sonrasında normal commit mesaj düzenleme akışı tercih edilmelidir.
Revert tamamlandıktan sonra oluşan değişikliği inceleyin:
git diff HEAD~1 HEAD
git status
git log --oneline --decorate -4
Beklenen geçmiş şu şekle dönüşür:
A --- B --- HATALI --- REVERT
HATALI commit’i geçmişte görünmeye devam eder; fakat onun etkisini tersine çeviren REVERT commit’i branch’in en ucunda yer alır. Bu durum ekip açısından izlenebilirdir. Bir ekip üyesi log’a baktığında hangi değişikliğin sorunlu bulunduğunu ve ne zaman geri alındığını görebilir.
Değişiklik beklediğiniz gibiyse geri alma commit’ini uzak depoya gönderin:
git push origin main
Branch adınız main yerine develop, release veya başka bir ad olabilir. Push işleminden önce doğru branch üzerinde olduğunuzu kontrol etmek önemlidir:
git branch --show-current
git status
Revert sırasında çakışma çıkarsa ne yapılır?
Geri alınmak istenen commit’ten sonra aynı satırlar başka commit’lerde değiştirildiyse Git ters değişikliği otomatik uygulayamayabilir. Bu durumda işlem yarıda kalır ve çalışma ağacında çakışma işaretleri oluşabilir.
İlk adım, Git’in hangi dosyalarda sorun gördüğünü öğrenmektir:
git status
Çakışan dosyayı açıp şu işaretleri bulun:
<<<<<<< HEAD
mevcut branch içeriği
=======
revert işleminin uygulamaya çalıştığı içerik
>>>>>>> parent of 8f31c2a
Bu işaretler dosyanın kalıcı içeriğinin parçası değildir. Uygun satırları seçerek dosyayı manuel olarak düzeltin, işaretleri kaldırın ve ardından çözümü stage edin:
git add path/to/conflicted-file
git status
Git tüm çakışmaların çözüldüğünü gösteriyorsa revert işlemine devam edin:
git revert --continue
İşlem sırasında kararınızı değiştirdiyseniz veya çakışmayı çözmeden önce başlangıç durumuna dönmek istiyorsanız:
git revert --abort
git status
--abort, devam eden revert dizisini iptal edip işlem öncesindeki duruma dönmeyi amaçlar. --continue ise çakışmalar çözüldükten ve ilgili dosyalar stage edildikten sonra yarım kalan revert akışını tamamlar. Resmî Git açıklamasında bu seçenekler, başarısız bir revert sonrasında çözümün tamamlanması veya işlemin iptal edilmesi için tanımlanır. Git revert dokümantasyonu üzerinden kullanılan Git sürümünüzdeki ayrıntıları kontrol edebilirsiniz.
Ekipçe çekilmiş commit neden reset ile geri alınmamalı?
Diyelim ki ekipte üç kişi main branch’ini çekti ve herkesin yerel geçmişi A-B-HATALI noktasına ulaştı. Siz git reset --hard B uygulayıp uzak branch’i de force push ile B’ye taşımaya çalışırsanız, diğer kişilerin yerel branch’leri artık uzak branch’in gösterdiği geçmişle uyuşmayabilir.
Ekip arkadaşları yeni commit’lerini eski HATALI commit’in üzerine kurduysa, geçmiş yeniden yazıldığında onların commit’lerini yeniden düzenlemesi, branch’lerini güncellemesi veya kaybolmuş gibi görünen değişiklikleri kurtarması gerekebilir. Bu yalnızca teknik bir sorun değildir; aynı zamanda ekip iletişimi ve iş akışı sorunudur.
Revert yaklaşımında ise herkes aynı doğrusal geçmişi görür:
A --- B --- HATALI --- REVERT --- yeni geliştirme
Bu yapı, sorunlu değişikliğin etkisini kaldırırken geçmişte yaşanan olayı saklar. Daha sonra hatanın yalnızca bir bölümünü düzeltmek veya bazı parçalarını yeniden uygulamak gerektiğinde, revert commit’i inceleme için açık bir referans olarak kalır.
Force Push Ne Zaman Risklidir ve Daha Güvenli Seçenek Nedir?
Yerel branch geçmişini reset, rebase veya amend ile değiştirdiğinizde, uzak branch’teki geçmiş artık yerel branch’inizle aynı olmayabilir. Normal git push işlemi hızlı ileri alma koşulu sağlanmadığında bunu reddeder. Böyle bir durumda force push teknik olarak mümkün olabilir; ancak bu, uzak branch’in başka commit’lerle ilerlemiş olabileceği gerçeğini ortadan kaldırmaz.
git push --force, uzak branch’in ucunu yerel branch’inizin gösterdiği commit’e taşımaya zorlar. Bu sırada uzak depoda sizden sonra oluşmuş commit’ler varsa, bunların branch geçmişindeki erişilebilirliği kaybolabilir. Git dokümantasyonunda --force seçeneğinin commit’lerin uzak depoda kaybedilmesine yol açabileceği ve dikkatle kullanılması gerektiği açıkça belirtilir. Git push dokümantasyonu ayrıca force push işleminin uzak branch kuralları ve sunucu yapılandırmaları tarafından reddedilebileceğini belirtir.
git push --force ile git push --force-with-lease farkı
İki komut arasındaki temel fark, uzak branch’in beklenmedik biçimde ilerleyip ilerlemediğine karşı gösterilen kontroldür:
| Komut | Temel davranış | Risk profili |
|---|---|---|
git push --force |
Normal hızlı ileri alma kontrolünü aşarak uzak branch’i yerel geçmişle değiştirmeye çalışır. | Başkalarının yeni commit’lerini ezme riski yüksektir. |
git push --force-with-lease |
Uzak branch’in beklenen noktada olup olmadığını kontrol eder; beklenmeyen ilerleme varsa push işlemini reddedebilir. | Daha temkinlidir, fakat risksiz değildir. |
--force-with-lease, uzak branch’in siz son gördüğünüz noktadan farklı bir commit’e ilerlemiş olması durumunda işlemi durdurmayı amaçlar. Bu, başka bir ekip üyesinin araya giren commit’ini fark etmenizi sağlayabilir. Fakat yerel uzak-izleme bilgileriniz güncel değilse veya başka araçlar arka planda fetch yapıyorsa korumanın dayandığı bilgi beklediğiniz kadar güvenilir olmayabilir. Bu nedenle --force-with-lease “güvenli force push” olarak değil, --force seçeneğine göre daha kontrollü bir seçenek olarak düşünülmelidir.
Kişisel bir feature branch üzerinde, branch’in başka biri tarafından kullanılmadığını teyit ettikten ve yedek aldıktan sonra örnek kullanım şöyle olabilir:
git fetch origin
git branch backup/feature-before-rewrite
git log --oneline --decorate --all -8
git push --force-with-lease origin feature
Bu akıştaki git fetch origin uzak referansların durumunu görmenize yardımcı olur; git branch backup/feature-before-rewrite ise mevcut yerel konumu ayrı bir branch adıyla korur. Push hâlâ başarısız olabilir veya ekibin branch korumaları nedeniyle reddedilebilir. Bu bir hata değil, çoğu zaman koruyucu davranıştır.
Force push öncesi uygulanabilir kontrol listesi
- Branch kişisel mi, ortak mı? Kişisel bir deneme branch’i ile herkesin kullandığı
mainveyadevelopbranch’i aynı riskte değildir. - Yerel değişiklikleriniz korunuyor mu?
git statusve gerekirse geçici bir yedek branch ile çalışma durumunu güvenceye alın. - Uzak durum görüldü mü?
git fetch originçalıştırın; ardındangit log --oneline --decorate --allile uzak branch’in ilerleyip ilerlemediğini inceleyin. - Ekip onayı alındı mı? Ortak branch üzerinde geçmiş değiştirme planını push işleminden önce açıkça duyurun.
- Yedek branch oluşturuldu mu? Hem yerelde hem de ekip politikanız uygunsa uzak depoda geri dönüş noktası bırakın.
- İşlem sonrası bilgilendirme yapıldı mı? Ekip arkadaşlarına hangi branch’in, hangi commit aralığının ve neden değiştirildiğini bildirin.
Ortak branch’te amaç yalnızca yanlış değişikliği etkisiz hâle getirmekse force push yerine git revert daha uygun olabilir. Böylece branch geçmişi ileri doğru yeni bir commit ile ilerler ve ekip arkadaşlarının mevcut çalışma kopyaları daha az müdahale gerektirir.
Force push kaçınılmazsa, komutun kapsamını mümkün olduğunca dar tutun. Önce doğru branch’te olduğunuzu doğrulayın, uzak branch’in son durumunu kontrol edin, yedek oluşturun ve doğrudan --force yerine çoğu durumda --force-with-lease değerlendirin. Yine de bu seçenek, yanlış branch’e push etme, beklenmeyen yerel durum veya hatalı ekip koordinasyonu gibi riskleri ortadan kaldırmaz.
Yanlış Reset Sonrasında Kurtarma: Yedek Branch ve Reflog
git reset --hard sonrasında ilk yapılacak işlem yeni bir reset çalıştırmak değil, durumu dondurup teşhis etmektir. Yanlış commit’e dönmüş olabilirsiniz; ancak commit nesnesi ve ona işaret eden önceki branch konumu çoğu durumda hemen yok olmaz. Önceden oluşturulmuş bir yedek branch varsa kurtarma oldukça kolaydır. Yedek branch yoksa yerel reflog kayıtları, HEAD veya branch referansının daha önce hangi commit’lerde bulunduğunu görmenizi sağlar.
Bu süreçte temel sıra şöyledir: önce yedek branch, sonra teşhis, en son reset. Kurtarmaya çalışırken tekrar tekrar reset --hard kullanmak, hangi konumun doğru olduğunu daha da belirsiz hâle getirebilir.
Önceden oluşturulan yedek branch neden en güvenli ağdır?
Reset işleminden önce mevcut konumu ayrı bir branch ile işaretlemek, commit’e kalıcı ve okunabilir bir referans bırakır. Örneğin main branch’i üzerinde çalışırken geçmişi değiştirmeden önce şu komut çalıştırılabilir:
git switch main
git branch backup-before-reset
Bu komut yeni bir çalışma dalı oluşturur; dosyaları değiştirmez ve mevcut main branch’ini hareket ettirmez. Ardından yanlış bir işlem yapılırsa önceki commit’e doğrudan şu şekilde ulaşabilirsiniz:
git log --oneline --decorate --all
git switch backup-before-reset
git status
Beklenen etki, backup-before-reset branch’inin reset öncesindeki commit üzerinde kalmasıdır. Bu branch üzerinde dosyaları inceleyebilir, doğru commit’i doğrulayabilir ve gerekiyorsa asıl branch’i daha sonra bu konuma taşıyabilirsiniz.
Örneğin main branch’i yanlışlıkla geriye alındıysa ve yedek branch doğru commit’i gösteriyorsa:
git switch main
git reset --hard backup-before-reset
git log --oneline --decorate -3
git status
Bu işlem main branch’ini yedek branch’in işaret ettiği commit’e taşır ve çalışma ağacını da o commit’in içeriğiyle eşleştirir. Reset öncesinde henüz commit edilmemiş değişiklikler varsa, yedek branch yalnızca commit geçmişini korur; çalışma ağacındaki commit edilmemiş dosyaları otomatik olarak geri getirmeyebilir. Bu nedenle kurtarma öncesinde mevcut dosyaları ayrıca kopyalamak veya bir patch almak daha güvenlidir.
git status
git diff > mevcut-degisiklikler.patch
git diff --staged > index-degisiklikleri.patch
Bu dosyalar, kurtarma sırasında çalışma ağacını değiştirmeniz gerekirse elinizde ek bir güvenlik kopyası olmasını sağlar. Özellikle reset --hard komutu tracked dosyalardaki commit edilmemiş değişiklikleri çalışma ağacından çıkarabileceği için, korunması gereken bir değişiklik varsa önce kopya almak, commit oluşturmak veya uygun bir stash kullanmak gerekir.
Yedek branch yoksa reflog ile önceki commit’i bulma
Yedek branch oluşturulmadıysa sıradaki araç git reflog komutudur. Reflog, normal commit geçmişinden farklı olarak yerel depoda branch ve diğer referansların hangi commit’lerden geçtiğini kaydeder. Bu nedenle git log artık göstermese bile, reset öncesindeki commit reflog içinde görülebilir.
Önce HEAD hareketlerini listeleyin:
git reflog --date=local
Örnek bir çıktı şu yapıya sahip olabilir:
a1b2c3d HEAD@{0}: reset: moving to HEAD~1
f6e7d8c HEAD@{1}: commit: ödeme kontrolü eklendi
91ab234 HEAD@{2}: commit: sipariş doğrulaması eklendi
...
Burada HEAD@{0} mevcut konumu, HEAD@{1} ise reset işleminden hemen önceki HEAD konumunu temsil eder. Ancak yalnızca sıra numarasına güvenmek yerine commit mesajını, tarihini ve dosya içeriğini de kontrol edin:
git show --stat f6e7d8c
git show --summary f6e7d8c
git diff f6e7d8c..HEAD
Doğru commit’in f6e7d8c olduğunu doğruladıktan sonra, onu doğrudan kullanmak yerine önce bir kurtarma branch’i oluşturun:
git branch rescue f6e7d8c
git show --oneline --decorate rescue
git switch rescue
git status
git branch rescue f6e7d8c komutu rescue adında yeni bir branch oluşturur ve branch’i belirtilen commit’e bağlar. Çalışma ağacını tek başına değiştirmez. Bu, kurtarma sürecindeki en önemli güvenlik adımlarından biridir: Önce bulunan commit’i ayrı bir referansla korur, sonra ne yapılacağına karar verirsiniz.
İsterseniz reflog girdisinin kendisini de commit belirtimi olarak kullanabilirsiniz:
git branch rescue HEAD@{1}
git switch rescue
git log --oneline --decorate -5
Shell ortamlarında süslü parantezlerin yorumlanma ihtimaline karşı aşağıdaki biçim daha güvenli olabilir:
git branch rescue 'HEAD@{1}'
Branch’i kurtarılan commit’e geri taşımak
Kurtarma branch’inde doğru geçmişi bulduktan sonra iki temel seçeneğiniz vardır. İlk seçenek, kurtarılan commit üzerinde çalışmaya devam etmektir:
git switch rescue
git status
git log --oneline --decorate -5
Bu yaklaşım, asıl branch’i hemen değiştirmeden dosyaları test etmenizi sağlar. Uygulamanın çalıştığını, doğru dosyaların bulunduğunu ve yanlışlıkla başka bir commit’i kurtarmadığınızı kontrol edebilirsiniz.
İkinci seçenek, asıl branch’i kurtarılan commit’e taşımaktır:
git switch main
git reset --hard rescue
git status
git log --oneline --decorate -5
Buradaki reset --hard rescue komutu yalnızca main branch’inin işaret ettiği commit’i değiştirmez; çalışma ağacını da rescue branch’indeki içerikle eşleştirir. Bu nedenle çalışma ağacında korunması gereken yeni değişiklikler varsa önce git status ile kontrol edilmeli ve gerekiyorsa değişiklikler güvenli bir yere alınmalıdır.
Asıl branch’teki dosyaları değiştirmeden yalnızca commit içeriğini incelemek istiyorsanız git switch rescue yeterlidir. Başka bir commit’e geçip dosyaları değiştirme ihtiyacı varsa, geçici bir branch oluşturmak da daha kontrollü olabilir:
git switch -c inceleme rescue
git diff main..inceleme
git status
Bu sayede main branch’i olduğu gibi kalır; kurtarılan geçmiş üzerinde inceleme ve test yapılır. Özellikle ekip deposunda çalışıyorsanız, asıl branch’i değiştirmeden önce bu yöntem daha az risklidir.
Reflog hangi durumda işe yarar, hangi durumda yetmez?
Reflog, yerel referans hareketlerini inceleyen bir mekanizmadır. Kendi bilgisayarınızdaki HEAD, main veya başka bir branch’in daha önce gösterdiği commit’leri bulmaya yardımcı olur. Ancak reflog, uzak depoyla paylaşılan ortak bir geçmiş değildir. Başka bir ekip üyesinin bilgisayarındaki reflog kayıtlarını kendi yerel deponuzdan göremezsiniz.
Bu nedenle uzak depoda silinmiş bir commit’in reflog tarafından otomatik olarak geri getirilmesini beklemeyin. Commit başka bir yerel branch’te, tag’de, remote-tracking branch’te veya ekip üyesinin klonunda hâlâ bulunuyorsa kurtarılabilir. Fakat yalnızca uzak depoda bulunmuş ve hiçbir yerel referansta kalmamış bir commit için kendi reflog’unuz doğrudan çözüm olmayabilir.
Reflog kayıtları da sınırsız süreyle saklanmaz. Git’in varsayılan yapılandırmasında erişilebilir reflog girdileri daha uzun süre, artık erişilemeyen commit’lere işaret eden girdiler ise daha kısa süre tutulacak şekilde temizlenebilir; gerçek süreler depo yapılandırmasına ve garbage collection süreçlerine bağlıdır. Bu yüzden yanlış reset’i fark ettiğinizde beklemeden kurtarma branch’i oluşturmak önemlidir. Reflog kapsamı ve saklama davranışı için Git reflog dokümantasyonu incelenebilir.
Reflog’da uygun kayıt bulunamıyorsa, depoda artık herhangi bir branch veya tag tarafından işaret edilmeyen nesneleri araştırmak için ileri düzeyde git fsck kullanılabilir. Ancak bu yöntem reflog kadar okunabilir değildir ve commit’in garbage collection tarafından temizlenmemiş olması gerekir. Öncelik her zaman yedek branch, reflog ve mevcut remote-tracking referanslarını kontrol etmek olmalıdır.
Kurtarma kontrol listesi
- Önce yedek branch: Mevcut doğru konumu biliyorsanız hemen
git branch backup-before-resetile koruyun. - Sonra teşhis:
git status,git log --oneline --decorate --allvegit reflogçıktısını inceleyin. - Mevcut değişiklikleri koruyun: Gerekirse dosyaları kopyalayın, patch alın veya güvenli bir commit/stash oluşturun.
- Doğru commit’i doğrulayın:
git show <hash>vegit diffile içerik ve kapsamı kontrol edin. - Kurtarma branch’i oluşturun:
git branch rescue <reflog-hash>komutuyla bulunan commit’i sabitleyin. - En son reset: Doğru konum kesinleştiğinde asıl branch’i
git resetveya çalışma ağacını da eşitlemeniz gerekiyorsagit reset --hard rescueile taşıyın.
Sık Sorulan Sorular
Uzak depoya gönderilmemiş son commit’i silmeden nasıl geri alabilirim?
Commit’i geçmişten kaldırmadan değişiklikleri yeniden düzenlemek için git reset --soft HEAD~1 kullanabilirsiniz. Bu işlem son commit’i geri alır, ancak değişiklikleri staged durumda bırakır. Dosyaları düzenleyip yeni bir commit oluşturabilirsiniz. Commit’in kendisini koruyup yalnızca ters yönde yeni bir commit eklemek istiyorsanız git revert HEAD tercih edilir.
Ekip arkadaşlarım commit’i çektiyse git reset kullanabilir miyim?
Kullanabilirsiniz; ancak paylaşılan branch’in geçmişini değiştireceğiniz için doğrudan uygulamak risklidir. Ekip arkadaşlarınız commit’i çektiyse onların yerel geçmişi sizin resetlediğiniz geçmişten ayrılabilir. Paylaşılan branch’lerde genellikle git revert <commit> ile yeni bir geri alma commit’i oluşturmak daha güvenlidir. Reset zorunluysa ekip iletişimi, yedek branch ve kontrollü push planı olmadan ilerlemeyin.
git reset --hard sonrası kaybolan değişiklikler reflog ile kurtarılabilir mi?
Commit edilmiş değişiklikler çoğu durumda reflog’daki önceki commit konumundan kurtarılabilir. Ancak yalnızca çalışma ağacında bulunan ve hiç commit edilmemiş değişiklikler reflog tarafından garanti edilmez; reflog commit edilmiş referans hareketlerini izler. Bu nedenle git reset --hard öncesinde commit edilmemiş dosyaları kopyalamak, patch almak veya uygun bir stash oluşturmak gerekir.
git push --force ile git push --force-with-lease arasındaki fark nedir?
git push --force, uzak branch’in beklenmeyen şekilde ilerleyip ilerlemediğini güvenli biçimde kontrol etmeden geçmişi değiştirebilir ve başkalarının commit’lerini ezebilir. git push --force-with-lease ise uzak branch’in beklediğiniz konumda olup olmadığını kontrol eder; uzak referans beklenenden farklıysa push işlemini reddeder. Bu, riski azaltır ancak ekip iletişiminin veya yedek almanın yerine geçmez.
Yanlış commit’i geri alırken revert işlemi çakışma oluşturursa ne yapmalıyım?
Önce Git’in çakışan dosyaları bildirdiği alanları git status ile listeleyin. Dosyalardaki conflict işaretlerini düzenleyip doğru içeriği bıraktıktan sonra dosyaları staged duruma alın ve git revert --continue çalıştırın. İşlemi tamamen iptal etmek isterseniz git revert --abort kullanabilirsiniz. Çakışmanın nedenini anlamadan dosyaları topluca silmek veya yeni bir reset çalıştırmak, geri alma işleminin amacını bozabilir.
Git’te güvenli kurtarma alışkanlığı, komutu ezberlemekten çok branch’in nerede olduğunu, commit’in kimler tarafından görüldüğünü ve çalışma ağacında korunması gereken değişiklik bulunup bulunmadığını doğru değerlendirmeye dayanır.