Chapter sebelumnya menutup satu varian penolakan dengan resep fetch → gabungkan → push. Varian keduanya lebih dalam: penolakan non-fast-forward yang muncul ketika kita menulis ulang commit yang sudah dipublikasikan — lewat git commit --amend atau rebase — lalu mencoba push hasil tulisan barunya. Git menolak demi melindungi siapa pun yang sudah membangun di atas riwayat lama; melanggar perlindungan itu butuh --force, dan --force punya versi berpelindung: --force-with-lease. Chapter ini menjalankan ketiganya di satu panggung, lengkap dengan insiden hilangnya pekerjaan Siti di remote.
Ketika Riwayat Ditulis Ulang #
Lab memakai tiga babak persiapan. Pertama Budi mengirim catatan stok dari clone-nya:
git pushOutput yang Dihasilkan:
To /home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-force/proyek-utama.git
e2d6081..1382cfe main -> mainKedua, Siti meng-clone keadaan itu dan mengirim halaman kontak — remote maju lagi. Ketiga, Budi menariknya supaya salinannya jujur:
git fetch originOutput yang Dihasilkan:
From /home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-force/proyek-utama
1382cfe..0667253 main -> origin/mainBaru kemudian kejadian intinya: Budi menelaah catatan stoknya, merasa isinya kurang, dan memperbaiki commit yang sudah terkirim itu — bukan dengan commit baru, melainkan menulis ulang yang lama:
printf 'Catatan stok harian\n- kopi 12 kg\n' > catatan.md
git add catatan.md
git commit --amend -m "Lengkapi catatan stok"Amend menciptakan commit baru yang menggantikan yang lama — mekanismenya dibedah di chapter Amend Commit
. Commit lama masih tercatat di remote, dan salinan Budi memegang keduanya: riwayat barunya plus cermin origin/main. Push-nya ditolak:
git pushOutput yang Dihasilkan:
To /home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-force/proyek-utama.git
! [rejected] main -> main (non-fast-forward)
error: failed to push some refs to '/home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-force/proyek-utama.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. If you want to integrate the remote changes,
hint: use 'git pull' before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.Alasannya berbeda dari fetch first di chapter Push Rejected
: Budi sudah memegang commit terjauh remote — origin/main-nya segar — tetapi riwayat barunya tidak memuat commit lama yang masih duduk di remote. Push yang diloloskan akan membuang commit lama itu dan semua yang dibangun di atasnya. Penolakan non-fast-forward adalah kata “yakin?” dari Git.
Kekuatan yang Berbahaya: –force #
Jawaban paksa ada, dan namanya sejujur isi peringatannya:
git push --forceOutput yang Dihasilkan:
To /home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-force/proyek-utama.git
+ 0667253...696fbc9 main -> main (forced update)Penanda + dan keterangan (forced update) menandakan penunjuk main di remote digeser bukan maju, melainkan dipindahkan paksa ke riwayat tulisan baru Budi. Remote kini berbunyi: hanya Buat README toko dan Lengkapi catatan stok. Konsekuensinya terlihat dari mata Siti:
git fetchOutput yang Dihasilkan (di clone siti):
From /home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-force/proyek-utama
+ 0667253...696fbc9 main -> origin/main (forced update)git log --oneline origin/mainOutput yang Dihasilkan (di clone siti):
696fbc9 Lengkapi catatan stok
e2d6081 Buat README tokogit log --oneline mainOutput yang Dihasilkan (di clone siti):
0667253 Tambah halaman kontak
1382cfe Tambah catatan stok
e2d6081 Buat README tokoDua keluaran terakhir memperlihatkan tabrakan yang menyakitkan: cermin origin/main Siti sudah tidak lagi memuat Tambah halaman kontak, padahal commit itu masih hidup di main lokalnya. Pekerjaan Siti terkubur di remote — siapa pun yang meng-clone baru tidak akan pernah melihatnya. Cermin Siti yang bergerak mundur — baris + 0667253...696fbc9 (forced update) — adalah wajah dari pemaksaan itu. Siti masih bisa menyelamatkan komitnya karena memegang salinan lokal, dan objek Git yang terputus pun belum langsung terhapus sebelum pembersihan gc — jaring pengaman ini dibedah di chapter git reflog
. Namun penyelamatan seperti itu hanya mungkin bagi yang kebetulan memegang salinannya.
–force-with-lease: Menolak Saat Kita Pergi Melamun #
Versi berpelindung menambahkan satu syarat kecil yang mengubah segalanya: push baru boleh menimpa bila kondisi remote masih sama seperti terakhir kali kita melihatnya — tepat pada posisi origin/* di salinan kita. Bila remote sudah bergerak sejak itu, push gagal. Skenarionya kita lanjutkan: Siti menerima kenyataan, membarui clone-nya, lalu mengirim halaman promo baru:
git reset --hard origin/main
git pushOutput yang Dihasilkan (perintah kedua, di clone siti):
To /home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-force/proyek-utama.git
696fbc9..6b1a8b0 main -> maingit reset --hard memindahkan branch aktif ke titik lain dan menimpa working tree — alatnya dibedah di chapter Reset: Soft, Mixed, Hard
. Remote maju lagi. Budi, yang salinannya tertinggal satu langkah, kini merapikan catatan stok sekali lagi dengan amend — lalu mencoba lease:
git push --force-with-leaseOutput yang Dihasilkan:
To /home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-force/proyek-utama.git
! [rejected] main -> main (stale info)
error: failed to push some refs to '/home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-force/proyek-utama.git'Penanda (stale info) memberitahu persis penyakitnya: informasi lease Budi basi — catatan terakhirnya menyebut remote di posisi lama, sedangkan remote kini memegang commit promo Siti yang belum pernah dilihat Budi. Tanpa --force-with-lease, --force akan mengubur commit promo itu persis seperti insiden sebelumnya.
Lease Menolak: Saatnya Melihat dulu #
Penolakan lease bukan halangan, melainkan pintu inspeksi. Budi menarik keadaan sebenarnya:
git fetch originOutput yang Dihasilkan:
From /home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-force/proyek-utama
696fbc9..6b1a8b0 main -> origin/mainSekarang Budi melihat promo Siti, dan pilihannya sadar: perbaikan kecil itu tidak layak menimpa apa pun. Ia membuang tulisan ulangnya dan mengulang perbaikan sebagai commit baru di atas keadaan terkini:
git reset --hard origin/mainOutput yang Dihasilkan:
HEAD is now at 6b1a8b0 Tambah halaman promoprintf 'Catatan stok harian\n- kopi 12 kg\n- gula 5 kg\n' > catatan.md
git add catatan.md
git commit -m "Rapikan catatan stok"
git pushOutput yang Dihasilkan (perintah terakhir):
To /home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-force/proyek-utama.git
6b1a8b0..4dd7b3e main -> mainRentang maju biasa tanpa pemaksaan — kedua pekerjaan hidup berdampingan.
Lease Lolos saat Remote Bersih #
Skenario pamungkas: keadaan di mana menulis ulang memang wajar. Budi baru saja push, lalu sadar pesan commit terakhirnya kurang tepat dan menyempurnakannya dengan amend. Push biasa ditolak non-fast-forward — tetapi remote tidak bergerak sejak push itu, posisi yang tercatat salinannya masih akurat:
git push --force-with-leaseOutput yang Dihasilkan:
To /home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-force/proyek-utama.git
+ 4dd7b3e...bca1ce6 main -> main (forced update)Lease lolos karena yang ditimpa hanya versi lama milik Budi sendiri — persis skenario “memperbaiki commit sendiri yang baru terkirim” atau “mempublikasikan ulang branch pribadi setelah rebase”. Menjadikannya kebiasaan bisa lewat konfigurasi:
git config push.forceWithLease trueDengan konfigurasi itu, git push --force polos pun diperlakukan sebagai --force-with-lease. Rincian keduanya terdokumentasi di dokumentasi git push
.
| Situasi | Alat yang tepat | Alasan |
|---|---|---|
| Branch pribadi, ingin menulis ulang | --force-with-lease | hanya kita yang membangun di atasnya |
| Publish ulang setelah rebase | --force-with-lease setelah fetch | pastikan lihat dulu kondisi terkini |
| Membenahi commit sendiri yang baru terkirim | --force-with-lease | yang ditimpa versi lama kita |
Branch bersama seperti main | jangan force — gabungkan | pekerjaan rekan ikut terkubur |
Kini kedua penolakan push dan seluruh jalan keluarnya sudah kita pegang: fetch first diselesaikan penggabungan, non-fast-forward ditangani lease dengan mata terbuka. Alat pertukarannya lengkap — yang belum hanyalah kebiasaan memakainya dalam irama kerja harian. Chapter berikutnya merangkainya menjadi satu rutinitas penuh, dari pull pagi hingga push penutup.