Skenario paling klasik dalam kolaborasi Git: dua orang mengerjakan hal berbeda pada branch yang sama, salah satu push lebih dulu, dan push yang kedua ditolak. Keluaran penolakannya panjang, penuh ! dan hint, dan kerap dibaca pemula sebagai bencana — padahal tidak satu byte pekerjaan yang hilang, dan penyelesaiannya hanya tiga langkah teratur. Chapter ini mereproduksi penolakan itu secara nyata dengan Budi dan Siti, membedah pesannya baris demi baris, lalu menuntaskan skenario sampai push akhirnya lulus — menutup janji yang digantung di akhir chapter git push
.
Mereproduksi Penolakan #
Lab-nya mewarisi pola section ini: bare repository proyek-utama.git berisi satu commit awal dari clone penyemai, Budi dan Siti masing-masing meng-clone-nya. Siti lebih dulu selesai — halaman kontak — dan langsung mengirim:
git pushOutput yang Dihasilkan (di clone siti):
To /home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-reject/proyek-utama.git
bf0d4bd..f33ebb8 main -> mainRemote maju satu commit. Budi, yang tidak menarik apa pun, sedang menyempurnakan halaman diskon: diskon.md dibuat, commit dijalankan, lalu giliran push-nya tiba:
git pushOutput yang Dihasilkan:
To /home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-reject/proyek-utama.git
! [rejected] main -> main (fetch first)
error: failed to push some refs to '/home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-reject/proyek-utama.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. This is usually caused by another repository pushing to
hint: the same ref. If you want to integrate the remote changes, use
hint: 'git pull' before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.Membaca Pesan Penolakan #
Baris ! [rejected] main -> main (fetch first) adalah intinya: remote menolak pergeseran main karena alasan (fetch first) — pihak remote memegang commit yang tidak dimiliki Budi, dan menggeser main tanpa memuat commit itu akan menguburnya. Baris error: failed to push some refs to '...' menegaskan kegagalan itu secara formal — refs adalah penunjuk seperti main; sebagian penunjuk gagal dikirim, dan alamat tujuannya tercantum lengkap.
Empat baris hint: adalah panduan penyelesaian yang jujur: penolakan ini biasanya terjadi karena repository lain mendorong ke penunjuk yang sama, dan jalan keluarnya adalah menggabungkan perubahan remote — git pull — sebelum push ulang. Catatan fast-forward yang dirujuk hint terakhir terbaca lengkap lewat git push --help maupun dokumentasi git push
. Perlu dicatat ulang: commit Budi tidak hilang. Semua aman di repository lokal; yang ditolak hanyalah pergeseran penunjuk di remote.
Langkah Pertama Tarik, Jangan Tebak #
Kita pecahkan dengan urutan eksplisit — fetch dulu, agar terlihat apa yang sebenarnya terjadi di balik git pull:
git fetch originOutput yang Dihasilkan:
From /home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-reject/proyek-utama
bf0d4bd..f33ebb8 main -> origin/maingit statusOutput yang Dihasilkan:
On branch main
Your branch and 'origin/main' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" if you want to integrate the remote branch with yours)
nothing to commit, working tree cleanKata kuncinya diverged: main Budi dan origin/main masing-masing membawa satu commit yang tidak dimiliki pihak lain — cermin di chapter Remote-Tracking Branch
kini memperlihatkan keadaan sebenarnya. Sebelum menggabungkan, kita periksa dulu apa yang masuk:
git log --oneline main..origin/mainOutput yang Dihasilkan:
f33ebb8 Tambah halaman kontakSatu commit Siti itulah seluruh “pekerjaan yang kita tidak punya” — persis klaim hint tadi. Kualitasnya bisa ditelaah dengan git show atau git diff main origin/main sebelum diputuskan cara menggabungkannya.
Menggabungkan lalu Push Lagi #
Dua jalan penggabungan tersedia — merge atau rebase — dan keduanya sudah dibedah di chapter git pull . Kita pakai merge agar bentuk riwayatnya terlihat jelas:
git merge origin/mainOutput yang Dihasilkan:
Merge made by the 'ort' strategy.
kontak.md | 1 +
1 file changed, 1 insertion(+)
create mode 100644 kontak.mdGit membuka editor dengan pesan bawaan Merge remote-tracking branch 'origin/main'; kita simpan apa adanya — atau menambahkan --no-edit bila ingin melewati editor. Dua pekerjaan kini berdamai dalam satu commit merge; bentuknya tergambar di graf riwayat:
git log --oneline --graph -5Output yang Dihasilkan:
* c3d1047 Merge remote-tracking branch 'origin/main'
|\
| * f33ebb8 Tambah halaman kontak
* | c1f6fec Tambah halaman diskon
|/
* bf0d4bd Buat README tokoEmpat commit berdiri di graf: kaki kiri pekerjaan Budi, kaki kanan pekerjaan Siti, puncaknya commit merge. Push ulang kini tidak menimpa apa pun — remote hanya bergerak maju:
git pushOutput yang Dihasilkan:
To /home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-reject/proyek-utama.git
f33ebb8..c3d1047 main -> mainRentang f33ebb8..c3d1047 mencatat keberhasilannya: seluruh cerita berakhir dengan main di remote memuat kedua pekerjaan. Jalur rebase memberi riwayat linear — commit Budi disusun ulang seolah dibuat setelah commit Siti — dengan langkah yang sama persis: tarik, gabungkan, push; mekanismenya dibahas di Konsep Rebase
.
Peta Penyebab dan Solusi #
Penolakan push bukan satu penyakit tunggal. Tabel ini memetakan yang paling sering dijumpai:
| Penyebab | Ciri pada keluaran | Solusi |
|---|---|---|
| Remote lebih dulu maju | (fetch first) + “remote contains work that you do not have” | fetch → merge/rebase → push (chapter ini) |
| Riwayat lokal ditulis ulang | (non-fast-forward) + “tip of your current branch is behind” | baca chapter Non-Fast-Forward Push |
| Branch lokal tanpa upstream | fatal: The current branch ... has no upstream branch. | pasang tracking seperti di chapter Tracking Branch |
| Branch dilindungi kebijakan | ditolak layanan hosting dengan pesan protected | kirim lewat pull request atau hubungi pemelihara |
Prosedur fetch → gabungkan → push menyelesaikan baris pertama sepenuhnya. Namun baris kedua menyimpan varian yang tidak bisa diselesaikan sekadar menggabungkan: ketika yang ditolak bukan commit baru, melainkan penulisan ulang atas commit lama — wilayah tempat --force dan --force-with-lease berkuasa. Chapter berikutnya memasukinya dengan penuh kewaspadaan.