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:

bash
git push

Output yang Dihasilkan (di clone siti):

text
To /home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-reject/proyek-utama.git
   bf0d4bd..f33ebb8  main -> main

Remote maju satu commit. Budi, yang tidak menarik apa pun, sedang menyempurnakan halaman diskon: diskon.md dibuat, commit dijalankan, lalu giliran push-nya tiba:

bash
git push

Output yang Dihasilkan:

text
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:

bash
git fetch origin

Output yang Dihasilkan:

text
From /home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-reject/proyek-utama
   bf0d4bd..f33ebb8  main       -> origin/main
bash
git status

Output yang Dihasilkan:

text
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 clean

Kata 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:

bash
git log --oneline main..origin/main

Output yang Dihasilkan:

text
f33ebb8 Tambah halaman kontak

Satu 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:

bash
git merge origin/main

Output yang Dihasilkan:

text
Merge made by the 'ort' strategy.
 kontak.md | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 kontak.md

Git 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:

bash
git log --oneline --graph -5

Output yang Dihasilkan:

text
*   c3d1047 Merge remote-tracking branch 'origin/main'
|\  
| * f33ebb8 Tambah halaman kontak
* | c1f6fec Tambah halaman diskon
|/  
* bf0d4bd Buat README toko

Empat 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:

bash
git push

Output yang Dihasilkan:

text
To /home/z/my-project/tutorial-extracted/work/sandbox/remote-repository/part-b/latihan-reject/proyek-utama.git
   f33ebb8..c3d1047  main -> main

Rentang 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:

PenyebabCiri pada keluaranSolusi
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 upstreamfatal: The current branch ... has no upstream branch.pasang tracking seperti di chapter Tracking Branch
Branch dilindungi kebijakanditolak layanan hosting dengan pesan protectedkirim 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.