Konflik di bab sebelumnya bukan kecelakaan acak: simpanan lama dibuat di atas commit yang sudah tertinggal, sementara branch utama terus berjalan, sehingga merge tiga pihak saat pengambilan kehilangan titik pijak yang sama. git stash branch menyelesaikannya dari akarnya — membuat branch baru yang berdiri tepat di commit tempat simpanan dibuat, menerapkan simpanan di sana, lalu menjatuhkannya begitu bersih. Kita buktikan dulu masalahnya, tonton satu perintah itu bekerja, bedah alasan keberhasilannya, lalu bangun ulang jalur manualnya dengan git switch -c agar trik ini tidak terasa seperti sihir.

Masalahnya: Simpanan Berbasis Masa Lalu #

Repository latihan-stash-branch memampangkan skenario lengkapnya: draf footer disimpan setengah jadi, main kemudian merilis footer versi resmi:

bash
mkdir latihan-stash-branch && cd latihan-stash-branch
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf 'beranda\n' > situs.md
git add situs.md
git commit -m "Buat halaman beranda"
printf 'beranda\nfooter v1\n' > situs.md
git stash push -m "draf footer setengah jadi"
printf 'beranda\nfooter resmi\n' > situs.md
git add situs.md
git commit -m "Rilis footer resmi"
git stash apply

Output yang Dihasilkan:

text
Saved working directory and index state On main: draf footer setengah jadi

Output yang Dihasilkan:

text
Auto-merging situs.md
CONFLICT (content): Merge conflict in situs.md
On branch main
Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
	both modified:   situs.md

no changes added to commit (use "git add" and/or "git commit -a")
bash
git status --short

Output yang Dihasilkan:

text
UU situs.md

Baris UU menandakan situs.md unmerged dari dua sisi sekaligus — draf lama dan footer resmi sama-sama menulis baris kedua situs.md. Percobaan ini kita batalkan; simpanannya sendiri tidak ikut hilang karena apply memang tidak pernah membuang:

bash
git reset --hard HEAD

Output yang Dihasilkan:

text
HEAD is now at a404694 Rilis footer resmi

Solusi Satu Perintah: git stash branch #

bash
git stash branch fitur-lanjutan "stash@{0}"

Output yang Dihasilkan:

text
Switched to a new branch 'fitur-lanjutan'
On branch fitur-lanjutan
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   situs.md

no changes added to commit (use "git add" and/or "git commit -a")
Dropped stash@{0} (ed422dc160551d64044ca70c99c4918240a56d3b)

Satu keluaran memuat tiga peristiwa: branch fitur-lanjutan lahir, simpanan diterapkan tanpa konflik sedikit pun, dan baris Dropped stash@{0} menutup siklusnya. Pekerjaan setengah jadi itu kini hidup di branchnya sendiri — selesaikan, lalu lihat posisinya di peta riwayat:

bash
cat situs.md
git add situs.md
git commit -m "Selesaikan draf footer"
git log --oneline --graph --all

Output yang Dihasilkan:

text
beranda
footer v1

Output yang Dihasilkan:

text
[fitur-lanjutan 35d433a] Selesaikan draf footer
 1 file changed, 1 insertion(+)

Output yang Dihasilkan:

text
* 35d433a Selesaikan draf footer
| * a404694 Rilis footer resmi
|/  
* 19cdf59 Buat halaman beranda

Graf dua cabang terbaca jelas: main membawa Rilis footer resmi, fitur-lanjutan membawa Selesaikan draf footer, keduanya bercabang dari Buat halaman beranda — hash di mesin pembaca akan berbeda. Dua versi footer itu kini berhadapan sebagai branch biasa yang bisa di-merge atau direbase sebagaimana branch mana pun.

Mengapa Ini Berhasil #

Jawabannya ada pada anatomi stash di git stash : commit simpanan menyimpan parent pertama berupa commit HEAD saat ia dibuat. git stash branch membuat branch baru di parent pertama itu — basis yang persis sama dengan saat draf ditulis — barulah simpanan diterapkan. Merge tiga pihak yang tadinya membandingkan draf lama dengan main yang sudah menjauh kini membandingkan draf dengan keadaan aslinya sendiri, sehingga tidak ada satu pun baris yang bertabrakan. Karena branch baru tak akan pernah memuat kerja orang lain, penerapan hampir selalu bersih, dan barulah drop dijalankan otomatis.

Alternatif Manual: switch -c dari Basis Simpanan #

Tiga langkah internal git stash branch bisa dibangun sendiri, dan memahaminya membuat perintah tadi berhenti terasa ajaib. Repository latihan-manual menyiapkan kerangka yang sama persis — draf footer di atas commit pertama, main sudah merilis footer resmi:

bash
mkdir latihan-manual && cd latihan-manual
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf 'beranda\n' > situs.md
git add situs.md
git commit -m "Buat halaman beranda"
printf 'beranda\nfooter v1\n' > situs.md
git stash push -m "draf footer setengah jadi"
printf 'beranda\nfooter resmi\n' > situs.md
git add situs.md
git commit -m "Rilis footer resmi"

Ekspresi "stash@{0}^" merujuk parent pertama stash commit — commit basis tempat draf dibuat:

bash
git rev-parse --short "stash@{0}^"
git switch -c pulihan-manual "stash@{0}^"
git stash apply
git stash drop
cat situs.md

Output yang Dihasilkan:

text
c6e6adc

Output yang Dihasilkan:

text
Switched to a new branch 'pulihan-manual'

Output yang Dihasilkan:

text
On branch pulihan-manual
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   situs.md

no changes added to commit (use "git add" and/or "git commit -a")

Output yang Dihasilkan:

text
Dropped refs/stash@{0} (fa2f4e7df52b2eac8f6c7e5a36981e2a37669755)

Output yang Dihasilkan:

text
beranda
footer v1

Empat langkah manual menghasilkan keadaan yang identik dengan git stash branch: branch berdiri di basis lama, draf diterapkan bersih, simpanan dijatuhkan, dan situs.md memuat footer v1. Perbedaannya cuma jumlah ketikan — dan tanggung jawab menjatuhkan simpanan yang kini ada di tangan kita. Rujukan sintaks lengkapnya ada di git-stash .

Ekosistem stash kini tuntas: menyimpan, memeriksa, mengambil, menjatuhkan, sampai memindahkan simpanan ke branch segar. Namun seluruhnya bergantung pada satu asumsi — objek yang dirujuk masih hidup di database. Pertanyaan pamungkas recovery adalah memeriksa asumsi itu sendiri, dan alatnya bukan stash melainkan git fsck, yang dibahas di git fsck .