Pertanyaan Bagaimana cara memulihkan simpanan yang jatuh di Git?


Saya sering menggunakannya git stash dan git stash pop untuk menyimpan dan mengembalikan perubahan di pohon kerja saya. Kemarin saya memiliki beberapa perubahan di pohon kerja saya yang saya simpan dan pincang, dan kemudian saya membuat lebih banyak perubahan pada pohon kerja saya. Saya ingin kembali dan meninjau perubahan yang disembunyikan kemarin, tapi git stash pop muncul untuk menghapus semua referensi ke commit terkait.

Saya tahu bahwa jika saya menggunakannya git stash kemudian .git / refs / simpanan berisi referensi dari komit yang digunakan untuk membuat simpanan. Dan .git / logs / refs / simpanan berisi seluruh simpanan. Tapi referensi itu hilang git stash pop. Saya tahu bahwa komit itu masih ada di repositori saya di suatu tempat, tetapi saya tidak tahu apa itu.

Apakah ada cara mudah untuk memulihkan referensi komitmen simpanan kemarin?

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


1331
2017-09-18 01:59


asal


Jawaban:


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

Jika tidak, Anda dapat menemukannya menggunakan ini untuk Linux dan Unix:

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

dan untuk Windows:

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

Ini akan menunjukkan kepada Anda semua commit di ujung grafik komit Anda yang tidak lagi direferensikan dari cabang atau tag apa pun - setiap komit yang hilang, termasuk setiap simpanan commit yang pernah Anda buat, akan ada di suatu tempat dalam grafik itu.

Cara termudah untuk menemukan simpanan yang Anda inginkan adalah mungkin untuk meneruskan daftar itu gitk:

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

Ini akan meluncurkan browser repositori yang menunjukkan Anda setiap komit dalam repositori yang pernah ada, terlepas dari apakah itu bisa 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 melalui aplikasi GUI yang terpisah.

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

WIP aktif somebranch: commithash Beberapa pesan commit lama

Catatan: Pesan commit hanya akan ada dalam formulir ini (dimulai dengan "WIP on") jika Anda tidak memberikan pesan ketika Anda melakukannya git stash.

Setelah Anda mengetahui hash dari komitmen yang Anda inginkan, Anda dapat menerapkannya sebagai simpanan:

git stash apply $ stash_hash

Atau Anda dapat menggunakan menu konteks di gitk untuk membuat cabang untuk setiap komitmen yang tidak dapat dijangkau yang Anda minati. Setelah itu, Anda dapat melakukan apa pun yang Anda inginkan dengan semua alat normal. Setelah selesai, buang saja ranting-ranting itu lagi.


2151
2017-09-18 11:38



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

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

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

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

git stash apply tmp
git stash

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


597
2017-10-21 03:13



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

$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219

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


231
2018-03-03 20:28



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 dalam pohon git / objek, menempatkan yang bertipe komit, kemudian menunjukkan ringkasan masing-masing. Dari titik ini, hanya masalah mencari komitmen untuk menemukan "WIP on work" yang tepat: 6a9bb2 "(" kerja "adalah cabang saya, 619bb2 adalah komitmen baru).

Saya perhatikan bahwa jika saya menggunakan "git simpanan berlaku" daripada "git simpanan pop" saya tidak akan memiliki masalah ini, dan jika saya menggunakan "git simpanan simpan pesan"maka komit itu mungkin lebih mudah ditemukan.

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

68
2017-09-18 02:10



Untuk mendapatkan daftar simpanan yang masih ada di 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 pada simpanan Anda, ganti "WIP" di -grep=WIP di bagian akhir perintah dengan bagian dari pesan Anda, mis. -grep=Tesselation.

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


56
2018-05-04 06:42



git fsck --unreachable | grep commit harus menunjukkan sha1, meskipun daftar itu kembali mungkin cukup besar. git show <sha1> akan menunjukkan jika itu adalah komitmen yang Anda inginkan.

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


36
2017-09-18 02:08



Jika Anda ingin menyimpan simpanan yang hilang, Anda harus menemukan potongan simpanan Anda yang hilang terlebih dahulu.

Seperti Aristoteles Pagaltzis menyarankan a git fsck akan membantu Anda.

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

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

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

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

git update-ref refs/stash ed6721d

Anda mungkin lebih suka memiliki pesan yang terkait jadi a -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

23
2018-06-23 14:20



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

Sebagai gantinya, saya mengambil commit yang menggantung dan menampilkan 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 (di folder rumah Anda) ke dalam editor txt Anda dan melihat kode aktual dan menghasilkan SHA.

Kemudian gunakan saja

git stash apply ad38abbf76e26c803b27a6079348192d32f52219

15
2018-01-07 20:17



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

Jika Anda tahu nama simpanannya, 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 id-komit hanya memukul simpanan git berlaku {commit-id}

Semoga ini bisa membantu seseorang dengan cepat


12
2018-06-09 13:19



Windows PowerShell setara 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 melakukan pekerjaan.


11
2018-01-07 23:22