git'te tek bir dosyayı önceki bir sürüme geri döndürme

Bir dosya üzerinde farklı işlemlerden geçmenin bir yolu var mı? Diyelim ki bir dosyayı 5 kez değiştirdim ve zaten işledikten ve bir depoya ittikten sonra 2. değişikliğe geri dönmek istiyorum.

Anladığım kadarıyla tek yol çok sayıda şube bulundurmak, doğru mu anladım? Eğer haklıysam, birkaç gün içinde yüzlerce şubem olacak, bu yüzden muhtemelen gerçekten anlamıyorum.

Biri bunu açıklığa kavuşturabilir mi lütfen?

Çözüm

Ne yapmak istediğimizin niteliksel bir tanımıyla başlayalım (bunların çoğu Ben Straub'un cevabında belirtilmiştir). Beş tanesi belirli bir dosyayı değiştiren bir dizi değişiklik yaptık ve dosyayı önceki sürümlerden birine geri döndürmek istiyoruz. Her şeyden önce, git tek tek dosyalar için sürüm numaralarını tutmaz. Sadece içeriği izler - bir commit, bazı meta verilerle (örneğin commit mesajı) birlikte çalışma ağacının anlık görüntüsüdür. Dolayısıyla, istediğimiz dosyanın sürümünün hangi commit'te olduğunu bilmemiz gerekir. Bunu öğrendikten sonra, dosyayı o duruma geri döndüren yeni bir commit yapmamız gerekir. (Geçmişle uğraşamayız, çünkü bu içeriği zaten ittik ve geçmişi düzenlemek diğer herkesi karıştırır).

Öyleyse doğru taahhüdü bulmakla başlayalım. Verilen dosya(lar) üzerinde değişiklik yapan commitleri çok kolay bir şekilde görebilirsiniz:

git log path/to/file

Eğer commit mesajlarınız yeterince iyi değilse ve her committe dosyaya ne yapıldığını görmeniz gerekiyorsa, -p/--patch seçeneğini kullanın:

git log -p path/to/file

Ya da gitk'in grafiksel görünümünü tercih ederseniz

gitk path/to/file

Bunu gitk'i başlattıktan sonra görünüm menüsünden de yapabilirsiniz; bir görünüm için seçeneklerden biri dahil edilecek yolların bir listesidir.

Her iki şekilde de, istediğiniz dosyanın sürümüyle birlikte commit'in SHA1'ini (hash) bulabileceksiniz. Şimdi tek yapmanız gereken şu:

# get the version of the file from the given commit
git checkout  path/to/file
# and commit this modification
git commit

(Checkout komutu önce dosyayı dizine okur, ardından çalışma ağacına kopyalar, bu nedenle işlemeye hazırlanırken dizine eklemek için git add kullanmanıza gerek yoktur).

Dosyanızın basit bir geçmişi yoksa (örneğin yeniden adlandırmalar ve kopyalar), VonC'nin mükemmel yorumuna bakın. git`, hız pahasına bu tür şeyleri daha dikkatli aramaya yönlendirilebilir. Eğer geçmişin basit olduğundan eminseniz, uğraşmanıza gerek yok.

Yorumlar (11)

Git, dosya sürümleri açısından düşünmez. Git'teki bir sürüm, tüm ağacın anlık görüntüsüdür.

Bu göz önüne alındığında, gerçekten istediğiniz şey, çoğu dosyanın en son içeriğine sahip olan, ancak bir dosyanın içeriğinin 5 işlem öncesiyle aynı olduğu bir ağaçtır. Bu, eskilerin üzerine yeni bir commit şeklinde olacak ve ağacın en son sürümü istediğiniz içeriğe sahip olacaktır.

Tek bir dosyayı 5 commit öncesine geri döndürecek tek satırlık bir çözüm var mı bilmiyorum, ama şu çözüm işe yarayacaktır: master~5 dosyasını kontrol et, dosyayı başka bir yere kopyala, master dosyasını kontrol et, dosyayı geri kopyala, sonra commit et.

Yorumlar (2)

İstediğiniz değişiklikleri geri alan bir diff alabilir ve bunu işleyebilirsiniz.

Örneğin, from..to aralığındaki değişiklikleri geri almak istiyorsanız, aşağıdakileri yapın

git diff to..from > foo.diff  # get a reverse diff
patch < foo.diff
git commit -a -m "Undid changes from..to".
Yorumlar (5)