Bagaimana cara mengekstrak satu file (atau perubahan ke file) dari git simpanan?

776

Saya ingin tahu apakah mungkin untuk mengekstrak satu file atau berbeda dari file dari git simpanan tanpa menghentikan perubahan set off.

Mungkinkah ada yang bisa memberikan beberapa saran / ide tentang ini?

Danny
sumber

Jawaban:

1132

Pada halaman manual git stash Anda dapat membaca (di bagian "Diskusi", tepat setelah deskripsi "Opsi") bahwa:

Sebuah simpanan diwakili sebagai komit yang pohonnya mencatat keadaan direktori kerja, dan induk pertamanya adalah komit di HEAD ketika simpanan dibuat.

Jadi Anda bisa memperlakukan simpanan (mis. Simpanan stash@{0}pertama / teratas) sebagai gabungan komit, dan gunakan:

$ git diff stash@{0}^1 stash@{0} -- <filename>

Penjelasan: stash@{0}^1berarti induk pertama dari simpanan yang diberikan, yang sebagaimana dinyatakan dalam penjelasan di atas adalah komit di mana perubahan disimpan. Kami menggunakan bentuk "git diff" (dengan dua komit) karena stash@{0}/ refs/stashadalah gabungan komit, dan kami harus memberi tahu git induk yang ingin kami bedakan. Lebih samar:

$ git diff stash@{0}^! -- <filename>

seharusnya juga berfungsi (lihat manual git rev-parse untuk penjelasan tentang rev^!sintaks, di bagian "Menentukan rentang").

Demikian juga, Anda dapat menggunakan checkout git untuk memeriksa satu file dari simpanan:

$ git checkout stash@{0} -- <filename>

atau untuk menyimpannya di bawah nama file lain:

$ git show stash@{0}:<full filename>  >  <newfile>

atau

$ git show stash@{0}:./<relative filename> > <newfile>

( perhatikan bahwa di sini <nama file lengkap> adalah nama path lengkap file relatif ke direktori teratas proyek (pikirkan: relatif terhadap stash@{0})).


Anda mungkin perlu melindungi stash@{0}dari ekspansi shell, yaitu menggunakan "stash@{0}"atau 'stash@{0}'.

Jakub Narębski
sumber
8
Ini sangat keren ... Saya tidak begitu mengerti bagaimana simpanan bekerja sampai saya membaca jawaban Anda (yang membawa saya ke penambahan git-checkout). Saya benar-benar tidak mengerti bahwa, ketika Anda melakukan simpanan, git menyimpan DUA komit - satu untuk kondisi indeks dan satu untuk status copy pekerjaan yang merupakan gabungan antara indeks dan KEPALA asli. Ini menjelaskan pohon-pohon aneh yang pernah saya lihat ketika saya memvisualisasikan repositori dengan "gitk --all" ketika ada simpanan.
Pat Notz
4
Sebagian besar saya menemukan aplikasi checkout git menjadi cara terbaik untuk mencapai apa yang ingin saya lakukan. Namun saya ingin tahu dan memeriksa git checkouthalaman manual. Itu tidak dapat menjatuhkan file ke lokasi lain. Ada referensi untuk ini di: stackoverflow.com/questions/888414/…
Danny
84
$ git checkout simpanan @ {0} - <filename> sangat berguna, terima kasih
gravitasi
43
Perhatikan bahwa git checkoutpendekatan ini menyalin file yang tepat dari simpanan - tidak menggabungkannya dengan apa yang ada di direktori kerja Anda git stash apply. (Jadi jika Anda memiliki perubahan dari pangkalan tempat penyimpanan dibuat, mereka akan hilang).
peterflynn
4
Perhatikan bahwa untuk git stash applymenggabungkan perubahan dalam file yang telah dimodifikasi di pohon kerja sejak file disimpan, file di pohon kerja harus dipentaskan. Agar penggabungan otomatis berfungsi, file yang sama tidak dapat dimodifikasi baik di copy yang berfungsi maupun di copy yang akan disatukan. Akhirnya, berlaku simpanan tidak menghapus item dari simpanan seperti git stash popakan.
Ville
46

Jika Anda menggunakan git stash applyalih-alih git stash pop, itu akan menerapkan simpanan ke pohon kerja Anda tetapi tetap menyimpan simpanan.

Dengan ini selesai, Anda bisa add/ commitfile yang Anda inginkan dan kemudian mengatur ulang perubahan yang tersisa.

Tim Henigan
sumber
2
Pop simpanan tertentu: git stash pop stash@{0}(daftar perubahan yang disembunyikan: git stash list)
MrYoshiji
Jika file lain dalam simpanan menyebabkan konflik penggabungan, git tidak membiarkan saya melakukan pada file yang saya inginkan :(
cambunctious
33

Ada cara mudah untuk mendapatkan perubahan dari cabang apa pun, termasuk simpanan:

$ git checkout --patch stash@{0} path/to/file

Anda dapat menghilangkan spesifikasi file jika Anda ingin menambal di banyak bagian. Atau hilangkan tambalan (tetapi bukan path) untuk mendapatkan semua perubahan pada satu file. Ganti 0dengan nomor simpanan dari git stash list, jika Anda memiliki lebih dari satu. Perhatikan bahwa ini seperti diff, dan menawarkan untuk menerapkan semua perbedaan di antara cabang-cabang. Untuk mendapatkan perubahan dari hanya satu komit / simpanan, lihat git cherry-pick --no-commit.

Walf
sumber
Apakah ini menyalin file persis dari simpanan, atau menggabungkan? Dalam kasus salinan, jika Anda memiliki perubahan sejak simpanan dibuat, mereka akan hilang.
Danijel
2
@Danijel Baca git help checkout. --patchtidak penggabungan interaktif, Ini berlaku apa pun yang Anda menyetujui dalam shell (atau apa pun yang Anda simpan jika Anda memilih untuk emenambal patch). Path sendiri akan menimpa file, seperti yang saya tulis, "semua perubahan".
Walf
1
sedikit perbaikan: git config --global alias.applydiffat '!git checkout --patch "$1" -- $(git diff --name-only "$1"^ "$1")' - maka melakukan git applydiffat stash@{4}hanya menggunakan file yang berubah antara simpanan dan induknya.
Tandai
25

Jawaban singkat

Untuk melihat seluruh file: git show stash@{0}:<filename>

Untuk melihat perbedaannya: git diff stash@{0}^1 stash@{0} -- <filename>

Luboš Turek
sumber
1
Saya tidak berpikir dia peduli dengan melihat simpanan untuk file tertentu - hanya muncul file itu.
Amalgovinus
1
Ini yang saya cari. Kemudian Anda dapat menggantinya diffdengan difftoolmenggunakan diff eksternal favorit Anda.
Peet Brits
19
$ git checkout stash@{0} -- <filename>

Catatan:

  1. Pastikan Anda memberi spasi setelah "-" dan parameter nama file

  2. Ganti nol (0) dengan nomor simpanan spesifik Anda. Untuk mendapatkan daftar simpanan, gunakan:

    git stash list
    

Berdasarkan jawaban Jakub Narębski - Versi lebih pendek

Ram
sumber
11

Anda bisa mendapatkan diff untuk simpanan dengan " git show stash@{0}" (atau berapa pun jumlah simpanan itu; lihat "daftar simpanan git"). Sangat mudah untuk mengekstrak bagian diff untuk satu file.

Nathan Kitchen
sumber
2
Masih lebih sederhana untuk pikiran seperti saya: gunakan git show stashuntuk menunjukkan simpanan paling atas (biasanya satu-satunya yang Anda miliki). Demikian pula Anda dapat menunjukkan perbedaan antara cabang Anda saat ini dan simpanan dengan git diff head stash.
Dizzley
5

Konsep paling sederhana untuk dipahami, meskipun mungkin bukan yang terbaik, adalah Anda memiliki tiga file yang diubah dan Anda ingin menyimpan satu file.

Jika Anda git stashmenyembunyikan semua, git stash applyuntuk mengembalikannya lagi dan kemudian git checkout f.cpada file yang dimaksud untuk meresetnya secara efektif.

Saat Anda ingin melepaskan file run, lakukan git reset --harddan kemudian jalankan git stash applylagi, manfaatkan fakta yang git stash applytidak menghapus perbedaan dari tumpukan simpanan.

Philluminati
sumber
1

Jika file simpanan perlu bergabung dengan versi saat ini, maka gunakan cara-cara sebelumnya menggunakan diff. Kalau tidak, Anda dapat menggunakan git popuntuk melepaskan mereka, git add fileWantToKeepuntuk pementasan file Anda, dan melakukan git stash save --keep-index, untuk menyimpan semuanya kecuali apa yang ada di atas panggung. Ingatlah bahwa perbedaan cara ini dengan yang sebelumnya adalah bahwa "muncul" file dari simpanan. Jawaban sebelumnya tetap git checkout stash@{0} -- <filename>sesuai dengan kebutuhan Anda.

Hola Kedelai Edu Feliz Navidad
sumber
0

Gunakan berikut ini untuk menerapkan perubahan pada file simpanan ke pohon kerja Anda.

git diff stash^! -- <filename> | git apply

Ini umumnya lebih baik daripada menggunakan git checkoutkarena Anda tidak akan kehilangan perubahan yang Anda buat ke file sejak Anda membuat simpanan.

cambunctious
sumber