Perbandingan

git reset dan git revert: cara membatalkan commit tanpa merusak riwayat tim

Diperbarui: · Skillaria.Top

git reset memindahkan penunjuk branch ke commit lain dan menulis ulang riwayat, sehingga hanya cocok untuk commit lokal yang belum dikirim. git revert membuat commit baru berisi kebalikan dari perubahan, tanpa mengubah riwayat, sehingga aman untuk membatalkan commit yang sudah ada di server.

Ringkasnya: git reset memundurkan branch dan membuat seolah-olah commit tambahan tidak pernah ada. git revert membiarkan riwayat apa adanya dan menambahkan commit baru yang membatalkan perubahan commit lama. Yang pertama cocok untuk pekerjaan lokal, yang kedua untuk apa pun yang sudah masuk repositori bersama. Jika hanya satu aturan ini yang diingat, sebagian besar kecelakaan dengan Git bisa dihindari.

Berikut ini dijelaskan cara kerja kedua perintah, perbedaan mode reset, cara membatalkan commit setelah push, cara mengembalikan commit yang «hilang», dan peran git clean.

Tiga lapisan yang menentukan perintah pembatalan

Untuk memahami perbedaannya, ingat tiga area di Git: folder kerja (berkas di disk), index (staging area, yaitu yang akan masuk ke commit berikutnya), dan riwayat (commit yang ditunjuk branch dan HEAD). Setiap perintah pembatalan bekerja pada kombinasi area yang berbeda.

PerintahRiwayatIndexFolder kerjaAman untuk branch bersama
git restore berkastidaktidakyaya
git restore --staged berkastidakyatidakya
git reset --softyatidaktidaktidak
git reset --mixed (default)yayatidaktidak
git reset --hardyayayatidak
git revertmenambah commit——ya
git cleantidaktidakmenghapus berkas yang tidak dilacakya, tetapi tidak dapat dibatalkan

Cara kerja git reset

Perintah git reset <commit> memindahkan penunjuk branch aktif (dan HEAD ikut bergerak) ke commit yang ditentukan. Commit setelahnya tidak dihapus secara fisik, tetapi tidak lagi terlihat di branch. Mode menentukan apa yang terjadi pada index dan berkas.

git reset --soft: membatalkan commit dan menyisakan perubahan di index

Branch bergeser, sementara index dan berkas tetap seperti semula. Semua perubahan dari commit yang dibatalkan kini sudah siap untuk di-commit. Ini cara ideal untuk menulis ulang pesan atau menggabungkan beberapa commit terakhir menjadi satu.

git reset --soft HEAD~3
git commit -m "feat: formulir pendaftaran"

Tiga commit terakhir berubah menjadi satu, dan isi berkasnya tidak berubah.

git reset --mixed: membatalkan commit dan index

Ini mode default: git reset HEAD~1 sama dengan git reset --mixed HEAD~1. Branch bergeser, index dikosongkan, dan perubahan tetap ada di folder kerja sebagai perubahan yang belum di-stage. Berguna jika Anda sudah commit hal yang keliru dan ingin memutuskan ulang apa saja yang akan di-add dan dalam porsi apa.

git reset HEAD~1
git status
# Changes not staged for commit:
#   modified:   app.py
#   modified:   config.yml

git reset --hard: kembali sepenuhnya

Branch, index, dan folder kerja dikembalikan ke keadaan commit yang ditentukan. Semua perubahan yang belum di-commit pada berkas yang dilacak hilang tanpa peringatan. Ini satu-satunya mode reset yang benar-benar bisa menghancurkan pekerjaan Anda.

git reset --hard HEAD~1          # buang commit terakhir beserta semua perubahan
git reset --hard origin/main     # samakan branch dengan keadaan server

Sebelum --hard, jalankan git status, dan gunakan git stash jika ada yang berharga. Perubahan yang sudah di-commit masih bisa dikembalikan (lihat bagian pemulihan di bawah), tetapi yang belum di-commit tidak.

git reset untuk satu berkas

Dengan path, reset tidak memindahkan branch, hanya mengubah index: git reset app.py mengeluarkan berkas dari index. Padanan modernnya adalah git restore --staged app.py, yang lebih jelas. Flag --soft dan --hard tidak berlaku untuk path.

Cara kerja git revert

git revert <commit> menghitung perubahan commit tersebut, menerapkannya dalam arah sebaliknya, lalu membuat commit baru. Baris yang ditambahkan dihapus, baris yang dihapus dikembalikan. Riwayat bertambah ke depan dan tidak ada yang ditulis ulang, sehingga rekan tim tidak perlu memperbaiki apa pun di komputer mereka.

git log --oneline
# a3f9c21 (HEAD -> main) docs: README
# 7be41d0 feat: cache untuk respons API
# 1c02e8f fix: timeout permintaan

git revert 7be41d0
# [main 5d8e2aa] Revert "feat: cache untuk respons API"
#  2 files changed, 3 insertions(+), 41 deletions(-)

Git akan membuka editor dengan pesan seperti Revert "..." dan baris This reverts commit 7be41d0.... Sebaiknya tambahkan alasan pembatalan di pesan itu.

Flag revert yang berguna

  • --no-edit — memakai pesan standar tanpa membuka editor.
  • -n (--no-commit) — menerapkan kebalikan perubahan ke index tanpa membuat commit. Dengan cara ini beberapa commit bisa dibatalkan dalam satu commit.
  • git revert A..B — membatalkan rentang commit (masing-masing dengan commit revert, dari yang terbaru ke yang terlama).
  • -m 1 — wajib untuk commit merge: menentukan induk mana yang dianggap jalur utama.
git revert --no-commit HEAD~3..HEAD
git commit -m "Revert: membatalkan tiga commit eksperimen"

Revert commit merge

Commit merge memiliki dua induk, dan Git tidak tahu terhadap induk mana perubahan «kebalikan» harus dihitung. Tanpa -m, Git akan menampilkan error is a merge but no -m option was given. Biasanya branch utama adalah induk pertama:

git revert -m 1 9f1e2ab

Jebakannya: jika nanti Anda ingin menggabungkan kembali branch tersebut, Git akan menganggap commit-commit-nya sudah tergabung, dan perubahan tidak ikut masuk. Solusinya adalah membatalkan commit revert itu terlebih dahulu, lalu menambahkan perubahan baru.

git reset vs git revert: mana yang dipilih

Kriteriagit resetgit revert
Dampak pada riwayatMenulis ulang (commit hilang dari branch)Menambah commit baru
Commit sudah di-pushPerlu push --force, merusak pekerjaan rekanCukup git push biasa
Membatalkan commit di tengah riwayatHanya bersama semua commit sesudahnyaBisa secara terpisah
Jejak di riwayatTidak adaTetap ada, terlihat siapa dan kapan membatalkan
Skenario tipikalMembersihkan commit lokal sebelum pushMembatalkan commit yang merusak produksi di main

Aturan sederhananya: jika commit sudah pernah dilihat orang lain, gunakan revert; jika belum, gunakan reset. Pengecualian adalah branch fitur pribadi yang belum disentuh siapa pun: di sana menulis ulang riwayat dan git push --force-with-lease masih wajar.

Mengapa reset --hard di branch bersama berbahaya

Bayangkan Anda menjalankan git reset --hard HEAD~2 di main lalu git push --force. Rekan Anda masih memiliki kedua commit itu. Saat mereka menjalankan git pull, Git mencoba menggabungkan riwayat mereka dengan riwayat Anda, dan commit yang «dihapus» tadi muncul kembali, lengkap dengan commit merge yang tidak perlu. Lebih buruk lagi, jika ada rekan yang sudah mengirim commit di atas commit tersebut, force push akan menimpanya begitu saja.

Karena itu, branch yang dilindungi (main, release) biasanya melarang force push di pengaturan hosting. Jika penulisan ulang tidak bisa dihindari, gunakan git push --force-with-lease: perintah ini menolak jika di server ada commit yang belum Anda lihat.

Skenario pembatalan yang umum

Membatalkan commit terakhir yang belum di-push

git reset --soft HEAD~1   # perubahan tetap di index, bisa di-commit ulang
git reset HEAD~1          # perubahan tetap di berkas, index kosong
git reset --hard HEAD~1   # perubahan dibuang

Jika hanya ingin memperbaiki pesan atau menambahkan berkas yang terlupa, reset tidak diperlukan: cukup git add berkas-terlupa lalu git commit --amend.

Membatalkan commit yang sudah di-push

git revert <hash>
git push

Inilah jawaban untuk pertanyaan umum «bagaimana membalik commit». Tidak ada perintah bernama git reverse di Git; commit kebalikan dibuat oleh git revert.

Mengembalikan branch ke keadaan server

git fetch origin
git reset --hard origin/main

Berguna ketika branch lokal kacau setelah rebase yang gagal atau eksperimen. Semua commit lokal yang tidak ada di server akan hilang dari branch.

Memulihkan commit setelah reset yang keliru

Git mencatat setiap perpindahan HEAD di log bernama reflog. Commit yang tertinggal setelah reset tetap berada di basis data objek setidaknya beberapa minggu (secara default, entri reflog yang tidak terjangkau disimpan 30 hari).

git reflog
# 1c02e8f HEAD@{0}: reset: moving to HEAD~2
# a3f9c21 HEAD@{1}: commit: docs: README
# 7be41d0 HEAD@{2}: commit: feat: cache untuk respons API

git reset --hard a3f9c21   # atau HEAD@{1}

Reflog bersifat lokal: ia hanya ada di klon Anda dan tidak dikirim ke server.

git clean: menghapus berkas yang tidak dilacak

git reset --hard tidak menyentuh berkas yang tidak dilacak Git: berkas baru yang belum pernah di-add, artefak build, dan log. Untuk itu ada git clean. Perintah ini tidak dapat dibatalkan: berkas yang dihapusnya tidak masuk ke reflog maupun tempat sampah.

git clean -n      # dry run: tampilkan apa yang akan dihapus
git clean -f      # hapus berkas yang tidak dilacak
git clean -fd     # sama, ditambah folder yang tidak dilacak
git clean -fdx    # ditambah berkas yang diabaikan (.gitignore): node_modules, dist
git clean -i      # pilih secara interaktif

Tanpa -f, Git menolak bekerja secara default (pengaturan clean.requireForce). Selalu mulai dengan -n, terutama dengan -x: flag ini juga menghapus .env lokal Anda jika berkas itu ada di daftar pengabaian.

Kombinasi untuk mengembalikan proyek ke keadaan commit terakhir sepenuhnya: git reset --hard && git clean -fd.

Kesalahan yang sering terjadi

  • reset --hard padahal seharusnya --soft. Commit masih bisa diselamatkan lewat reflog, tetapi perubahan yang belum di-commit sudah hilang. Kebiasaan menjalankan git stash sebelum eksperimen akan menyelesaikan masalah ini.
  • revert tanpa memahami ketergantungan. Jika commit-commit yang lebih baru mengubah baris yang sama, revert akan menimbulkan konflik. Selesaikan seperti biasa: perbaiki berkas, git add, lalu git revert --continue; jika berubah pikiran, git revert --abort.
  • Tertukar antara restore dan reset. Untuk membatalkan perubahan pada satu berkas, Anda tidak perlu reset seluruh branch: cukup git restore berkas.
  • Force push ke main. Lebih baik revert dan push biasa, meskipun riwayat menjadi sedikit lebih panjang.

Ringkasan

git reset adalah alat untuk riwayat pribadi yang belum dipublikasikan: --soft menyimpan perubahan di index, --mixed di berkas, dan --hard membuang semuanya. git revert adalah cara membatalkan yang aman di branch bersama, dan meninggalkan jejak yang jujur di riwayat. git clean membersihkan berkas yang tidak dilacak, tetapi tidak memberi kesempatan kedua. Skenario pembatalan dengan restore, reset, dan revert dibahas dengan praktik dalam kursus Git.

Pertanyaan umum

Apakah git reset menghapus commit selamanya?

Tidak. Commit tetap ada di basis data objek dan bisa diakses lewat git reflog, sampai dibersihkan oleh garbage collector, yang secara default baru terjadi setelah 30 hari untuk entri yang tidak terjangkau.

Bisakah revert dibatalkan?

Bisa. Commit revert adalah commit biasa, jadi bisa dibatalkan dengan git revert lagi, atau jika belum di-push, dihapus dengan git reset.

Apa bedanya git reset dengan git checkout?

git reset memindahkan penunjuk branch aktif, sedangkan git checkout (atau git switch) memindahkan HEAD ke branch atau commit lain tanpa mengubah branch yang ditinggalkan.

Apa arti HEAD~1 dan HEAD^?

Keduanya menunjuk induk dari commit saat ini. HEAD~3 adalah leluhur ketiga lewat induk pertama, sedangkan HEAD^2 adalah induk kedua dari commit merge.

Bagaimana cara membatalkan git clean?

Dengan Git tidak bisa, karena berkas yang tidak dilacak memang tidak pernah disimpan di repositori. Itulah sebabnya selalu jalankan git clean -n terlebih dahulu.

Pelajari topik ini lewat video

Topik ini dibahas mendalam dengan praktik di kursus “Git dari Nol hingga Pengembang Percaya Diri”.

Ke kursus