Dapatkah saya melakukan pengembalian sebagian di GIT

156

Apakah mungkin untuk mengembalikan hanya satu file atau perubahan tertentu dalam file di multi file commit?

Kisah lengkap saya melakukan banyak file. Sejumlah komit kemudian seseorang yang akan tetap tanpa nama (JACK !!!) menyalin file ke dalam repositori dan melakukan beberapa file, menimpa beberapa perubahan yang saya lakukan. Saya ingin mengembalikan satu file yang menjadi musnah atau lebih baik lagi, masuk dan kembalikan dua perubahan dalam file itu. Ini harus berupa komit pengembalian yang terpisah karena ditarik dan didorong.

Kopling
sumber
Brian membuatku di jalur yang benar. Saya akhirnya menggunakan git add --patch kemudian menggunakan fungsi edit dalam tambalan untuk mendapatkan apa yang saya inginkan.
Kopling
2
Saya sangat terlambat ke permainan, tapi saya pikir saya menemukan jawaban yang "benar" .
ntc2
@ ntc2 Anehnya, jawaban yang diterima bekerja untuk saya jauh lebih baik daripada yang Anda tautkan - itu menciptakan konflik gabungan untuk saya selesaikan, bukannya hanya gagal menerapkan tambalan.
Iiridayn
@ liridayn Apakah Anda membaca seluruh jawaban saya? Di bagian "variasi" saya mengklaim bahwa menambahkan --3wayhasil dalam konflik gabungan bukan kegagalan untuk menerapkan tambalan.
ntc2

Jawaban:

204

Anda dapat mengembalikan komit tanpa membuat yang baru dengan menambahkan opsi '--tidak ada komit'. Ini meninggalkan semua file yang dikembalikan di area pementasan. Dari sana, saya akan melakukan soft reset dan menambahkan perubahan yang saya inginkan. Sebagai contoh alur kerja:

git revert <sha-of-bad-commit> --no-commit
git reset   // This gets them out of the staging area
<edit bad file to look like it should, if necessary>
git add <bad-file>
git checkout . // This wipes all the undesired reverts still hanging around in the working copy
git commit
bobDevil
sumber
42
Setelah soft reset, Anda juga dapat melakukan git add -puntuk memulai sesi interaktif yang memungkinkan Anda untuk menambahkan potongan file secara selektif, bukan seluruh file. (Ada juga git reset -pbeberapa perubahan unstage yang selektif. Baik untuk diketahui, tetapi mungkin bukan yang Anda inginkan dalam skenario ini.)
Stéphan Kochen
1
Ini persis apa yang saya cari: Kembalikan ke copy pekerjaan, pilih bakhil interaktif, komit. Anda pantas untuk berciuman dengan pria besar dan asin untuk itu: *
das_weezul
Solusi lain terinspirasi oleh satu ini akan revert, reset, stash -p(simpanan "membatalkan bahwa saya tidak ingin sebenarnya make"), addsisanya,commit
Cyril Chapon
82

Anda dapat secara interaktif menerapkan versi file yang lama menggunakan checkoutperintah.

Misalnya, jika Anda tahu di COMMITmana kode untuk menambahkan kembali dihapus, Anda dapat menjalankan perintah berikut:

git checkout -p COMMIT^ -- FILE_TO_REVERT

Git akan meminta Anda untuk menambahkan kembali bakhil yang hilang dari versi file saat ini. Anda bisa menggunakan euntuk membuat tambalan perubahan sebelum menerapkannya kembali.

cmcginty
sumber
Sangat berguna jika Anda ingin mengembalikan sebagian file saja! Pada dasarnya, untuk mendapatkan potongan dari kepala,git checkout -p path/to/file
falstaff
40

Anda bisa secara manual memeriksa konten lama dan bagus dari file yang ingin Anda kembalikan menggunakan git checkout. Misalnya, jika Anda ingin kembali my-important-fileke versi yang ada di versi abc123, Anda dapat melakukannya

git checkout abc123 -- my-important-file

Sekarang Anda memiliki konten my-important-filekembali yang lama, dan bahkan dapat mengeditnya jika Anda mau, dan komit seperti biasa untuk membuat komit yang akan mengembalikan perubahan yang dibuatnya. Jika hanya ada beberapa bagian dari komit yang ingin Anda kembalikan, gunakan git add -puntuk memilih hanya beberapa bakhil dari tambalan yang Anda lakukan.

Brian Campbell
sumber
19
Ini bukan revert, Anda hanya mengambil kembali file versi lama. Sebuah tepat revertakan menghapus buruk komit modifikasi dalam file, bahkan jika itu telah beberapa kali diubah sejak buruk komit, dan Anda tidak ingin kehilangan mereka modifikasi.
Totor
2
Totor, lihat jawabanku. Anda dapat menggunakan '-p' untuk menyimpan modifikasi. Jawabannya sangat dekat dengan yang ini sebenarnya.
cmcginty
1
Atau Anda dapat menggabungkan ini menjadi git checkout -p.
Léo Lam
31

Saya menemukan cara untuk melakukan ini di milis Git:

git show <commit> -- <path> | git apply --reverse

Sumber: http://git.661346.n2.nabble.com/Revert-a-single-commit-in-a-single-file-td6064050.html#a6064406

Variasi

Perintah itu gagal (tidak menyebabkan perubahan) jika tambalan tidak berlaku bersih, tetapi dengan --3wayAnda malah mendapatkan konflik yang kemudian dapat Anda atasi secara manual (dalam hal ini jawaban Casey mungkin lebih praktis):

git show <commit> -- <path> | git apply --reverse --3way

Anda juga dapat menggunakan ini untuk mengembalikan sebagian komit, misalnya:

git log -S<string> --patch | git apply --reverse

untuk mengembalikan file dengan perubahan yang cocok <string>di komit apa pun. Ini adalah persis apa yang saya butuhkan dalam kasus penggunaan saya (beberapa komit terpisah memperkenalkan perubahan serupa ke file yang berbeda, bersama dengan perubahan file lain dengan cara yang tidak berhubungan yang saya tidak ingin kembalikan).

Jika Anda telah diff.noprefix=truemengatur di Anda ~/.gitconfigmaka Anda perlu menambahkan -p0ke git applyperintah, misalnya

git show <commit> -- <path> | git apply -p0 --reverse
ntc2
sumber
Jawaban ini jauh lebih baik daripada yang diterima: "lebih baik, masuk dan kembalikan dua perubahan dalam file itu".
ditulis ulang
Saya ingin mengembalikan hanya sebagian dari komit, jadi saya lakukan: (1) git show ... > foo.txt (2) edit foo.txtuntuk menghapus diff yang saya inginkan untuk tidak mengembalikan (3) git apply --reverse foo.txt untuk mengembalikan diff yang masih tercantum dalam foo.txt.
cxw
Menambahkan --binary --full-index ke git show part juga bisa menjadi variasi yang berguna
Laurynas Biveinis