git stash blunder: git stash pop dan berakhir dengan menggabungkan konflik

200

Saya melakukan git stash popdan berakhir dengan menggabungkan konflik. Saya menghapus file-file dari sistem file dan melakukan git checkoutseperti yang ditunjukkan di bawah ini, tetapi ia berpikir file-file tersebut masih belum dihapus. Saya kemudian mencoba mengganti file dan melakukan git checkoutlagi dan hasil yang sama. Saya acara mencoba memaksanya dengan -fbendera. Bantuan apa pun akan dihargai!

chirag-patels-macbook-pro:haloror patelc75$ git status
app/views/layouts/_choose_patient.html.erb: needs merge
app/views/layouts/_links.html.erb: needs merge
# On branch prod-temp
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   db/schema.rb
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       unmerged:   app/views/layouts/_choose_patient.html.erb
#       unmerged:   app/views/layouts/_links.html.erb

chirag-patels-macbook-pro:haloror patelc75$ git checkout app/views/layouts/_choose_patient.html.erb
error: path 'app/views/layouts/_choose_patient.html.erb' is unmerged
chirag-patels-macbook-pro:haloror patelc75$ git checkout -f app/views/layouts/_choose_patient.html.erb
warning: path 'app/views/layouts/_choose_patient.html.erb' is unmerged
Chirag Patel
sumber
Catatan: memulihkan negara sebelum yang git stash apply/popharus lebih mudah dengan Git 2,5 (Q2 2015), karena pohon bekerja sekarang harus bersih: lihat jawaban saya di bawah
VonC

Jawaban:

219

Lihat man git merge ( CARA MENYELESAIKAN KONFLIK ):

Setelah melihat konflik, Anda dapat melakukan dua hal:

  • Putuskan untuk tidak bergabung. Satu-satunya pembersihan yang Anda butuhkan adalah mereset file indeks ke komit HEAD untuk membalikkan 2. dan untuk membersihkan perubahan susunan yang dibuat oleh 2. dan 3 .; git-reset --hard dapat digunakan untuk ini.

  • Selesaikan konflik. Git akan menandai konflik di pohon kerja. Edit file ke dalam bentuk dan git menambahkannya ke indeks. Gunakan git commit untuk menyegel transaksi.

Dan di bawah TRUE MERGE (untuk melihat apa yang 2. dan 3. merujuk):

Ketika tidak jelas bagaimana mendamaikan perubahan, berikut ini terjadi:

  1. Pointer HEAD tetap sama.

  2. Referensi MERGE_HEAD diatur untuk mengarah ke kepala cabang lainnya.

  3. Jalur yang digabungkan dengan bersih diperbarui di file indeks dan di pohon kerja Anda.

  4. ...

Jadi: gunakan git reset --hardjika Anda ingin menghapus perubahan simpanan dari pohon kerja Anda, atau git resetjika Anda hanya ingin membersihkan indeks dan membiarkan konflik di pohon kerja Anda untuk bergabung dengan tangan.

Di bawah man git simpanan ( PILIHAN, pop ) Anda dapat membaca sebagai tambahan:

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.

tanascius
sumber
9
Bahkan, bahkan setelah Anda menjatuhkan simpanan, masih mungkin (meskipun lebih sulit) untuk mengambilnya lagi, karena set perubahan masih ada di repositori. stackoverflow.com/search?q=git+recover+dropped+stash
phils
3
@nalply: apakah itu baik atau buruk? Anda dipersilakan untuk meningkatkan jawaban saya, di mana Anda tidak memahaminya sejak awal ...
tanascius
1
Saya pikir revisi kode sumber adalah domain masalah yang kompleks. Sangat mudah untuk bingung. Saya masih berpikir bahwa jawaban Anda baik karena itu menegaskan kembali pendekatan saya.
nalply
1
Tidak hanya itu banyak membantu saya untuk menyadari bahwa simpanan belum dihapus seperti yang saya duga, tetapi ini menjelaskan mengapa simpanan saya terus tumbuh bahkan ketika saya yakin saya tidak lupa untuk mengambil sesuatu dari itu.
Thor84no
11
"Menerapkan negara dapat gagal dengan konflik; dalam hal ini, itu tidak dihapus dari daftar simpanan."Ini adalah bagian terpenting dari posting, menurut saya. Pertimbangkan untuk mengedit jawaban Anda untuk meletakkannya di depan bersama dengan kata-kata JANGAN PANIC dalam huruf besar dan ramah. (+1 sudah.) Terima kasih.
Patrick M
42

Saya memiliki hal serupa yang terjadi pada saya. Saya tidak ingin memformat file dulu jadi saya menambahkannya git adddan kemudian melakukannya git reset. Ini pada dasarnya hanya ditambahkan dan kemudian unstaged perubahan saya tetapi membersihkan jalur yang tidak bermigrasi.

Harun
sumber
4
Ini tampaknya lebih baik daripada menggunakan reset --hardkarena tidak menimpa file Anda (kecuali yang dengan masalah penggabungan). Terima kasih!
sinelaw
Saya tidak ingin mem-stage file-nya dulu jadi saya menambahkannya - bukankah addkonten stage dari tree yang berfungsi ke index? Saya rasa saya tidak mengerti mengapa jawaban Anda bekerja dari deskripsi.
Drew Noakes
2
git addtidak tahap mereka tetapi git reset, yang saya lakukan segera setelah, panggung mereka. Pada dasarnya itu membersihkan jalan yang tidak bermandikan dan mengembalikan saya ke pohon kerja normal saya dengan memalsukan git.
Aaron
3
Anda tidak perlu melakukannya git addjika mau git reset. Secara git resetefektif "membatalkan" itu git add. git reset( --mixed<- default) secara efektif tidak menyentuh direktori kerja jadi apa yang ada di direktori kerja Anda, menggabungkan konflik dan semuanya, ditinggalkan sendirian. Indeks (dan secara teknis kepala cabang) diatur ulang meskipun (tanpa referensi mereka dapat diatur ulang ke HEAD, yang mungkin berarti tidak ada perubahan untuk kepala cabang, dan secara efektif membatalkan apa pun yang git adddilakukan pada indeks, serta membersihkan keadaan jalur yang tidak diolah) .
bambams
3
The urut , mengedit / tekad , git resetdan git stash dropbekerja dengan baik. Itu melakukan apa yang git stash popakan dilakukan tanpa konflik. Tampaknya git addmemang tidak diperlukan; Meskipun mungkin berguna, Anda memiliki banyak file dengan konflik. Ketika masing-masing diselesaikan , mereka dapat ditambahkan dan git statusmelacak mereka.
kebisingan seni
13

Jika, seperti saya, yang biasanya Anda inginkan adalah menimpa isi direktori kerja dengan file yang disimpan, dan Anda masih mendapatkan konflik, maka yang Anda inginkan adalah menyelesaikan konflik menggunakan git checkout --theirs -- .dari root.

Setelah itu, Anda dapat git resetmembawa semua perubahan dari indeks ke direktori yang berfungsi, karena tampaknya jika terjadi konflik, perubahan pada file yang tidak konflik tetap berada dalam indeks.

Anda mungkin juga ingin menjalankan git stash drop [<stash name>]setelahnya, untuk menyingkirkan simpanan, karena git stash poptidak menghapusnya jika terjadi konflik.

Pedro Gimeno
sumber
2

Catat itu Git 2.5 (Q2 2015) Git masa depan mungkin mencoba membuat skenario itu mustahil.

Lihat commit ed178ef oleh Jeff King ( peff), 22 Apr 2015.
(Digabung oleh Junio ​​C Hamano - gitster- dalam commit 05c3967 , 19 Mei 2015)

Catatan: Ini telah dikembalikan. Lihat di bawah .

stash: memerlukan indeks bersih untuk menerapkan / pop

Masalah

Jika Anda telah mementaskan konten dalam indeks Anda dan menjalankan " stash apply/pop", kami dapat mencapai konflik dan memasukkan entri baru ke dalam indeks.
Memulihkan ke kondisi awal Anda sulit pada saat itu, karena alat seperti "git reset --keep" akan menerbangkan apa pun yang dipentaskan .

Dengan kata lain:

" git stash pop/apply" lupa memastikan bahwa tidak hanya pohon yang bekerja bersih tetapi juga indeksnya bersih.
Yang terakhir ini penting karena aplikasi simpanan dapat konflik dan indeks akan digunakan untuk resolusi konflik.

Larutan

Kita dapat membuat ini lebih aman dengan menolak untuk menerapkan ketika ada perubahan bertahap.

Itu berarti jika ada penggabungan sebelumnya karena menerapkan simpanan pada file yang dimodifikasi (ditambahkan tetapi tidak dilakukan), sekarang mereka tidak akan ada penggabungan karena simpanan berlaku / pop akan segera berhenti dengan:

Cannot apply stash: Your index contains uncommitted changes.

Memaksa Anda melakukan perubahan berarti bahwa, dalam kasus penggabungan, Anda dapat dengan mudah mengembalikan keadaan awal (sebelumnya git stash apply/pop) dengan a git reset --hard.


Lihat komit 1937610 (15 Jun 2015), dan komit ed178ef (22 Apr 2015) oleh Jeff King ( peff) .
(Digabung oleh Junio ​​C Hamano - gitster- di commit bfb539b , 24 Jun 2015)

Komit itu adalah upaya untuk meningkatkan keamanan penerapan simpanan, karena proses aplikasi dapat membuat entri indeks yang bertentangan, setelah itu sulit untuk memulihkan keadaan indeks asli.

Sayangnya, ini menyakitkan beberapa alur kerja umum di sekitar " git stash -k", seperti:

git add -p       ;# (1) stage set of proposed changes
git stash -k     ;# (2) get rid of everything else
make test        ;# (3) make sure proposal is reasonable
git stash apply  ;# (4) restore original working tree

Jika Anda "git commit" antara langkah (3) dan (4), maka ini hanya berfungsi. Namun, jika langkah-langkah ini adalah bagian dari hook pra-komit, Anda tidak memiliki kesempatan itu (Anda harus mengembalikan status awal terlepas dari apakah tes lulus atau gagal).

VONC
sumber