it-swarm-id.com

Bagaimana memulihkan simpanan yang dijatuhkan di Git?

Saya sering menggunakan git stash dan git stash pop untuk menyimpan dan mengembalikan perubahan di pohon kerja saya. Kemarin saya memiliki beberapa perubahan pada pohon kerja saya yang saya simpanan dan muncul, dan kemudian saya membuat lebih banyak perubahan pada pohon kerja saya. Saya ingin kembali dan meninjau perubahan simpanan kemarin, tetapi git stash pop tampaknya menghapus semua referensi untuk komit terkait.

Saya tahu bahwa jika saya menggunakan git stash maka .git/refs/stash berisi referensi dari komit yang digunakan untuk membuat simpanan. Dan . Git/logs/refs/simpanan berisi seluruh simpanan. Tetapi referensi itu hilang setelah git stash pop. Saya tahu bahwa komit masih dalam repositori saya di suatu tempat, tetapi saya tidak tahu apa itu.

Apakah ada cara mudah untuk memulihkan referensi simpanan kemarin?

Perhatikan bahwa ini tidak penting bagi saya hari ini karena saya memiliki cadangan harian dan dapat kembali ke pohon kerja kemarin untuk mendapatkan perubahan saya. Saya bertanya karena pasti ada cara yang lebih mudah!

1508
Greg Hewgill

Setelah Anda mengetahui hash simpanan yang Anda jatuhkan, Anda dapat menerapkannya sebagai simpanan:

git stash apply $stash_hash

Atau, Anda dapat membuat cabang terpisah untuknya

git branch recovered $stash_hash

Setelah itu, Anda dapat melakukan apa pun yang Anda inginkan dengan semua alat normal. Setelah selesai, cukup cabut cabang itu.

Menemukan hash

Jika Anda baru saja mengeluarkannya dan terminal masih terbuka, Anda akan masih memiliki nilai hash dicetak oleh git stash pop di layar (terima kasih, Dolda).

Jika tidak, Anda dapat menemukannya menggunakan ini untuk Linux, Unix atau Git Bash untuk Windows:

git fsck --no-reflog | awk '/dangling commit/ {print $3}'

... atau menggunakan Powershell untuk Windows:

git fsck --no-reflog | select-string 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];}

Ini akan menunjukkan kepada Anda semua komit di ujung grafik komit Anda yang tidak lagi dirujuk dari cabang atau tag mana pun - setiap komit yang hilang, termasuk setiap komit simpanan yang pernah Anda buat, akan berada di suatu tempat di grafik itu.

Cara termudah untuk menemukan simpanan komit yang Anda inginkan mungkin dengan meneruskan daftar itu ke gitk:

gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )

... atau lihat jawaban dari emragins jika menggunakan Powershell untuk Windows.

Ini akan meluncurkan browser repositori yang menunjukkan kepada Anda setiap komit di repositori , terlepas dari apakah itu dapat dijangkau atau tidak.

Anda dapat mengganti gitk di sana dengan sesuatu seperti git log --graph --oneline --decorate jika Anda lebih suka grafik yang bagus di konsol daripada aplikasi GUI yang terpisah.

Untuk melihat komit simpanan, cari pesan komit dari formulir ini:

WIP aktif somebranchcommithash Beberapa pesan komit lama

Catatan : Pesan komit hanya akan berada dalam formulir ini (dimulai dengan "WIP aktif") jika Anda tidak memberikan pesan saat Anda melakukannya git stash.

2430

Jika Anda tidak menutup terminal, lihat saja output dari git stash pop dan Anda akan memiliki ID objek dari simpanan yang jatuh. Biasanya terlihat seperti ini:

$ git stash pop
[...]
Dropped refs/[email protected]{0} (2ca03e22256be97f9e40f08e6d6773c7d41dbfd1)

(Perhatikan bahwa git stash drop juga menghasilkan baris yang sama.)

Untuk mendapatkan simpanan itu kembali, jalankan git branch tmp 2cae03e, dan Anda akan mendapatkannya sebagai cabang. Untuk mengonversikan ini menjadi simpanan, jalankan:

git stash apply tmp
git stash

Memiliki itu sebagai cabang juga memungkinkan Anda untuk memanipulasinya secara bebas; misalnya, untuk mengambil atau menggabungkannya.

666
Dolda2000

Hanya ingin menyebutkan tambahan ini untuk solusi yang diterima. Tidak segera jelas bagi saya saat pertama kali saya mencoba metode ini (mungkin seharusnya), tetapi untuk menerapkan simpanan dari nilai hash, cukup gunakan "git stash apply":

$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219

Ketika saya masih baru di git, ini tidak jelas bagi saya, dan saya mencoba berbagai kombinasi "git show", "git apply", "patch", dll.

253
Wade

Untuk mendapatkan daftar simpanan yang masih dalam repositori Anda, tetapi tidak dapat dijangkau lagi:

git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk --grep=WIP

Jika Anda memberi judul untuk simpanan Anda, ganti "WIP" di -grep=WIP di akhir perintah dengan bagian dari pesan Anda, mis. -grep=Tesselation.

Perintah ini mengambil "WIP" karena pesan komit default untuk simpanan adalah dalam bentuk WIP on mybranch: [previous-commit-hash] Message of the previous commit.

82
Senthil A Kumar

Saya baru saja membangun sebuah perintah yang membantu saya menemukan simpanan simpanan yang hilang:

for ref in `find .git/objects | sed -e 's#.git/objects/##' | grep / | tr -d /`; do if [ `git cat-file -t $ref` = "commit" ]; then git show --summary $ref; fi; done | less

Ini mencantumkan semua objek di pohon .git/objek, mencari objek yang bertipe commit, lalu memperlihatkan ringkasan masing-masing. Dari titik ini itu hanya masalah melihat melalui komitmen untuk menemukan "WIP pada pekerjaan: 6a9bb2" yang sesuai (("pekerjaan" adalah cabang saya, 619bb2 adalah komitmen baru-baru ini).

Saya perhatikan bahwa jika saya menggunakan "git stash apply" daripada "git stash pop" saya tidak akan memiliki masalah ini, dan jika saya menggunakan "git stash save message" maka komit mungkin lebih mudah mencari.

Pembaruan: Dengan ide Nathan, ini menjadi lebih pendek:

for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less
71
Greg Hewgill

git fsck --unreachable | grep commit harus menunjukkan sha1, meskipun daftar yang dikembalikan mungkin cukup besar. git show <sha1> akan muncul jika komit yang Anda inginkan.

git cherry-pick -m 1 <sha1> akan menggabungkan komit ke cabang saat ini.

38
Nathan Jones

Jika Anda ingin menyembunyikan simpanan yang hilang, Anda harus mencari hash simpanan yang hilang terlebih dahulu.

Seperti yang disarankan Aristoteles Pagaltzis, git fsck akan membantu Anda.

Secara pribadi saya menggunakan alias log-all saya yang menunjukkan kepada saya setiap commit (recoverable commit) untuk memiliki pandangan yang lebih baik tentang situasi:

git log --graph --decorate --pretty=oneline --abbrev-commit --all $(git fsck --no-reflogs | grep commit | cut -d' ' -f3)

Anda dapat melakukan pencarian lebih cepat jika Anda hanya mencari pesan "WIP aktif".

Setelah Anda tahu sha1 Anda, Anda cukup mengubah reflog simpanan Anda untuk menambahkan simpanan lama:

git update-ref refs/stash ed6721d

Anda mungkin lebih suka memiliki pesan terkait sehingga -m

git update-ref -m "$(git log -1 --pretty=format:'%s' ed6721d)" refs/stash ed6721d

Dan Anda bahkan ingin menggunakan ini sebagai alias:

restash = !git update-ref -m $(git log -1 --pretty=format:'%s' $1) refs/stash $1
27
Colin Hebert

Setara dengan Windows PowerShell menggunakan gitk:

gitk --all $(git fsck --no-reflog | Select-String "(dangling commit )(.*)" | %{ $_.Line.Split(' ')[2] })

Mungkin ada cara yang lebih efisien untuk melakukan ini dalam satu pipa, tetapi ini berhasil.

22
emragins

Saya menyukai pendekatan Aristoteles, tetapi tidak suka menggunakan GITK ... karena saya terbiasa menggunakan GIT dari baris perintah.

Sebagai gantinya, saya mengambil komit yang menggantung dan mengeluarkan kode ke file DIFF untuk ditinjau di editor kode saya.

git show $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' ) > ~/stash_recovery.diff

Sekarang Anda dapat memuat file diff/txt yang dihasilkan (yang ada di folder rumah Anda) ke dalam editor txt Anda dan melihat kode aktual dan SHA yang dihasilkan.

Maka gunakan saja

git stash apply ad38abbf76e26c803b27a6079348192d32f52219
16
Shaheen Ghiassy

Di OSX dengan git v2.6.4, saya hanya menjalankan git stash drop secara tidak sengaja, kemudian saya menemukannya dengan menelusuri langkah-langkah di bawah

Jika Anda tahu nama simpanan maka gunakan:

$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show | grep -B 6 -A 2 <name of the stash>

jika tidak, Anda akan menemukan ID dari hasil secara manual dengan:

$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show

Kemudian ketika Anda menemukan commit-id tekan saja simpanan git berlaku {commit-id}

Semoga ini bisa membantu seseorang dengan cepat

12
Can Tecim

Mengapa orang menanyakan pertanyaan ini? Karena mereka belum tahu atau mengerti reflog.

Sebagian besar jawaban untuk pertanyaan ini memberikan perintah panjang dengan opsi yang hampir tidak akan diingat oleh siapa pun. Jadi orang-orang masuk ke pertanyaan ini dan menyalin apa pun yang mereka pikir mereka butuhkan dan segera melupakannya setelah itu.

Saya akan menyarankan semua orang dengan pertanyaan ini untuk hanya memeriksa reflog (git reflog), tidak lebih dari itu. Setelah Anda melihat daftar semua komitmen itu, ada ratusan cara untuk mengetahui komitmen apa yang Anda cari dan untuk mengambilnya atau membuat cabang darinya. Dalam prosesnya Anda akan belajar tentang reflog dan opsi yang berguna untuk berbagai perintah dasar git.

11
RobbyD

Anda dapat membuat daftar semua komitmen yang tidak dapat dijangkau dengan menuliskan perintah ini di terminal -

git fsck --unreachable

Periksa hash komit yang tidak dapat dijangkau -

git show hash

Akhirnya berlaku jika Anda menemukan barang simpanan -

git stash apply hash
10
Vivek Kumar

Saya ingin menambahkan solusi yang diterima cara lain yang baik untuk melalui semua perubahan, ketika Anda tidak memiliki gitk tersedia atau tidak ada X untuk output.

git fsck --no-reflog | awk '/dangling commit/ {print $3}' > tmp_commits

for h in `cat tmp_commits`; do git show $h | less; done

Kemudian Anda mendapatkan semua diff untuk hash yang ditampilkan satu demi satu. Tekan 'q' untuk mendapatkan perbedaan berikutnya.

10
Phil

Saya tidak bisa mendapatkan jawaban untuk bekerja di Windows dalam jendela perintah sederhana (Windows 7 dalam kasus saya). awk, grep dan Select-string tidak dikenali sebagai perintah. Jadi saya mencoba pendekatan yang berbeda:

  • jalankan pertama: git fsck --unreachable | findstr "commit"
  • salin output ke notepad
  • temukan ganti "komit yang tidak terjangkau" dengan start cmd /k git show

akan terlihat seperti ini:

start cmd /k git show 8506d235f935b92df65d58e7d75e9441220537a4 start cmd /k git show 44078733e1b36962571019126243782421fcd8ae start cmd /k git show ec09069ec893db4ec1901f94eefc8dc606b1dbf1 start cmd /k git show d00aab9198e8b81d052d90720165e48b287c302e

  • simpan sebagai file .bat dan jalankan
  • script akan membuka banyak jendela perintah, menunjukkan setiap komit
  • jika Anda menemukan yang Anda cari, jalankan: git stash apply (your hash)

mungkin bukan solusi terbaik, tetapi berhasil untuk saya

9
kromakollision

Jawaban yang diterima oleh Aristoteles akan menunjukkan semua komitmen yang dapat dicapai, termasuk komitmen yang tidak bersifat simpanan. Untuk menyaring suara:

git fsck --no-reflog | \
awk '/dangling commit/ {print $3}' | \
xargs git log --no-walk --format="%H" \
  --grep="WIP on" --min-parents=3 --max-parents=3

Ini hanya akan mencakup komit yang memiliki persis 3 induk komit (yang akan dimiliki simpanan), dan yang pesannya mencakup "WIP aktif".

Perlu diingat, bahwa jika Anda menyimpan simpanan Anda dengan pesan (mis. git stash save "My newly created stash"), ini akan menggantikan pesan "WIP pada ..." default.

Anda dapat menampilkan informasi lebih lanjut tentang setiap komit, mis. tampilkan pesan komit, atau sampaikan ke git stash show:

git fsck --no-reflog | \
awk '/dangling commit/ {print $3}' | \
xargs git log --no-walk --format="%H" \
  --grep="WIP on" --min-parents=3 --max-parents=3 | \
xargs -n1 -I '{}' bash -c "\
  git log -1 --format=medium --color=always '{}'; echo; \
  git stash show --color=always '{}'; echo; echo" | \
less -R
9
Brad Feehan

Memulihkannya dengan menggunakan langkah-langkah berikut:

  1. Identifikasi kode hash simpanan yang dihapus:

    gitk --all $ (git fsck --no-reflog | awk '/ menggantung komit/{print $ 3}')

  2. Cherry Pick the Stash:

    git cherry-pick -m 1 $ stash_hash_code

  3. Selesaikan Konflik jika ada yang menggunakan:

    git mergetool

Selain itu Anda mungkin mengalami masalah dengan pesan komit jika Anda menggunakan gerrit. Harap simpan perubahan Anda sebelum mengikuti alternatif berikut:

  1. Gunakan hard reset untuk komit sebelumnya dan kemudian komit perubahan ini.
  2. Anda juga dapat menyimpan perubahan, rebase, dan komitmen ulang.
4
Abhijeet

Yang saya cari di sini adalah bagaimana mengembalikan simpanan, terlepas dari apa yang telah saya periksa. Secara khusus, saya telah menyembunyikan sesuatu, kemudian memeriksa versi yang lebih lama, lalu mengeluarkannya, tetapi simpanan tersebut adalah larangan pada titik waktu sebelumnya, sehingga simpanan hilang; Saya tidak bisa melakukan git stash untuk mendorongnya kembali ke stack. Ini bekerja untuk saya:

$ git checkout somethingOld
$ git stash pop
...
nothing added to commit but untracked files present (use "git add" to track)
Dropped refs/[email protected]{0} (27f6bd8ba3c4a34f134e12fe69bf69c192f71179)
$ git checkout 27f6bd8ba3c
$ git reset HEAD^    # Make the working tree differ from the parent.
$ git stash # Put the stash back in the stack.
Saved working directory and index state WIP on (no branch): c2be516 Some message.
HEAD is now at c2be516 Some message.
$ git checkout somethingOld # Now we are back where we were.

Dalam retrospeksi, saya seharusnya menggunakan git stash apply bukan git stash pop. Saya sedang melakukan bisect dan memiliki sedikit tambalan yang ingin saya terapkan pada setiap langkah bisect. Sekarang saya melakukan ini:

$ git reset --hard; git bisect good; git stash apply
$ # Run tests
$ git reset --hard; git bisect bad; git stash apply
etc.
4
Ben