Bedah Sejarah:
Rebase & Undo Aman
Dua kemampuan yang membuatmu tenang menghadapi history: merapikannya dengan rebase agar enak dibaca, dan membatalkan perubahan dengan alat yang tepat agar tidak ada kerja keras yang hilang.
Chapter ini satu busur “bedah sejarah”: dua operasi yang sama-sama menyentuh masa lalu repo, tapi dengan tujuan berbeda. Rebase menata ulang commit agar history bercerita rapi; undo (restore, reset, revert, stash) membatalkan langkah yang keliru. Benang merah keduanya adalah satu aturan emas yang kamu pelajari di Chapter 4: jangan menulis ulang sejarah yang sudah dibagikan. Kuasai itu, dan kamu bisa membongkar-pasang history tanpa takut merusak kerja tim.
Rebase: Merapikan Sejarah
Linear history, merge vs rebase, dan interactive rebase
Rebase memindahkan commit branch-mu ke atas base terbaru, menulis ulang sejarah agar menjadi garis lurus yang mudah dibaca.
Saat kamu bekerja di branch feature/checkout, branch main tidak diam. Rekanmu terus merge fitur lain ke sana. Kalau nanti kamu merge balik, sejarah jadi rumit: garis bercabang, merge commit di mana-mana, dan git log terlihat seperti peta kereta bawah tanah. Rebase menawarkan jalan lain: alih-alih menyatukan dua cabang dengan merge commit, ia mengangkat commit-commitmu dan menanamnya ulang satu per satu di atas ujung main yang terbaru.
Dokumen GitHub menyebut rebasing sebagai cara “menulis ulang riwayat commit”, yang membuat riwayat lebih bersih namun harus dipakai dengan hati-hati karena commit lama digantikan oleh commit baru dengan hash berbeda.
Terminalgit switch feature/checkout git fetch origin git rebase origin/main
Secara teknis, git rebase origin/main melakukan ini: Git mencari commit nenek moyang bersama antara feature/checkout dan origin/main, “melepas” tiap commit milikmu sejak titik itu, memindahkan HEAD ke ujung origin/main, lalu memutar ulang (replay) commit-commitmu satu demi satu. Karena induknya berubah, setiap commit mendapat hash baru. Isinya sama, identitasnya berbeda. Inilah inti dari “menulis ulang sejarah” yang harus kamu pahami benar sebelum melangkah lebih jauh.
Bayangkan commit-mu sebagai tanaman di pot. Merge menyambung dua pot dengan selang. Rebase mencabut tanamanmu dan menanamnya ulang di tanah main yang baru, seolah ia tumbuh di sana sejak awal.
Merge versus rebase
Keduanya menggabungkan kerja dari dua branch, tetapi menghasilkan sejarah yang berbeda secara mendasar. Merge jujur apa adanya: ia menyimpan fakta bahwa dua jalur paralel pernah ada lalu bertemu di satu merge commit. Rebase memilih kerapian: ia berpura-pura kerjamu memang dibangun di atas base terbaru, menghasilkan garis lurus tanpa merge commit.
| Aspek | Merge | Rebase |
|---|---|---|
| Sejarah | Bercabang, ada merge commit | Linear, tanpa merge commit |
| Hash commit | Tetap (tidak berubah) | Ditulis ulang (hash baru) |
| Kejujuran riwayat | Menyimpan jejak paralel | Menyembunyikan jejak paralel |
| Aman untuk branch shared? | Ya | Tidak, jangan |
flowchart LR
subgraph Merge
A1[main] --> M[merge commit]
B1[feature] --> M
end
subgraph Rebase
A2[main] --> C1[feature']
C1 --> C2[feature'']
endDua hasil akhir. Merge menyatu di satu titik; rebase memanjang lurus.
Bila commit sudah di-push dan dipakai orang lain, rebase menulis ulang hash-nya. Saat rekanmu menarik, Git melihat dua sejarah berbeda dan repo mereka kacau dengan commit ganda. Rebase hanya pada commit yang masih lokal dan belum dibagikan. Inilah aturan emas yang menghubungkan chapter ini dengan larangan force push ke branch bersama di Chapter 4.
Banyak tim menyetel git config —global pull.rebase true supaya git pull menumpuk commit lokal di atas perubahan remote alih-alih membuat merge commit “Merge branch main” yang berisik. Tambah git config —global rebase.autoStash true agar Git otomatis memarkir perubahan working tree saat rebase dan mengembalikannya setelah selesai.
Konflik saat rebase
Karena rebase memutar ulang commit satu per satu, konflik bisa muncul di commit mana pun di tengah jalan. Saat itu terjadi, rebase berhenti dan menunggu. Pola penyelesaiannya berbeda dari merge: kamu tidak commit, melainkan melanjutkan rebase.
Buka file bertanda, sunting, lalu git add file yang sudah beres.
Jalankan git rebase —continue, Git memutar commit berikutnya.
Bila ingin batal, git rebase —abort mengembalikan branch ke kondisi sebelum rebase.
Interactive rebase: poles sebelum PR
Inilah use-case rebase yang paling sering kamu pakai di tim nyata: merapikan branch draft sebelum dibaca reviewer, apalagi di tim yang memakai squash merge. git rebase -i membuka editor berisi daftar todo: tiap commit satu baris dengan kata kunci di depannya. Tiga commit “wip”, “fix typo”, dan “beneran fix” bisa dilebur jadi satu commit bersih yang menceritakan satu perubahan utuh, sehingga history main tetap terbaca rapi.
| Kata kunci | Arti |
|---|---|
pick | Pakai commit apa adanya |
reword | Pakai commit, tapi ubah pesannya |
squash | Lebur ke commit di atasnya, gabung kedua pesan |
fixup | Lebur ke commit di atasnya, buang pesannya |
edit | Berhenti di commit ini untuk diubah |
drop | Buang commit sepenuhnya |
Terminalgit rebase -i HEAD~3 # editor terbuka: # pick a1b2c3d add product handler # fixup d4e5f6a fix typo # fixup 9z8y7x6 wip # simpan & tutup → tiga commit jadi satu
Mengubah urutan baris di editor todo akan mengubah urutan commit saat replay. Pindahkan commit dokumentasi ke bawah, atau dekatkan fixup ke commit asalnya, lalu simpan.
Saat menulis artikel, kamu tidak menerbitkan setiap coretan. Kamu menggabung paragraf, menghapus catatan, lalu publish versi rapi. Interactive rebase adalah penyuntingan akhir itu untuk riwayat commit-mu.
Reset, Restore, Revert, dan Stash
Membatalkan perubahan dengan aman
Git punya beberapa cara membatalkan perubahan, dan salah memilih bisa menghapus kerja keras secara permanen.
Pertanyaan “bagaimana cara undo di Git?” tidak punya satu jawaban, karena tergantung kamu ingin membatalkan apa: perubahan file yang belum di-commit, staging yang keliru, atau commit yang sudah masuk sejarah. Empat perintah menangani kasus yang berbeda, dan memahami batas masing-masing menyelamatkanmu dari kehilangan data.
git restore: buang perubahan working tree
git restore menangani file yang sudah kamu ubah tapi belum di-commit. Ada dua arah: mengembalikan isi file ke versi terakhir, atau mengeluarkannya dari staging area.
Terminalgit restore internal/product/service.go # buang edit, kembali ke HEAD git restore --staged internal/product/service.go # unstage, edit tetap ada
Ctrl+Z di editor membatalkan ketikan terakhir di satu file. git restore bekerja di level snapshot repo, mengembalikan file ke kondisi commit terakhir sekaligus, bahkan setelah editor ditutup.
git reset: memindahkan HEAD
reset menggeser pointer HEAD ke commit lain, dan tiga modenya menentukan area mana yang ikut berubah. Inilah perintah yang paling sering disalahpahami, dan --hard adalah yang paling berbahaya.
| Mode | HEAD | Index (staging) | Working tree |
|---|---|---|---|
—soft | Pindah | Tetap (perubahan tetap staged) | Tetap |
—mixed (default) | Pindah | Di-reset (unstage) | Tetap |
—hard | Pindah | Di-reset | Ditimpa (perubahan hilang) |
Terminalgit reset --soft HEAD~1 # batalkan commit terakhir, isinya tetap tersimpan & staged git reset HEAD~1 # (--mixed) batalkan commit, isi jadi unstaged di working tree git reset --hard HEAD~1 # batalkan commit DAN buang semua perubahannya
--soft berguna saat kamu ingin menyusun ulang commit terakhir tanpa kehilangan apa pun. --mixed mengembalikan perubahan ke working tree untuk dipilah ulang. --hard membuang semuanya tanpa ampun.
Mode —hard menimpa working tree dan perubahan yang belum di-commit lenyap. Untuk commit yang sempat ada, git reflog masih merekam pergerakan HEAD dan bisa dipakai memulihkan (dibahas di Chapter 7), tapi file yang belum pernah di-commit sama sekali tidak terselamatkan.
git revert: undo aman untuk sejarah publik
reset cocok untuk commit lokal, tapi berbahaya bila commit sudah di-push. Untuk membatalkan commit yang sudah dibagikan, pakai git revert. Alih-alih menghapus, ia membuat commit baru yang isinya kebalikan dari commit target. Sejarah tetap utuh, hash lama tetap ada, dan rekanmu tidak terganggu.
flowchart LR A[C1] --> B[C2 buggy] --> C[C3] --> D[C4 revert C2]
Revert menambah, bukan menghapus. C4 membalik efek C2 tanpa menyentuh sejarah yang sudah dipush.
Terminalgit revert a1b2c3d # buat commit baru yang membalik a1b2c3d
Aturan praktis: commit belum di-push? reset boleh. Commit sudah di-push dan dipakai orang lain? Selalu revert, karena ia tidak menulis ulang sejarah yang sudah dimiliki orang. Ini cerminan aturan emas rebase di section sebelumnya.
git stash: simpan sementara
Kadang kamu sedang setengah jalan mengerjakan sesuatu lalu harus pindah branch untuk perbaikan mendesak. git stash menyimpan perubahan yang belum di-commit ke tumpukan terpisah, membersihkan working tree, lalu bisa kamu kembalikan nanti.
git stash push -m “wip checkout” menyimpan dan memberi label.
Working tree bersih, bebas git switch ke branch lain.
git stash pop menerapkan lalu menghapus dari tumpukan, atau git stash apply menerapkan tanpa menghapus.
Terminalgit stash push -m "wip checkout" git stash list # lihat semua stash git switch hotfix/price-bug # ... perbaiki, commit ... git switch feature/checkout git stash pop # lanjutkan kerja sebelumnya
Ringkasan
Membongkar-pasang history tanpa takut
Rebase menata sejarah agar rapi, empat alat undo membatalkan langkah keliru, dan satu aturan emas menjaga semuanya tetap aman.
Kamu kini bisa membedah history dengan percaya diri. Rebase memindahkan commit ke base terbaru dan, lewat mode interaktif, melebur draft jadi commit bersih sebelum PR, asal tidak pada sejarah yang sudah dibagikan. Untuk membatalkan, pilih alat sesuai sasaran: restore untuk file working tree, reset untuk menggeser HEAD (hati-hati --hard), revert untuk membatalkan commit publik dengan aman, dan stash untuk memarkir kerja sementara. Di Chapter 6 kita beralih dari operasi ke konvensi: tag, gitignore, hooks, Conventional Commits, dan workflow tim yang menata semua kemampuan ini untuk banyak orang.
Yang Wajib Menempel
git rebase mainmemindahkan commit branch ke atas base terbaru, hasilnya linear; setiap commit dapat hash baru.- Konflik rebase diselesaikan lalu
git rebase —continue, atau batalkan dengan—abort. - Aturan emas: jangan rebase (atau reset) commit publik yang sudah dipakai orang lain; pakai
revertuntuk itu. git rebase -idengan squash/fixup/reword merapikan draft commit sebelum PR.- Undo:
restore(file),reset—soft/—mixed/—hard(geser HEAD),revert(publik aman),stash(parkir sementara). reflogadalah jaring pengaman saatreset —hardtak sengaja, commit jarang benar-benar hilang.