Batalkan simpanan pop di Git

257

Saya muncul simpanan dan ada konflik gabungan. Tidak seperti pertanyaan yang didaftar sebagai duplikat, saya sudah memiliki beberapa perubahan dalam direktori yang ingin saya simpan. Saya tidak hanya ingin membuat konflik gabungan menghilang, tetapi juga untuk mendapatkan direktori saya kembali ke keadaan sebelum pop.

Saya mencoba git merge --abort, tetapi git mengklaim tidak ada penggabungan yang sedang berlangsung. Apakah ada cara mudah untuk membatalkan pop tanpa merusak perubahan yang saya miliki di direktori?

Casebash
sumber
Adapun perubahan Anda yang tidak dikomit: apakah perubahan ini sudah ada dalam indeks?
jørgensen
Bisakah Anda memposting versi git yang Anda gunakan.
Tinman
2
Jawaban yang diterima terlihat rumit. Saya pikir ini praktik umum yang cukup bagus untuk tidak pernah melakukan sesuatu seperti upaya git stash poppada dir yang kotor. Dalam hal ini Anda mungkin hanya git reset --harddan simpanan Anda masih utuh. (Ini kurang lebih seperti yang disarankan oleh topik terkait @ BradKoch)
Steven Lu
1
@ SevenLu, saya setuju, tetapi masalah ini dapat terjadi dalam direktori kerja yang bersih jika Anda menyembunyikan perubahan untuk memindahkannya ke cabang yang berbeda. Stash bertentangan dengan komit yang ada di cabang baru yang tidak ada di yang lama.
Jake Stevens-Haas

Jawaban:

55

Ok, saya pikir saya sudah berhasil "git simpanan tidak pantas". Ini lebih kompleks daripada git apply --reversekarena Anda perlu tindakan penggabungan terbalik jika ada penggabungan yang dilakukan oleh git stash apply.

Penggabungan terbalik mengharuskan semua perubahan saat ini didorong ke dalam indeks:

  • git add -u

Kemudian membalikkan merge-recursiveitu dilakukan oleh git stash apply:

  • git merge-recursive stash@{0}: -- $(git write-tree) stash@{0}^1

Sekarang Anda akan dibiarkan hanya dengan perubahan non-simpanan. Mereka akan berada dalam indeks. Anda dapat menggunakan git resetuntuk menghapus stage perubahan Anda jika Anda mau.

Mengingat bahwa dokumen asli Anda git stash applygagal, saya berasumsi sebaliknya mungkin juga gagal karena beberapa hal yang ingin dibatalkan tidak dilakukan.

Berikut ini contoh yang menunjukkan bagaimana copy pekerjaan (via git status) kembali bersih:

 $ git status
# On branch trunk
nothing to commit (working directory clean)
 $ git stash apply
Auto-merging foo.c
# On branch trunk
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   foo.c
#
no changes added to commit (use "git add" and/or "git commit -a")
 $ git add -u
 $ git merge-recursive stash@{0}: -- $(git write-tree) stash@{0}^1
Auto-merging foo.c
 $ git status
# On branch trunk
nothing to commit (working directory clean)
Ben Jackson
sumber
2
setelah melakukan ini, apakah suntingan yang sebelumnya disimpan akan hilang selamanya, atau mereka kembali di simpanan?
Brian H.
7
git stash applytidak pernah menjatuhkan simpanan, dan ketika penggabungan gagal maka git stash popjuga mempertahankan simpanan
Xerus
Hal-hal buruk akan terjadi jika ada konflik gabungan selama pop simpanan asli
3ocene
286

Kasus penggunaan saya: baru saja mencoba muncul ke cabang yang salah dan mendapat konflik. Yang saya butuhkan adalah membatalkan pop tetapi menyimpannya di daftar simpanan sehingga saya bisa mengeluarkannya di cabang yang benar. Saya melakukan ini:

git reset HEAD --hard
git checkout my_correct_branch
git stash pop

Mudah.

jmoz
sumber
22
Jadi simpanan yang Anda inginkan tetap berada dalam daftar simpanan hingga Anda memiliki pop sukses?
Ryan Clark
52
Ini bukan jawaban untuk pertanyaan awal karena akan menghapus perubahan lokal yang tidak dilakukan.
Dmitry
13
@RyanClark Lihat jawaban DavidG di bawah ini. Pada dasarnya, ya, itu tetap dalam daftar simpanan.
fkorsa
1
Saya pikir sebagian besar pengguna yang menemukan diri mereka dalam situasi ini akan menemukan solusi ini ideal. Saya tidak bisa membayangkan situasi di mana saya memiliki perubahan yang tidak dikomit di direktori kerja saya sebelum mencoba stash popke dalamnya. Itu terdengar seperti resep bencana.
Shadoninja
2
Bagus. Setelah membaca ini saya melihat dokumen pop simpanan git dan mengatakan "Menerapkan negara dapat gagal dengan konflik; dalam hal ini, itu tidak dihapus dari daftar simpanan.". Jadi, inilah sebabnya simpanan dapat muncul kembali setelah reset / checkout.
Brady Holt
48

Sunting: Dari git help stashdokumentasi di bagian pop:

Menerapkan negara dapat gagal dengan konflik; dalam hal ini, itu tidak dihapus dari daftar simpanan. Anda perlu menyelesaikan konflik dengan tangan dan memanggil drop git secara manual setelahnya.

Jika opsi --index digunakan, maka cobalah untuk mengembalikan tidak hanya perubahan pohon kerja, tetapi juga yang indeks itu. Namun, ini bisa gagal, ketika Anda memiliki konflik (yang disimpan dalam indeks, karena itu Anda tidak dapat lagi menerapkan perubahan seperti aslinya).

Cobalah menyalin semua repo ke dalam direktori baru (sehingga Anda memiliki salinannya) dan jalankan:

git stash show dan simpan output itu di suatu tempat jika Anda peduli.

lalu: git stash dropuntuk membatalkan simpanan yang bertentangan maka:git reset HEAD

Itu seharusnya membuat repo Anda dalam keadaan seperti semula (semoga, saya masih belum bisa menegur masalah Anda)

===

Saya mencoba untuk memperbaiki masalah Anda, tetapi semua yang saya dapatkan ketika menggunakan git stash popadalah:

error: Your local changes to the following files would be overwritten by merge:
...
Please, commit your changes or stash them before you can merge.
Aborting

Dalam dir bersih:

git init
echo hello world > a
git add a & git commit -m "a"
echo hallo welt >> a
echo hello world > b
git add b & git commit -m "b"
echo hallo welt >> b
git stash
echo hola mundo >> a
git stash pop

Saya tidak melihat git mencoba untuk menggabungkan perubahan saya, itu hanya gagal. Apakah Anda memiliki langkah repro yang dapat kami ikuti untuk membantu Anda?

DavidG
sumber
Coba menyimpan perubahan ke file yang berbeda.
penanggung jawab
Mencoba menyembunyikan file yang berbeda tidak berhasil (lihat langkah repro baru). Saya tidak bisa menegur masalah ini ...
DavidG
1
Solusi ini tidak berfungsi jika ada perubahan yang tidak dikomit di direktori kerja.
sini
@di sini Ini bukan solusi nyata, ini hanya untuk menunjukkan bahwa saya tidak dapat mereproduksi masalah yang dimiliki OP dan bahwa dia belum memberikan langkah apa pun untuk sampai ke tempat dia berada.
DavidG
1
Skenario aktual adalah: 1) Ubah file A. 2) Perubahan simpanan 3) Buat perubahan yang bertentangan dalam file A dan komit (misalnya ubah baris yang sama) 4) Ubah file B 5) Lakukan 'git stash pop'. Sekarang Anda memiliki konflik dan perubahan lokal. Umumnya mereka akan berada di file yang berbeda, tetapi Anda tidak akan pernah tahu file modifikasi mana yang tidak bertentangan dari simpanan dan yang merupakan perubahan lokal yang tidak dipentaskan.
Dmitry
17

Saya selalu menggunakan

git reset --merge

Saya tidak dapat mengingatnya pernah gagal.

Kenn Sebesta
sumber
@GauravPaliwal, saya akan memberikan tampilan itu lain kali saya git reset. Apakah Anda tahu apakah itu identik secara fungsional git reset --merge?
Kenn Sebesta
5

Jika Anda tidak perlu khawatir tentang perubahan lain yang Anda buat dan Anda hanya ingin kembali ke komit terakhir, maka Anda dapat melakukan:

git reset .
git checkout .
git clean -f
hugo der hungrige
sumber
4

OK, saya pikir saya telah berhasil menemukan alur kerja yang akan membawa Anda kembali ke tempat yang Anda inginkan (seolah-olah Anda belum melakukan pop).

MENGAMBIL CADANGAN SEBELUM !! Saya tidak tahu apakah ini akan berhasil untuk Anda, jadi salin seluruh repo Anda kalau-kalau itu tidak berhasil.

1) Perbaiki masalah penggabungan dan perbaiki semua konflik dengan memilih semua perubahan yang datang dari tambalan (dalam tortoisemerge, ini muncul sebagai satu. REMOETE (milik mereka)).

git mergetool

2) Komit perubahan ini (mereka sudah akan ditambahkan melalui perintah mergetool). Berikan pesan komit "gabungan" atau sesuatu yang Anda ingat.

git commit -m "merge"

3) Sekarang Anda masih akan memiliki perubahan lokal yang belum diprogram yang Anda mulai semula, dengan komit baru dari tambalan (kami dapat menyingkirkan ini nanti). Sekarang komit perubahan Anda yang tidak dipentaskan

git add .
git add -u .
git commit -m "local changes"

4) Balikkan tambalan. Ini dapat dilakukan dengan perintah berikut:

git stash show -p | git apply -R

5) Lakukan perubahan ini:

git commit -a -m "reversed patch"

6) Singkirkan tambalan / pembatalan komitmen

git rebase -i HEAD^^^

dari ini, hapus dua baris dengan 'menggabungkan' dan 'tambalan terbalik' di dalamnya.

7) Dapatkan kembali perubahan tak bertanggal Anda dan batalkan komit 'perubahan lokal'

git reset HEAD^

Saya telah menjalankannya dengan contoh sederhana dan itu membuat Anda kembali ke tempat yang Anda inginkan - langsung sebelum simpanan muncul, dengan perubahan lokal Anda dan simpanan masih tersedia untuk muncul.

agentgonzo
sumber
Jika itu tidak berhasil, mudah-mudahan itu akan membuat Anda hampir sampai ke sana! :-)
agentgonzo
git stash show -p | git apply -Ritu tidak bekerja jika git stash applymelakukan penggabungan nyata. Lihat jawaban saya ...
Ben Jackson
3

Saya memecahkan ini dengan cara yang agak berbeda. Inilah yang terjadi.

Pertama, saya muncul di cabang yang salah dan mendapat konflik. Stash tetap utuh tetapi indeks dalam resolusi konflik, memblokir banyak perintah.

Sederhana git reset HEADdibatalkan resolusi konflik dan meninggalkan perubahan tidak berkomitmen (dan TIDAK DIINGINKAN ).

Beberapa git co <filename>mengembalikan indeks ke keadaan awal. Akhirnya, saya beralih cabang git co <branch-name>dan menjalankan yang baru git stash pop, yang diselesaikan tanpa konflik.

pid
sumber
2

Beberapa ide:

  • Gunakan git mergetooluntuk membagi file gabungan menjadi bagian asli dan baru. Semoga salah satunya adalah file dengan perubahan non-simpanan Anda di dalamnya.

  • Terapkan diff simpanan secara terbalik, untuk membatalkan perubahan itu saja. Anda mungkin harus membagi file secara manual dengan konflik penggabungan (yang semoga trik di atas akan berhasil).

Saya tidak menguji salah satu dari ini, jadi saya tidak tahu pasti mereka akan bekerja.

penilai
sumber
1

Saya dapat mereproduksi bersih git stash poppada direktori "kotor", dengan perubahan yang tidak dikomit, tetapi belum muncul yang menghasilkan konflik gabungan.

Jika pada konflik gabungan simpanan yang Anda coba terapkan tidak hilang, Anda dapat mencoba memeriksa git show stash@{0}(opsional dengan --oursatau --theirs) dan membandingkan dengan git statisdan git diff HEAD. Anda harus dapat melihat perubahan mana yang berasal dari penerapan simpanan.

Jakub Narębski
sumber
1

Jika DavidG benar bahwa itu tidak menghapus simpanan karena konflik gabungan, maka Anda hanya perlu membersihkan direktori kerja Anda. Dengan cepat git commitsemua yang Anda pedulikan. (Anda dapat resetatau squashkomit nanti jika Anda tidak selesai.) Kemudian dengan semua yang Anda pedulikan aman, git resetsemua yang lain git stash popdimasukkan ke direktori kerja Anda.

Robrich
sumber
1

Jika tidak ada perubahan bertahap sebelum git stash pop, seperti dalam pertanyaan, maka dua perintah berikut akan berfungsi.

git diff --name-only --cached | xargs git checkout --ours HEAD
git ls-tree stash@{0}^3 --name-only | xargs rm

Yang pertama membalikkan gabungan dari simpanan, sukses atau tidak. Yang kedua menghapus semua file yang tidak terlacak yang diperkenalkan oleh simpanan.

Dari man git stash: The working directory must match the index. Yang ditunjukkan @DavidG, stash popakan gagal jika ada file yang dimodifikasi yang tidak dipentaskan konflik. Dengan demikian, kita tidak perlu khawatir tentang menyelesaikan konflik gabungan sebelum kembali ke HEAD. Setiap file yang dimodifikasi yang tersisa kemudian tidak terkait dengan simpanan, dan dimodifikasi sebelumstash pop

Jika ada perubahan bertahap, saya tidak yakin apakah kita bisa mengandalkan perintah yang sama dan Anda mungkin ingin mencoba teknik @Ben Jackson. Saran dihargai ..

Berikut ini adalah pengaturan pengujian untuk semua berbagai kasus https://gist.github.com/here/4f3af6dafdb4ca15e804

# Result:
# Merge succeeded in m (theirs)
# Conflict in b
# Unstaged in a
# Untracked in c and d

# Goal:
# Reverse changes to successful merge m
# Keep our version in merge conflict b
# Keep our unstaged a
# Keep our untracked d
# Delete stashed untracked c
sini
sumber
Saya pikir ini adalah jawaban yang paling benar sejauh ini. Dipikirkan dengan sangat baik.
Agen Jumat
0

Gunakan git refloguntuk mendaftar semua perubahan yang dibuat dalam sejarah git Anda. Salin id tindakan dan ketikgit reset ACTION_ID

Fatih Acet
sumber
2
Git tidak membuat entri reflog sebelum Anda muncul (Anda harus memiliki komit)
Casebash
-1

Saya memposting di sini berharap yang lain menemukan jawaban saya bermanfaat. Saya memiliki masalah yang sama ketika saya mencoba melakukan simpanan pada cabang yang berbeda dari yang saya simpan. Pada kasus saya, saya tidak memiliki file yang tidak dikomit atau dalam indeks tetapi masih masuk ke kasus menggabungkan konflik (kasus yang sama dengan @pid). Seperti yang orang lain tunjukkan sebelumnya, pop gagal git yang gagal memang mempertahankan simpanan saya, lalu git cepat mereset KEPALA ditambah kembali ke cabang asli saya dan melakukan simpanan dari sana memang menyelesaikan masalah saya.

Victor Camacho
sumber