Untuk membatalkan perubahan di Git, pilih perintah berdasarkan di mana perubahan itu berada. Perubahan yang belum di-commit dibatalkan dengan git restore. Commit lokal yang belum di-push bisa dibatalkan dengan git reset (soft, mixed, atau hard) atau diperbaiki dengan git commit --amend. Commit yang sudah di-push ke branch bersama sebaiknya dibatalkan dengan git revert, karena perintah ini membuat commit baru tanpa menulis ulang riwayat. Jika ada yang terlanjur hilang, git reflog hampir selalu bisa menyelamatkannya.
Artikel ini khusus membahas cara "undo" di Git, lengkap dengan tabel keputusan di bagian akhir. Semua perintah memakai sintaks Git modern (versi 2.23 ke atas, saat git restore dan git switch diperkenalkan).
Peta singkat: tiga area di Git
Memahami undo jauh lebih mudah jika Anda ingat tiga tempat perubahan bisa berada:
- Working directory: file yang sedang Anda edit.
- Staging area (index): perubahan yang sudah di-
git adddan siap di-commit. - Repositori (riwayat commit): perubahan yang sudah di-commit, ditunjuk oleh
HEADdan nama branch.
Setiap perintah undo bekerja pada satu atau beberapa area ini. Kebingungan biasanya muncul karena git reset bisa menyentuh ketiganya sekaligus tergantung opsinya.
git restore: membatalkan perubahan yang belum di-commit
Buang perubahan di working directory
git restore index.php
git restore . # semua file di folder saat ini
File dikembalikan ke versi yang ada di staging area (atau ke commit terakhir jika belum di-stage). Perubahan yang dibuang dengan cara ini tidak bisa dipulihkan lewat Git, karena belum pernah tersimpan di commit. Pastikan Anda benar-benar tidak membutuhkannya.
Keluarkan file dari staging (unstage)
git restore --staged index.php
Perubahan tetap ada di file Anda, hanya saja tidak lagi masuk antrean commit. Ini aman dan tidak menghilangkan apa pun.
Ambil versi file dari commit tertentu
git restore --source=HEAD~2 config/app.php
Perintah ini mengembalikan isi satu file seperti pada dua commit sebelumnya, tanpa mengubah riwayat. Hasilnya muncul sebagai perubahan biasa yang bisa Anda commit.
Pada Git versi lama, fungsi yang sama dilakukan dengan git checkout -- file dan git reset HEAD file. Keduanya masih berfungsi, tetapi git restore lebih jelas maksudnya.
File baru yang belum dilacak
git restore tidak menyentuh file yang belum pernah di-add. Untuk menghapusnya, gunakan git clean, dan selalu lihat dulu apa yang akan dihapus:
git clean -n # simulasi: tampilkan daftar file
git clean -fd # hapus file dan folder yang tidak dilacak
git commit --amend: memperbaiki commit terakhir
Lupa menambahkan file, atau pesan commit salah ketik? Selama commit tersebut belum di-push, --amend adalah cara paling rapi.
# ubah pesan commit terakhir
git commit --amend -m "Perbaiki validasi form registrasi"
# tambahkan file yang terlupa tanpa mengubah pesan
git add tests/RegistrasiTest.php
git commit --amend --no-edit
Penting dipahami: --amend tidak "mengedit" commit lama, melainkan membuat commit baru dengan hash berbeda dan mengganti commit terakhir. Jika commit lama sudah di-push, riwayat lokal dan remote akan berbeda, dan Anda harus force push. Untuk branch yang dipakai bersama, hindari ini. Tips menulis pesan commit yang baik sudah dibahas di artikel tersendiri, jadi di sini kita fokus pada cara membatalkannya.
git reset: memundurkan branch
git reset <commit> memindahkan penunjuk branch saat ini ke commit lain. Opsi yang dipakai menentukan apa yang terjadi pada staging area dan working directory.
| Opsi | Riwayat (HEAD) | Staging area | Working directory | Risiko |
|---|---|---|---|---|
--soft | Mundur | Tetap (perubahan dari commit yang dibatalkan tetap ter-stage) | Tetap | Aman |
--mixed (default) | Mundur | Dikosongkan sesuai commit tujuan | Tetap (perubahan jadi unstaged) | Aman |
--hard | Mundur | Disamakan | Disamakan; perubahan dibuang | Berbahaya |
reset --soft: gabungkan atau tulis ulang commit
git reset --soft HEAD~3
git commit -m "Tambah fitur ekspor laporan"
Tiga commit terakhir dibatalkan, tetapi semua perubahannya tetap ter-stage. Commit ulang, dan tiga commit kecil menjadi satu commit yang rapi. Ini cara sederhana untuk "squash" commit lokal tanpa rebase interaktif.
reset --mixed: batalkan commit, simpan perubahan
git reset HEAD~1
Commit terakhir dibatalkan, perubahannya kembali ke working directory sebagai perubahan yang belum di-stage. Cocok jika Anda ingin memecah satu commit besar menjadi beberapa commit, dengan git add per bagian.
reset --hard: buang commit dan perubahannya
git reset --hard HEAD~1
git reset --hard origin/main # samakan persis dengan remote
Branch mundur dan semua perubahan, baik yang ter-stage maupun belum, ikut dibuang. Commit yang dibatalkan masih bisa diselamatkan lewat reflog, tetapi perubahan yang belum pernah di-commit akan hilang permanen. Sebelum menjalankan --hard, jalankan git status dan pertimbangkan git stash untuk berjaga-jaga.
Notasi HEAD~ yang perlu diketahui
HEAD~1atauHEAD~: satu commit sebelum HEAD.HEAD~3: tiga commit sebelumnya.- Anda juga bisa memakai hash commit langsung, misalnya
git reset --soft a1b2c3d.
git revert: membatalkan commit yang sudah di-push
Ketika commit sudah ada di remote dan mungkin sudah di-pull orang lain, menulis ulang riwayat dengan reset akan merepotkan seluruh tim. git revert menyelesaikan masalah ini dengan membuat commit baru yang isinya kebalikan dari commit yang ingin dibatalkan.
git revert a1b2c3d
git push
Riwayat tetap utuh dan jujur: siapa pun bisa melihat bahwa ada perubahan yang dibatalkan dan kapan. Tidak perlu force push.
Revert beberapa commit
# revert rentang commit tanpa langsung commit, lalu satukan
git revert --no-commit a1b2c3d^..f6e5d4c
git commit -m "Batalkan fitur diskon yang bermasalah"
Revert merge commit
Merge commit punya dua induk, jadi Git perlu tahu sisi mana yang dianggap "utama". Biasanya Anda memakai induk pertama, yaitu branch tempat merge dilakukan:
git revert -m 1 <hash-merge-commit>
Catatan penting: setelah merge di-revert, jika nanti Anda ingin me-merge ulang branch yang sama, Git menganggap commit-commit di branch itu sudah pernah masuk. Anda perlu me-revert commit revert tersebut terlebih dahulu agar perubahannya kembali.
Jika revert menghasilkan konflik, cara menyelesaikannya sama seperti konflik merge biasa: perbaiki file, git add, lalu git revert --continue.
Membatalkan commit yang sudah di-push dengan aman
Ada dua skenario dengan solusi berbeda:
Berlangganan gratis. Artikel & tutorial coding terbaru langsung ke email kamu. Tanpa spam.
Branch bersama (main, develop)
Gunakan git revert. Ini satu-satunya pilihan yang tidak mengganggu orang lain. Banyak tim juga memproteksi branch utama sehingga force push memang tidak diizinkan.
Branch pribadi (feature branch yang hanya Anda pakai)
Anda boleh menulis ulang riwayat dengan reset atau amend, lalu push ulang dengan --force-with-lease:
git reset --hard HEAD~1
git push --force-with-lease
--force-with-lease lebih aman daripada --force karena push akan ditolak jika remote ternyata berisi commit yang belum Anda lihat, misalnya rekan sempat push ke branch yang sama. Dengan --force biasa, commit mereka akan tertimpa tanpa peringatan.
Jika yang ter-push adalah data rahasia
Jika commit tersebut berisi password atau API key, revert tidak cukup karena isinya masih ada di riwayat. Ganti kredensial tersebut segera, lalu bersihkan riwayat dengan alat seperti git filter-repo. Untuk password baru yang kuat, Anda bisa memakai Password Generator.
git reflog: jaring pengaman terakhir
Reflog mencatat setiap pergerakan HEAD di repositori lokal Anda: commit, reset, checkout, rebase, amend. Artinya, commit yang "hilang" setelah reset --hard atau rebase yang kacau sebenarnya masih ada dan bisa ditemukan.
git reflog
Contoh keluaran:
3f9a1c2 HEAD@{0}: reset: moving to HEAD~2
8d7e6b5 HEAD@{1}: commit: Tambah halaman laporan
c4b3a29 HEAD@{2}: commit: Tambah export CSV
...
Untuk kembali ke kondisi sebelum reset:
git reset --hard HEAD@{1}
# atau lebih aman: buat branch baru di commit tersebut
git branch penyelamatan 8d7e6b5
Membuat branch baru adalah pilihan yang lebih aman karena tidak mengubah apa pun di branch saat ini; Anda bisa memeriksa isinya dulu sebelum memutuskan.
Batasan reflog yang perlu diketahui:
- Reflog hanya ada di repositori lokal, tidak ikut di-push atau di-clone.
- Entri reflog kedaluwarsa. Secara default, entri untuk commit yang tidak lagi terjangkau dari branch mana pun disimpan 30 hari, dan entri lainnya 90 hari, sebelum dibersihkan oleh
git gc. - Reflog tidak bisa memulihkan perubahan yang tidak pernah di-commit atau di-stash.
Tabel keputusan: perintah mana yang dipakai?
| Situasi | Perintah | Aman untuk branch bersama? |
|---|---|---|
| Ingin membuang edit di file yang belum di-stage | git restore file | Ya (lokal saja) |
Salah git add | git restore --staged file | Ya (lokal saja) |
| Pesan commit terakhir salah, belum push | git commit --amend | Hanya jika belum di-push |
| Lupa file di commit terakhir, belum push | git add + git commit --amend --no-edit | Hanya jika belum di-push |
| Ingin menggabungkan beberapa commit lokal | git reset --soft HEAD~N lalu commit | Hanya jika belum di-push |
| Batalkan commit tapi simpan perubahannya | git reset HEAD~1 | Hanya jika belum di-push |
| Buang commit lokal beserta perubahannya | git reset --hard HEAD~1 | Tidak |
| Batalkan commit yang sudah di-push | git revert <hash> | Ya |
| Batalkan merge yang sudah di-push | git revert -m 1 <hash> | Ya |
| Perbaiki commit di branch pribadi yang sudah di-push | reset/amend + git push --force-with-lease | Tidak |
| Commit hilang setelah reset atau rebase | git reflog + git branch/git reset | Lokal saja |
Kesalahan umum
- Menjalankan
git reset --hardsaat masih ada perubahan yang belum di-commit, lalu kehilangan pekerjaan. - Melakukan amend atau reset pada commit yang sudah di-push ke branch bersama, kemudian force push dan menimpa pekerjaan rekan.
- Memakai
--forcepadahal--force-with-leasetersedia. - Mengira revert menghapus data rahasia dari riwayat.
- Lupa opsi
-m 1saat me-revert merge commit, sehingga Git menolak perintahnya. - Menjalankan
git clean -fdtanpa-nterlebih dahulu. - Panik dan meng-clone ulang repositori, padahal reflog di clone lama bisa memulihkan commit.
Ringkasan
- Belum di-commit:
git restore(dan--stageduntuk unstage). - Commit terakhir perlu diperbaiki dan belum di-push:
git commit --amend. - Commit lokal ingin dibatalkan:
git resetdengan--soft,--mixed, atau--hardsesuai kebutuhan. - Sudah di-push ke branch bersama:
git revert. - Branch pribadi yang sudah di-push: tulis ulang lalu
--force-with-lease. - Sesuatu hilang:
git reflog.
FAQ
Apa beda git reset dan git revert?
git reset memindahkan branch ke commit lama, seolah commit setelahnya tidak pernah ada (riwayat ditulis ulang). git revert membuat commit baru yang membatalkan efek commit lama, sehingga riwayat tetap utuh. Reset cocok untuk commit lokal, revert untuk commit yang sudah dibagikan.
Bisakah memulihkan file setelah git restore?
Tidak lewat Git, karena perubahan yang belum di-commit tidak pernah tersimpan di repositori. Kemungkinan terakhir adalah fitur riwayat lokal di editor Anda (misalnya Local History di VS Code atau IDE JetBrains).
Bagaimana membatalkan git add .?
Jalankan git restore --staged .. Semua file keluar dari staging area, sementara isinya tetap seperti yang Anda edit.
Bagaimana membatalkan git revert?
Jika revert belum di-push, Anda bisa git reset --hard HEAD~1. Jika sudah di-push, revert commit revert-nya: git revert <hash-commit-revert>.
Apakah git reset --hard bisa dibatalkan?
Commit yang terbuang bisa dipulihkan lewat git reflog. Namun perubahan di working directory yang belum pernah di-commit atau di-stash tidak bisa dipulihkan oleh Git.