Sebagai sedikit penjelasan tambahan, catatan yang git stashmembuat dua komit, atau tiga komit. Defaultnya adalah dua; Anda mendapatkan tiga jika Anda menggunakan ejaan --allatau --include-untrackedopsi.
Dua, atau tiga, komit ini istimewa dalam satu hal penting: tidak ada cabang. Git menempatkannya melalui nama khusus stash. 1 Namun, hal terpenting adalah apa yang Git izinkan untuk Anda — dan buat Anda — lakukan dengan dua atau tiga komitmen ini. Untuk memahami hal ini kita perlu melihat apa yang ada di dalam commit tersebut.
Apa yang ada di dalam simpanan
Setiap komit bisa mendaftar satu atau lebih komit orang tua . Ini membentuk grafik, di mana kemudian komitmen menunjuk kembali ke yang sebelumnya. Stash biasanya menampung dua komit, yang ingin saya panggil iuntuk konten index / staging-area, dan wuntuk konten work-tree. Ingat juga bahwa setiap komit menyimpan sebuah snapshot. Dalam komit normal, snapshot ini dibuat dari konten index / staging-area. Jadi ikomit sebenarnya adalah komit normal sempurna! Hanya saja tidak di cabang mana pun:
...--o--o--o <-- branch (HEAD)
|
i
Jika Anda membuat simpanan normal, git stashkodenya wsekarang dengan menyalin semua file pohon kerja terlacak Anda (ke dalam indeks tambahan sementara). Git menetapkan orang tua pertama dari wkomit ini untuk menunjuk ke HEADkomit, dan orang tua kedua untuk menunjuk ke komit i. Terakhir, set stashuntuk menunjuk ke wkomit ini :
...--o--o--o <-- branch (HEAD)
|\
i-w <-- stash
Jika Anda menambahkan --include-untrackedatau --all, Git membuat komit ekstra u,, di antara pembuatan idan w. Konten snapshot untuk uadalah file yang tidak terlacak tetapi tidak diabaikan ( --include-untracked), atau file yang tidak terlacak meskipun diabaikan ( --all). Ekstra ini uberkomitmen memiliki tidak ada orang tua, dan kemudian ketika git stashmerek w, ia menetapkan w's ketiga orang tua untuk ini ukomit, sehingga Anda mendapatkan:
...--o--o--o <-- branch (HEAD)
|\
i-w <-- stash
/
u
Git juga, pada titik ini, menghapus semua file pohon kerja yang berakhir di ukomit (menggunakan git cleanuntuk melakukan itu).
Mengembalikan simpanan
Saat Anda pergi untuk memulihkan simpanan, Anda memiliki opsi untuk menggunakan --index, atau tidak menggunakannya. Ini memberitahu git stash apply(atau salah satu perintah yang menggunakan internal apply, seperti pop) yang seharusnya menggunakan yang iberkomitmen untuk mencoba mengubah indeks Anda saat ini. Modifikasi ini dilakukan dengan:
git diff <hash-of-i> <hash-of-i's-parent> | git apply --index
(kurang lebih; ada banyak detail kecil yang menghalangi ide dasar di sini).
Jika Anda menghilangkan --index, git stash applymengabaikan ikomit sepenuhnya .
Jika simpanan hanya memiliki dua komit, git stash applysekarang dapat menerapkan wkomit. Ini dilakukan dengan memanggil git merge2 (tanpa mengizinkannya untuk mengkomit atau memperlakukan hasil sebagai gabungan normal), menggunakan komit asli tempat simpanan dibuat ( iinduk pertama, dan winduk pertama) sebagai basis gabungan, wsebagai --theirskomit, dan komit (HEAD) Anda saat ini sebagai target penggabungan. Jika penggabungan berhasil, semua akan baik-baik saja — yah, setidaknya menurut Git — dan git stash applysukses itu sendiri. Jika Anda dulu git stash popmenggunakan simpanan, kode sekarang menjatuhkan simpanan. 3 Jika penggabungan gagal, Git menyatakan bahwa penerapan gagal. Jika Anda dulugit stash pop, kode mempertahankan simpanan dan memberikan status kegagalan yang sama seperti untuk git stash apply.
Tetapi jika Anda memiliki komit ketiga itu — jika ada ukomit di simpanan yang Anda terapkan — maka segalanya berubah! Tidak ada pilihan untuk berpura-pura bahwa ukomit tidak ada. 4 Git bersikeras mengekstrak semua file dari yang ukomit, ke dalam arus kerja-pohon. Ini berarti file harus tidak ada sama sekali, atau memiliki konten yang sama seperti di ukomit.
Untuk mewujudkannya, Anda dapat menggunakan git cleandiri Anda sendiri — tetapi ingat bahwa file yang tidak terlacak (diabaikan atau tidak) tidak memiliki keberadaan lain di dalam repositori Git, jadi pastikan semua file ini dapat dihancurkan! Atau, Anda dapat membuat direktori sementara, dan memindahkan file ke sana untuk diamankan — atau bahkan melakukan yang lain git stash save -uatau git stash save -a, karena itu akan berjalan git cleanuntuk Anda. Tapi itu hanya membuat Anda memiliki usimpanan gaya lain untuk ditangani nanti.
1 Ini sebenarnya refs/stash. Ini penting jika Anda membuat cabang dengan nama stash: nama lengkap cabang adalah refs/heads/stash, jadi tidak ada konflik. Tapi jangan lakukan itu: Git tidak keberatan, tapi Anda akan membingungkan diri sendiri. :-)
2 The git stashkode benar-benar menggunakan git merge-recursivelangsung di sini. Ini diperlukan karena berbagai alasan, dan juga memiliki efek samping untuk memastikan Git tidak memperlakukannya sebagai gabungan saat Anda menyelesaikan konflik dan melakukan.
3 Inilah mengapa saya merekomendasikan menghindari git stash pop, demi git stash apply. Anda mendapat kesempatan untuk meninjau apa yang telah diterapkan, dan memutuskan apakah itu benar - benar diterapkan dengan benar. Jika tidak, Anda masih memiliki simpanan yang berarti dapat Anda gunakan git stash branchuntuk memulihkan semuanya dengan sempurna. Nah, dengan asumsi kurangnya ukomitmen sial itu .
4 Benar-benar harus ada: git stash apply --skip-untrackedatau sesuatu. Juga harus ada varian yang berarti letakkan semua ufile komit itu ke direktori baru , misalnya git stash apply --untracked-into <dir>, mungkin.
git stash show -p | git apply --3