Git'te bir dosyanın çalışan kopya değişikliklerini geri al?


1632

Son işlemden sonra, çalışma kopyamdaki bir grup dosyayı değiştirdim, ancak bu dosyalardan birindeki değişiklikleri, en son taahhütle aynı duruma sıfırlarken olduğu gibi geri almak istiyorum.

Ancak, sadece o dosyanın tek başına çalışan kopya değişikliklerini geri almak istiyorum.

Bunu nasıl yaparım?

Yanıtlar:


2212

Kullanabilirsiniz

git checkout -- file

Bunu --(nimrodm tarafından önerildiği gibi) olmadan yapabilirsiniz , ancak dosya adı bir şube veya etiket (veya başka bir düzeltme tanımlayıcısı) gibi görünüyorsa, karışabilir, bu nedenle kullanmak --en iyisidir.

Ayrıca bir dosyanın belirli bir sürümünü de kontrol edebilirsiniz:

git checkout v1.2.3 -- file         # tag v1.2.3
git checkout stable -- file         # stable branch
git checkout origin/master -- file  # upstream master
git checkout HEAD -- file           # the version from the most recent commit
git checkout HEAD^ -- file          # the version before the most recent commit

34
HEAD ve HEAD ^ arasındaki fark nedir?
hasen

62
HEAD, geçerli dalda en son taahhüttür ve HEAD ^, geçerli daldakinden önceki taahhüttür. Açıkladığınız durum için git checkout HEAD - dosya adını kullanabilirsiniz.
Paul

16
Kısaca "git checkout sha-reference - filename" (burada sha-referansı, herhangi bir biçimde (şube, etiket, ebeveyn, vb.) Bir taahhüdün sha'sına bir referanstır)
Lakshman Prasad

29
NOT: Dosya önceden hazırlanmışsa, önce onu sıfırlamanız gerekir. git reset HEAD <filename> ; git checkout -- <filename>
Olie

14
@gwho Evet, HEAD^^en son 2 taahhüt HEAD^^^için veya 3 geri ödeme için yapabilirsiniz . Ayrıca kullanabilirsiniz HEAD~2, ya HEAD~3da daha fazla taahhütte bulunmak istiyorsanız daha uygun hale gelirken HEAD^2, "bu taahhüdün ikinci ebeveyni" anlamına gelir; birleştirme taahhütleri nedeniyle, bir taahhüdün birden fazla önceki taahhüdü olabilir, bu nedenle HEAD^bir sayı ile bu ebeveynlerden hangisini seçerken, HEAD~bir sayı ile her zaman ilk ebeveyni seçer, ancak bu sayı geri döner. Daha git help rev-parsefazla bilgi için bakınız.
Brian Campbell

139

Sadece kullan

git checkout filename

Bu, dosya adını geçerli daldaki en son sürümle değiştirir.

UYARI: Yaptığınız değişiklikler atılacak - yedek tutulmuyor.


22
@duckx, şube adlarını dosya adlarından ayırmaktır. derseniz git checkout xx bir dal adı yanısıra dosya adı olur, ben emin varsayılan davranış ne olduğunu değilim ama git şube x geçmek istediğiniz üstlenecek düşünüyorum. Kullandığınızda --, aşağıdakilerin dosya adları olduğunu söylüyorsunuz.
hasen

1
Bunu temizlediğin için teşekkürler. herkes sadece size örnek gösterdiğinde ne anlama geldiğini bildiğini varsayar. ve bu da kolayca google bir şey değil.
Patoshi シ ト シ

1
Cevabı kaldırmak için düzenlendi gibi görünüyor --. Hala doğru olsa da, @ hasen'in de belirttiği gibi, dosya adı ve şube adları arasında bir belirsizlik varsa, burada çok istenmeyen davranışlarla karşılaşabilirsiniz!
BrainSlugs83

2
Olmadan --, hoş ve kolay olduğu gibi seviyorum . Dosya adlarını kullanarak şubeleri adlandırdığınızda, bir yerde kötü düşünmek gerekir ...
Marco Faustinelli

133
git checkout <commit> <filename>

Bunu bugün kullandım çünkü drupal 6.10'a yükselttiğimde favicon'umun birkaç işlemden önce üzerine yazıldığını fark ettim, bu yüzden geri almak zorunda kaldım. İşte yaptığım şey:

git checkout 088ecd favicon.ico

1
Tonlarca "git log --stat" çıktısını atmak dışında (önceden silinen bir dosyanın) taahhüdünü nasıl alabilirim?
Alex

4
IMO, gits günlüğünü taramak ve doğru dosyayı bulmak için komut satırı aracılığıyla biraz zor. Sourcetreeapp.com
neoneye

6
git log --oneline <filename>size daha kompakt bir günlük verir ve yalnızca belirli dosyadaki değişiklikleri içerir
rjmunro

1
alternatif olarak kullanabilirsinizgit reflog <filename>
ygesher

70

Dosyanız zaten değiştirilmişse (dosya düzenlendikten sonra bir git add vb. Yaptığınızda gerçekleşir) değişikliklerinizi iptal etmek için.

kullanım

git reset HEAD <file>

Sonra

git checkout <file>

Henüz sahnelenmemişse,

git checkout <file>

2
Bu kabul edilenlerden daha yararlı oldu haha. Hangi değişikliklerin yapıldığını ve nelerin yapılmadığını unutmak kolaydır, bu yüzden sıfırlama yardımcı oldu. Daha önce "git reset --hard" ı da denememe rağmen, "git reset HEAD" ın yaptığı şeyi yapmadı. Nedenini merak ediyorum?
Arman Bimatov

20

Önceki taahhüdün bu dosyadaki değişikliklerini geri almak istiyorsanız şunu deneyebilirsiniz:

git checkout branchname^ filename

Bu, dosyayı son işlemden önceki gibi teslim eder. Birkaç işlem daha geri gitmek isterseniz branchname~ngösterimi kullanın .


Bu, değişiklikleri taahhütten kaldırmaz, fark sadece HEAD'deki sürüme uygulanır.
FernandoEscher

2
Doğru olsa da, orijinal poster sadece son kopyadaki değişiklikleri geri almak değil, çalışma kopyası değişikliklerini (bence) geri almak istedi. Orijinal posterin sorusu biraz belirsizdi, bu yüzden karışıklığı anlayabiliyorum.

belki OP'nin kullanımı değil, ama şubemin ustasının kopyasıyla nasıl yazılacağını arıyordum - bu değiştirilirken oldukça iyi çalışıyorbranchname^
Alex

15

Git bash ile yaptım:

(use "git checkout -- <file>..." to discard changes in working directory)

  1. Git durumu. [Yani bir dosya wad değiştirildi gördük.]
  2. git checkout - index.html [index.html dosyasında değiştim:
  3. git durumu [artık bu değişiklikler kaldırıldı]

resim açıklamasını buraya girin


8

Her zaman bununla kafam karışıyor, işte bir hatırlatma testi örneği; diyelim ki bashtest etmek için şu komut dosyasına sahibiz git:

set -x
rm -rf test
mkdir test
cd test
git init
git config user.name test
git config user.email test@test.com
echo 1 > a.txt
echo 1 > b.txt
git add *
git commit -m "initial commit"
echo 2 >> b.txt
git add b.txt
git commit -m "second commit"
echo 3 >> b.txt

Bu noktada, değişiklik önbellekte gösterilmez, yani git status:

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   b.txt

no changes added to commit (use "git add" and/or "git commit -a")

Bu noktadan itibaren yaparsak git checkout, sonuç şudur:

$ git checkout HEAD -- b.txt
$ git status
On branch master
nothing to commit, working directory clean

Bunun yerine git reset, sonuç:

$ git reset HEAD -- b.txt
Unstaged changes after reset:
M   b.txt
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   b.txt

no changes added to commit (use "git add" and/or "git commit -a")

Yani, bu durumda - değişiklikler sahnelenmezse, değişikliklerin üzerine git resetyazarken fark etmez git checkout.


Şimdi, yukarıdaki komut dosyasındaki son değişikliğin sahnelendiğini / önbelleğe alındığını, yani aynı zamanda git add b.txt yani sonunda varsayalım.

Bu durumda, git statusbu noktada:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   b.txt

Bu noktadan itibaren yaparsak git checkout, sonuç şudur:

$ git checkout HEAD -- b.txt
$ git status
On branch master
nothing to commit, working directory clean

Bunun yerine git reset, sonuç:

$ git reset HEAD -- b.txt
Unstaged changes after reset:
M   b.txt
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   b.txt

no changes added to commit (use "git add" and/or "git commit -a")

Dolayısıyla, bu durumda - değişiklikler aşamalı ise git reset, temel olarak işaretlenmemiş değişikliklere aşamalı değişiklikler yapar - ancak git checkoutdeğişikliklerin tamamen üzerine yazılır.


7

Bu yanıtlar, aynı veya birden çok klasördeki (veya dizinlerdeki) belirli dosyalarda bulunan yerel değişiklikleri geri almak için gereken komut içindir. Bu yanıt, özellikle bir kullanıcının birden fazla dosyaya sahip olduğu ancak kullanıcının tüm yerel değişiklikleri geri almak istemediği soruları ele alır:

bir veya daha fazla dosyanız varsa git checkout -- file, konumlarının her birini boşlukla ayrılmış olarak listeleyerek bu dosyaların her birine aynı komutu ( ) uygulayabilirsiniz :

git checkout -- name1/name2/fileOne.ext nameA/subFolder/fileTwo.ext

name1 / name2 / fileOne.ext nameA / subFolder / fileTwo.ext arasındaki boşluğa dikkat edin

Aynı klasördeki birden çok dosya için:

Belirli bir dizindeki tüm dosyalar için değişiklikleri atmanız gerekirse, git kontrolünü aşağıdaki gibi kullanın:

git checkout -- name1/name2/*

Yukarıdaki yıldız işareti, name1 / name2 altındaki bu konumdaki tüm dosyaları geri alma hilesini yapar.

Ve benzer şekilde, aşağıdakiler birden çok klasör için tüm dosyalardaki değişiklikleri geri alabilir:

git checkout -- name1/name2/* nameA/subFolder/*

yine yukarıdaki ad1 / ad2 / * adA / altKlasör / * arasındaki boşluğa dikkat edin.

Not: name1, name2, nameA, subFolder - bu örnek klasör adlarının tümü, söz konusu dosyaların bulunduğu klasör veya paketi gösterir.


5

Dosyalarımı SHA kimliğini kullanarak geri yüklüyorum git checkout <sha hash id> <file name>



2

Taahhütünüzü henüz itmediyseniz veya başka bir şekilde paylaşmadıysanız:

git diff --stat HEAD^...HEAD | \
fgrep filename_snippet_to_revert | cut -d' ' -f2 | xargs git checkout HEAD^ --
git commit -a --amend

0

Zaten taahhüt edilmişse, dosyadaki değişikliği geri alabilir ve tekrar kaydedebilirsiniz, ardından son taahhüdüyle yeni taahhüdü ezebilirsiniz.


1
Kullanılacak belirli komutlar eklemek orijinal postere ve gelecekteki ziyaretçilere yardımcı olacaktır.
Adrian

0

Neden bilmiyorum ama kodumu girmeye çalıştığımda, bir görüntü olarak geliyor.

resim açıklamasını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.