Membatalkan modifikasi salinan dari satu file di Git?

1634

Setelah komit terakhir, saya memodifikasi banyak file dalam copy pekerjaan saya, tetapi saya ingin membatalkan perubahan ke salah satu file tersebut, seperti di reset ke keadaan yang sama dengan komit terbaru.

Namun, saya hanya ingin membatalkan perubahan copy pekerjaan hanya dari satu file saja, tidak ada yang lain dengan itu.

Bagaimana aku melakukan itu?

Hasen
sumber

Jawaban:

2215

Kamu bisa menggunakan

git checkout -- file

Anda dapat melakukannya tanpa --(seperti yang disarankan oleh nimrodm), tetapi jika nama file terlihat seperti cabang atau tag (atau pengenal revisi lainnya), itu mungkin membingungkan, jadi menggunakan-- yang terbaik.

Anda juga dapat melihat versi file tertentu:

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
Brian Campbell
sumber
34
apa perbedaan antara KEPALA dan KEPALA ^?
hasen
62
HEAD adalah komit terbaru di cabang saat ini, dan HEAD ^ adalah komit sebelum itu di cabang saat ini. Untuk situasi yang Anda jelaskan, Anda bisa menggunakan git checkout HEAD - nama file.
Paul
16
Singkatnya "git checkout sha-reference - filename" di mana sha-reference adalah referensi ke sha dari commit, dalam bentuk apa pun (cabang, tag, induk, dll.)
Lakshman Prasad
29
CATATAN: Jika file sudah dipentaskan, Anda harus mengatur ulang, terlebih dahulu. git reset HEAD <filename> ; git checkout -- <filename>
Olie
14
@ gw, Ya, Anda bisa melakukannya HEAD^^untuk 2 komit dari yang terbaru, atau HEAD^^^untuk 3 komit. Anda juga dapat menggunakan HEAD~2, atau HEAD~3, yang menjadi lebih nyaman jika Anda ingin melakukan lebih banyak komit, sementara itu HEAD^2berarti "induk kedua dari komit ini"; karena gabungan komit, komit dapat memiliki lebih dari satu komit sebelumnya, sehingga dengan HEAD^nomor memilih yang mana dari orangtua tersebut, sementara dengan HEAD~angka selalu memilih orangtua pertama tetapi jumlah komit kembali. Lihat git help rev-parseuntuk lebih jelasnya.
Brian Campbell
139

Gunakan saja

git checkout filename

Ini akan mengganti nama file dengan versi terbaru dari cabang saat ini.

PERINGATAN: perubahan Anda akan dibuang - tidak ada cadangan yang disimpan.

nimrodm
sumber
22
@duckx itu untuk mendamaikan nama cabang dari nama file. jika Anda mengatakan git checkout xdan x kebetulan merupakan nama cabang dan juga nama file, saya tidak yakin apa perilaku defaultnya tetapi saya pikir git akan menganggap Anda ingin beralih ke cabang x. Ketika Anda menggunakan --Anda mengatakan bahwa yang berikut adalah nama file.
Hasen
1
Terima kasih sudah membereskannya. semua orang menganggap Anda tahu apa - artinya ketika mereka menunjukkan kepada Anda contoh. dan itu bukan sesuatu yang Anda dapat dengan mudah juga google.
Patoshi パ ト シ
1
Sepertinya jawabannya diedit untuk menghapusnya --. Meskipun masih benar, seperti yang ditunjukkan @hasen, jika ada ambiguitas antara nama file dan nama cabang, Anda mungkin berakhir dengan perilaku yang sangat tidak diinginkan di sini!
BrainSlugs83
2
Saya suka apa adanya, tanpa --, enak dan mudah. Ketika Anda memberi nama cabang menggunakan nama file, pasti ada pemikiran buruk di suatu tempat ...
Marco Faustinelli
133
git checkout <commit> <filename>

Saya menggunakan ini hari ini karena saya menyadari bahwa favicon saya telah ditimpa beberapa komit yang lalu ketika saya meningkatkan ke drupal 6.10, jadi saya harus mendapatkannya kembali. Inilah yang saya lakukan:

git checkout 088ecd favicon.ico
neoneye
sumber
1
Bagaimana saya mendapatkan komit (dari file yang sebelumnya dihapus) kecuali dari gulir melempar ton output "git log --stat"?
Alex
4
IMO agak sulit melalui commandline untuk memindai melalui log gits dan menemukan file yang tepat. Ini jauh lebih mudah dengan aplikasi GUI, seperti sourcetreeapp.com
neoneye
6
git log --oneline <filename>akan memberi Anda log yang lebih ringkas, dan hanya menyertakan perubahan pada file tertentu
rjmunro
1
sebagai alternatif, Anda dapat menggunakangit reflog <filename>
ygesher
70

Jika file Anda sudah dipentaskan (terjadi ketika Anda melakukan git add dll setelah file diedit) untuk menghapus tahapan perubahan Anda.

Menggunakan

git reset HEAD <file>

Kemudian

git checkout <file>

Jika belum dipentaskan, gunakan saja

git checkout <file>
thanikkal
sumber
2
Ini lebih bermanfaat daripada yang diterima haha. Sangat mudah untuk melupakan perubahan apa yang telah dilakukan dan apa yang belum, jadi mengatur ulang membantu. Walaupun saya juga mencoba "git reset --hard" sebelumnya, itu tidak melakukan apa yang "git reset HEAD" lakukan. Kenapa ya?
Arman Bimatov
20

Jika Anda ingin membatalkan perubahan komit sebelumnya pada satu file itu, Anda dapat mencoba ini:

git checkout branchname^ filename

Ini akan memeriksa file seperti sebelum komit terakhir. Jika Anda ingin kembali melakukan beberapa komitmen, gunakan branchname~nnotasi.

sykora
sumber
Ini tidak akan menghapus perubahan dari komit, itu hanya akan menerapkan diff ke versi di HEAD.
FernandoEscher
2
Meskipun benar, poster aslinya hanya ingin mengembalikan modifikasi copy pekerjaannya (saya pikir), bukan mengembalikan perubahan dari komit terakhir. Pertanyaan poster asli sedikit tidak jelas, jadi saya bisa mengerti kebingungannya.
mungkin bukan penggunaan OP, tapi saya sedang mencari cara menimpa cabang saya dengan salinan master - ini bekerja cukup baik ketika menggantibranchname^
Alex
15

Saya telah selesai melalui git bash:

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

  1. Status git. [Jadi kita telah melihat satu file yang dimodifikasi.]
  2. git checkout - index.html [saya telah mengubah file index.html:
  3. status git [sekarang perubahan itu dihapus]

masukkan deskripsi gambar di sini

Siwa
sumber
8

Saya selalu bingung dengan ini, jadi ini adalah test case pengingat; katakanlah kita memiliki bashskrip ini untuk diuji git:

set -x
rm -rf test
mkdir test
cd test
git init
git config user.name test
git config user.email [email protected]
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

Pada titik ini, perubahan tidak dilakukan dalam cache, demikian git statusjuga:

$ 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")

Jika dari titik ini, kita lakukan git checkout, hasilnya adalah ini:

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

Jika sebaliknya kita lakukan git reset, hasilnya adalah:

$ 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")

Jadi, dalam hal ini - jika perubahan tidak dilakukan, git resettidak ada bedanya, sambil git checkoutmenimpa perubahan.


Sekarang, katakanlah bahwa perubahan terakhir dari skrip di atas dipentaskan / di-cache, artinya kita juga melakukannya git add b.txtdi akhir.

Dalam hal ini, git statuspada titik ini adalah:

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

    modified:   b.txt

Jika dari titik ini, kita lakukan git checkout, hasilnya adalah ini:

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

Jika sebaliknya kita lakukan git reset, hasilnya adalah:

$ 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")

Jadi, dalam hal ini - jika perubahan dipentaskan, git resetpada dasarnya akan membuat perubahan bertahap menjadi perubahan yang tidak dipentaskan - sementara git checkoutakan menimpa perubahan sepenuhnya.

sdaau
sumber
7

Jawaban ini untuk perintah yang diperlukan untuk membatalkan perubahan lokal yang ada di beberapa file spesifik di folder yang sama atau lebih dari satu (atau direktori). Jawaban ini secara khusus menjawab pertanyaan di mana pengguna memiliki lebih dari satu file tetapi pengguna tidak ingin membatalkan semua perubahan lokal:

jika Anda memiliki satu file atau lebih, Anda dapat menerapkan perintah yang sama ( git checkout -- file) untuk masing-masing file tersebut dengan mendaftar setiap lokasi mereka dipisahkan oleh ruang seperti pada:

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

perhatikan ruang di atas antara name1 / name2 / fileOne.ext nameA / subFolder / fileTwo.ext

Untuk banyak file dalam folder yang sama:

Jika Anda perlu membuang perubahan untuk semua file di direktori tertentu, gunakan checkout git sebagai berikut:

git checkout -- name1/name2/*

Tanda bintang di atas melakukan trik membatalkan semua file di lokasi itu di bawah name1 / name2.

Dan, sama halnya hal berikut ini dapat membatalkan perubahan di semua file untuk beberapa folder:

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

lagi-lagi ingat ruang antara name1 / name2 / * nameA / subFolder / * di atas.

Catatan: name1, name2, nameA, subFolder - semua nama folder contoh ini menunjukkan folder atau paket tempat file tersebut berada.

Nirmal
sumber
5

Saya mengembalikan file saya menggunakan id SHA, Apa yang saya lakukan adalah git checkout <sha hash id> <file name>

Beto
sumber
3

Bagi saya hanya ini yang berhasil

git checkout -p filename

masukkan deskripsi gambar di sini

Ramesh Bhupathi
sumber
2

Jika Anda belum mendorong atau membagikan komitmen Anda:

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

Jika sudah dikomit, Anda bisa mengembalikan perubahan untuk file dan komit lagi, lalu squash komit baru dengan komit terakhir.

Gina
sumber
1
Menambahkan perintah khusus untuk digunakan akan membantu poster asli dan pengunjung masa depan.
Adrian
0

Saya tidak tahu mengapa, tetapi ketika saya mencoba memasukkan kode saya, itu muncul sebagai gambar.

masukkan deskripsi gambar di sini

Gene
sumber