Bagaimana cara saya memaksakan Git dengan benar?

1274

Saya telah menyiapkan repo "main" non-telanjang jarak jauh dan mengkloningnya ke komputer saya. Saya membuat beberapa perubahan lokal, memperbarui repositori lokal saya, dan mendorong perubahan kembali ke repo jarak jauh saya. Semuanya baik-baik saja hingga saat itu.

Sekarang, saya harus mengubah sesuatu di repo jarak jauh. Kemudian saya mengubah sesuatu di repo lokal saya. Saya menyadari bahwa perubahan repo jarak jauh tidak diperlukan. Jadi saya mencoba git pushdari repo lokal saya ke repo jarak jauh saya, tetapi saya mendapat kesalahan seperti:

Untuk mencegah Anda kehilangan riwayat, pembaruan non-maju ditolak. Gabungkan perubahan jarak jauh sebelum mendorong lagi. Lihat bagian 'Catatan tentang maju cepat' git push --helpuntuk detailnya.

Saya pikir mungkin a

git push --force

akan memaksa salinan lokal saya untuk mendorong perubahan ke yang jauh dan membuatnya sama. Memang memaksa pembaruan , tetapi ketika saya kembali ke repo jarak jauh dan membuat komit, saya melihat bahwa file berisi perubahan yang sudah ketinggalan zaman (yang repo jarak jauh utama sebelumnya).

Seperti yang saya sebutkan di komentar untuk salah satu jawaban :

[Saya] mencoba memaksa, tetapi ketika kembali ke server master untuk menyimpan perubahan, saya mendapatkan pementasan yang ketinggalan zaman. Jadi, ketika saya melakukan repositori tidak sama. Dan ketika saya mencoba menggunakan git push lagi, saya mendapatkan kesalahan yang sama.

Bagaimana saya bisa memperbaiki masalah ini?

Spyros
sumber
4
Anda akan segera (git1.8.5, Q4 2013) dapat melakukan git push -forcelebih hati-hati .
VonC
6
Seperti yang saya jelaskan dalam jawaban saya sendiri , git push --forcememang merupakan cara lain yang valid untuk memaksa push, dan akan mendorong cabang sama seperti halnya git push origin master --forcedengan standar Git push.default config settings, meskipun cabang mana yang secara khusus terdorong berbeda antara versi Git sebelum 2.0 versus setelah 2.0.
2
git push --forcehari ini berfungsi dengan baik, FWIW ...
rogerdpack
git push --force-with-leasebekerja lebih baik :), ia akan menolak untuk memperbarui cabang kecuali jika itu adalah keadaan yang Anda harapkan. (lihat developer.atlassian.com/blog/2015/04/force-with-lease )
spoorcc

Jawaban:

2309

Kerjakan saja:

git push origin <your_branch_name> --force

atau jika Anda memiliki repo tertentu:

git push https://git.... --force

Ini akan menghapus komit Anda sebelumnya dan mendorong komit Anda saat ini.

Ini mungkin tidak tepat, tetapi jika ada yang menemukan halaman ini, mengira mereka mungkin menginginkan solusi sederhana ...

Bendera pendek

Perhatikan juga bahwa -fitu kependekan dari --force, jadi

git push origin <your_branch_name> -f

juga akan bekerja.

Katie
sumber
58
Anda dapat menggunakannya git push origin +mastersebagai gantinya, yang memungkinkan Anda mendorong beberapa refspec tanpa memaksa semuanya.
jamaah
5
Ketahuilah bahwa, jika Anda secara tidak sengaja melakukan hal yang benar git push --force, Anda mungkin akan mengacaukan cabang master Anda (tergantung pada perilaku default push Anda) .. Yang mungkin payah .. sedikit ..: D
Jeewes
9
@Jeewes dimulai dengan Git versi 2.0, perilaku defaultgit push --force pada dasarnya adalah untuk memaksa mendorong cabang yang saat ini check-out ke bagian remote-counter, jadi jika Anda memiliki cabang master diperiksa, maka itu identik dengan git push origin master --force. Ini akan berbeda jika Anda menggunakan matchingpengaturan untuk push.default, yang merupakan default untuk versi Git sebelum 2.0. matchingmendorong semua cabang lokal ke yang jauh yang memiliki nama yang sama, jadi memaksa mendorong maka pasti bukan yang ingin Anda lakukan ...
@Jeewes Tapi dengan Git 2.0, standarnya lebih aman, atau setidaknya tidak lebih berbahaya dari git push origin master --forceitu.
2
push -f baik tetapi tidak direkomendasikan untuk master karena sebagian besar repositori perusahaan telah -f dinonaktifkan untuk master. yang merge -s oursbekerja untuk saya
mihai
247

Dan jika push --forcetidak berhasil, Anda bisa melakukannya push --delete. Lihat 2 nd garis pada contoh ini:

git reset --hard HEAD~3  # reset current branch to 3 commits ago
git push origin master --delete  # do a very very bad bad thing
git push origin master  # regular push

Tapi waspadalah ...

Jangan pernah kembali pada sejarah git publik!

Dengan kata lain:

  • Jangan pernah forcemendorong repositori publik.
  • Jangan lakukan ini atau apa pun yang dapat merusak seseorang pull.
  • Jangan pernah resetatau rewriteriwayat dalam repo seseorang mungkin sudah menarik.

Tentu saja ada pengecualian yang sangat jarang bahkan untuk aturan ini, tetapi dalam kebanyakan kasus itu tidak diperlukan untuk melakukannya dan itu akan menimbulkan masalah bagi semua orang.

Kembalikan sebagai gantinya.

Dan selalu berhati-hati dengan apa yang Anda dorong ke repo publik . Mengembalikan:

git revert -n HEAD~3..HEAD  # prepare a new commit reverting last 3 commits
git commit -m "sorry - revert last 3 commits because I was not careful"
git push origin master  # regular push

Akibatnya, kedua kepala asal (dari revert dan dari ulang jahat ) akan berisi file yang sama.


sunting untuk menambahkan info terbaru dan lebih banyak argumen di sekitar push --force

Pertimbangkan untuk mendorong kekuatan dengan sewa alih-alih mendorong, tetapi masih lebih suka kembali

Masalah lain yang push --forcemungkin timbul adalah ketika seseorang mendorong sesuatu sebelum Anda melakukannya, tetapi setelah Anda mengambilnya. Jika Anda mendorong paksa versi rebased Anda sekarang Anda akan mengganti pekerjaan dari yang lain .

git push --force-with-leasediperkenalkan pada git 1.8.5 ( terima kasih kepada komentar @VonC pada pertanyaan) mencoba untuk mengatasi masalah khusus ini. Pada dasarnya, itu akan membawa kesalahan dan tidak mendorong jika remote telah dimodifikasi sejak pengambilan terbaru Anda.

Ini bagus jika Anda benar-benar yakin push --forcediperlukan, tetapi masih ingin mencegah lebih banyak masalah. Saya akan mengatakan bahwa itu seharusnya merupakan push --forceperilaku default . Tapi itu masih jauh dari alasan untuk memaksakan push. Orang-orang yang mengambil sebelum rebase Anda masih akan memiliki banyak masalah, yang bisa dengan mudah dihindari jika Anda telah dikembalikan sebagai gantinya.

Dan karena kita sedang berbicara tentang git --pushcontoh ...

Mengapa ada orang yang ingin memaksakan dorongan?

@linquize membawa contoh gaya dorong yang baik pada komentar: data sensitif . Anda salah membocorkan data yang seharusnya tidak didorong. Jika Anda cukup cepat, Anda dapat "memperbaikinya"* dengan memaksakan dorongan di atasnya.

*The Data masih akan di remote kecuali jika Anda juga melakukan sampah mengumpulkan , atau membersihkannya entah bagaimana . Ada juga potensi yang jelas untuk disebarkan oleh orang lain yang sudah mengambilnya , tetapi Anda mendapatkan idenya.

cregox
sumber
1
Masalahnya, @rogerdpack, tidak bisa dilakukan. Ini. Tapi itu bisa menjadi bencana besar. Semakin banyak seseorang melakukannya (memaksa) dan semakin jarang Anda memperbarui (menarik) dari repo publik, semakin besar bencana. Itu bisa membongkar dunia seperti yang kamu tahu !!! 111 Setidaknya dunia terdiri dari repositori tertentu.
cregox
3
Jika Anda memiliki data sensitif, paksa dorong
linquize
3
@ Cawas: Saya pikir maksudnya jika Anda mencoba untuk menghapus data sensitif dari repositori, maka Anda ingin menulis ulang sejarah. Jika Anda mengembalikan, data sensitif masih ada di komit sebelumnya. Yang mengatakan, jika orang lain sudah menarik dari repositori, maka penulisan ulang riwayat tidak akan membantu Anda mencegah mereka mengakses data sensitif - sudah terlambat pada saat itu.
Stuart Golodetz
3
git push origin master --delete # do a very very bad bad thing git push origin master # regular pushini benar-benar menyelesaikan masalah saya dengan sempurna (pada repo hanya dengan saya dan teman saya). mungkin itu salah untuk repo publik tetapi untuk yang pribadi ini adalah penyelamat.
Can Poyrazoğlu
1
ini terjadi secara otomatis dengan beberapa manajer repo, alias auto-squash, dll. Kekuatan mendorong setelah menyelesaikan cabang fitur untuk mengurangi commit adalah hal biasa dan diharapkan.
FlavourScape
18

Pertama-tama, saya tidak akan membuat perubahan secara langsung dalam repo "utama". Jika Anda benar-benar ingin memiliki repo "utama", maka Anda hanya perlu mendorongnya, jangan pernah mengubahnya secara langsung.

Mengenai kesalahan yang Anda dapatkan, sudahkah Anda mencoba git pulldari repo lokal Anda, dan kemudian git pushke repo utama? Apa yang Anda lakukan saat ini (jika saya memahaminya dengan baik) adalah memaksa dan kemudian kehilangan perubahan Anda dalam repo "utama". Anda harus menggabungkan perubahan secara lokal terlebih dahulu.

ubik
sumber
ya saya mencoba tarikan tetapi saya kehilangan data karena tarikan itu. Saya ingin membuat repo utama saya seperti lokal saya, tanpa terlebih dahulu memperbarui dari utama.
Spyros
1
Dalam hal ini digunakan git push -f, tetapi kemudian jika Anda mengubah repo utama Anda lagi, Anda harus kembali ke repo lokal Anda dan git pull, sehingga bisa disinkronkan dengan perubahan terbaru. Kemudian Anda bisa melakukan pekerjaan Anda, dan mendorong lagi. Jika Anda mengikuti alur kerja "tarik-tarik" ini, Anda tidak akan mendapatkan jenis kesalahan yang Anda keluhkan.
ubik
ya, saya mengerti bahwa ini adalah kesalahan saya: / Saya akan mencobanya dan kembali lagi sebentar lagi
Spyros
1
mencoba memaksa, tetapi ketika kembali ke server master untuk menyimpan perubahan, saya mendapatkan pementasan yang ketinggalan zaman. Jadi, ketika saya melakukan repositori tidak sama. Dan ketika saya mencoba menggunakan git push lagi, saya mendapatkan kesalahan yang sama.
Spyros
17

Jika saya di cabang lokal saya A, dan saya ingin memaksa mendorong cabang lokal B ke cabang asal CI dapat menggunakan sintaks berikut:

git push --force origin B:C
IcedDante
sumber
2
Saya mengetahui bahwa meskipun saya menggunakan cabang lokal B, saya masih perlu melakukannya git push --force origin B:C. Dalam kasus saya, tampaknya git push --force origin Chanya akan mendorong dari master lokal ke cabang C jarak jauh, terlepas dari cabang mana saya saat ini. git version 2.3.8 (Apple Git-58)
Weishi Zeng
12

gunakan perintah berikut ini:

git push -f origin master
mustafa Elsayed
sumber
1
Mungkin berikan penjelasan lebih lanjut tentang mengapa jawaban ini lebih disukai daripada yang lain, dan apa yang membuatnya berbeda.
Adam
oh, maaf atas ketidaknyamanan ini, saya mengalami masalah yang sama dan perintah ini menyelesaikannya, saya pikir saya harus membagikannya.
mustafa Elsayed
12
Sama seperti yang lain, Anda baru saja mengubah posisi -fbendera ...
svelandiag
11

Saya sangat merekomendasikan:

  • dorong hanya ke repo utama

  • pastikan repo utama adalah repo kosong , agar tidak pernah ada masalah dengan pohon repo utama yang bekerja tidak sinkron dengan .gitbasisnya. Lihat " Bagaimana cara mendorong repositori git lokal ke komputer lain? "

  • Jika Anda harus melakukan modifikasi pada repo utama (telanjang), tiru (di server utama), lakukan modifikasi Anda dan tekan kembali ke sana

Dengan kata lain, biarkan repo telanjang dapat diakses baik dari server utama dan komputer lokal, agar memiliki repo hulu tunggal dari / yang dapat digunakan untuk menarik / menarik.

VONC
sumber
5

Ini adalah solusi kami untuk mengganti master pada repositori gitHub korporat sambil mempertahankan sejarah.

push -funtuk menguasai repositori perusahaan sering dinonaktifkan untuk mempertahankan sejarah cabang. Solusi ini berhasil bagi kami.

git fetch desiredOrigin
git checkout -b master desiredOrigin/master // get origin master

git checkout currentBranch  // move to target branch
git merge -s ours master  // merge using ours over master
// vim will open for the commit message
git checkout master  // move to master
git merge currentBranch  // merge resolved changes into master

dorong cabang Anda ke desiredOrigindan buat PR

mihai
sumber
3

Saya memiliki pertanyaan yang sama tetapi akhirnya menemukan jawabannya. Apa yang kemungkinan besar perlu Anda lakukan adalah menjalankan dua perintah git berikut (mengganti hash dengan nomor revisi komit git):

git checkout <hash>
git push -f HEAD:master
Brian M.
sumber