Get reset --hard dan push ke repositori jarak jauh

200

Saya memiliki repositori yang memiliki beberapa komit buruk di atasnya (D, E dan F untuk contoh ini).

Master ABCDEF dan asal / master

Saya telah memodifikasi repositori lokal secara khusus dengan a git reset --hard. Saya mengambil cabang sebelum reset jadi sekarang saya memiliki repo yang terlihat seperti:

A-B-C master  
     \ D-E-F old_master

A-B-C-D-E-F origin/master

Sekarang saya membutuhkan beberapa bagian dari komit buruk itu jadi saya ceri memilih bit yang saya butuhkan dan membuat beberapa komit baru jadi sekarang saya memiliki yang berikut secara lokal:

A-B-C-G-H master
     \ D-E-F old_master

Sekarang saya ingin mendorong keadaan ini ke repo jarak jauh. Namun, ketika saya mencoba melakukan git pushGit dengan sopan memberi saya sikat:

$ git push origin +master:master --force  
Total 0 (delta 0), reused 0 (delta 0)  
error: denying non-fast forward refs/heads/master (you should pull first)  
To [email protected]:myrepo.git  
! [remote rejected] master -> master (non-fast forward)  
error: failed to push some refs to '[email protected]:myrepo.git'  

Bagaimana cara mendapatkan repo jarak jauh untuk mengambil status repo lokal saat ini?

robertpostill
sumber
2
Merupakan 'hampir' menduplikasi beberapa "bagaimana cara mendorong pertanyaan sejarah diubah", misalnya melihat jawaban di sini stackoverflow.com/questions/253055/...
CB Bailey
2
Itu benar dan saya telah mencari jawaban StackOverflow sebelum memposting. Namun pencarian saya hanya menghasilkan jawaban di mana git push - force memperbaiki masalah. Terima kasih untuk menghubungkan ke posting Anda :)
robertpostill
2
Anda akan segera (git1.8.5, Q4 2013) dapat melakukan git push -forcelebih hati-hati .
VonC

Jawaban:

287

Jika memaksa push tidak membantu ( " git push --force origin'atau' git push --force origin master" harus cukup), mungkin berarti bahwa server remote menolak non dorongan maju cepat baik melalui receive.denyNonFastForwards konfigurasi variabel (lihat git config manualnya untuk deskripsi), atau melalui perbarui / pra-terima kait.

Dengan Git yang lebih tua, Anda dapat mengatasi batasan itu dengan menghapus " git push origin :master" (lihat ':' sebelum nama cabang) dan kemudian membuat kembali git push origin mastercabang yang diberikan " ".

Jika Anda tidak dapat mengubah ini, maka satu-satunya solusi adalah alih-alih menulis ulang riwayat untuk membuat komit mengembalikan perubahan pada DEF :

ABCDEF - [(DEF) ^ - 1] master

Asal / master ABCDEF
Jakub Narębski
sumber
2
@ JakubNarębski, terima kasih. get revert HEAD~Nmembantu. Nadalah jumlah komit. Misalnya, jika saya memerlukan komit sebelumnya, saya akan menggunakangit revert HEAD~1
Maksim Dmitriev
1
Dan ketahuilah bahwa Anda akan mematahkan semua master lokal dengan melakukan hal ini.
Tom Brito
24

Untuk melengkapi jawaban Jakub, jika Anda memiliki akses ke server git jarak jauh di ssh, Anda dapat masuk ke direktori git jarak jauh dan mengatur:

user@remote$ git config receive.denyNonFastforwards false

Kemudian kembali ke repo lokal Anda, coba lagi untuk melakukan komit Anda dengan --force:

user@local$ git push origin +master:master --force

Dan akhirnya mengembalikan pengaturan server dalam keadaan terlindungi asli:

user@remote$ git config receive.denyNonFastforwards true
Jealie
sumber
Lihat juga pete.akeo.ie/2011/02/denying-non-fast-forward-and.html untuk sourceforge informasi khusus tentang ini.
hlovdal
Petunjuk terperinci tentang cara menonaktifkan denyNonFastForwards menggunakan vidisediakan pada posting SO ini: stackoverflow.com/a/43721579/2073804
ron190
2

Alih-alih memperbaiki cabang "master" Anda, lebih mudah menukarnya dengan "master yang Anda inginkan" dengan mengganti nama cabang. Lihat https://stackoverflow.com/a/2862606/2321594 . Dengan cara ini Anda bahkan tidak akan meninggalkan jejak beberapa log pemulihan.

Aidin
sumber
1

Seluruh bisnis pengaturan ulang git tampak menyulitkan saya.

Jadi saya melakukan sesuatu di sepanjang baris untuk mendapatkan folder src saya di negara saya punya beberapa komit yang lalu

# reset the local state
git reset <somecommit> --hard 
# copy the relevant part e.g. src (exclude is only needed if you specify .)
tar cvfz /tmp/current.tgz --exclude .git  src
# get the current state of git
git pull
# remove what you don't like anymore
rm -rf src
# restore from the tar file
tar xvfz /tmp/current.tgz
# commit everything back to git
git commit -a
# now you can properly push
git push

Dengan cara ini keadaan urusan dalam src disimpan dalam file tar dan git dipaksa untuk menerima keadaan ini tanpa terlalu banyak mengutak-atik pada dasarnya direktori src diganti dengan keadaan yang telah dilakukan beberapa kali lalu.

Wolfgang Fahl
sumber
0

Untuk pengguna GitHub, ini bekerja untuk saya:

  1. Dalam aturan perlindungan cabang mana pun yang Anda inginkan untuk melakukan perubahan, pastikan Perbolehkan dorongan paksa diaktifkan
  2. git reset --hard <full_hash_of_commit_to_reset_to>
  3. git push --force

Ini akan "memperbaiki" riwayat cabang pada mesin lokal Anda dan server GitHub, tetapi siapa pun yang telah menyinkronkan cabang ini dengan server karena komit yang buruk akan memiliki riwayat pada mesin lokal mereka. Jika mereka memiliki izin untuk mendorong ke cabang secara langsung maka komit ini akan ditampilkan segera kembali ketika mereka menyinkronkan.

Yang perlu dilakukan semua orang adalah git resetperintah dari atas untuk "memperbaiki" cabang pada mesin lokal mereka. Tentu saja mereka perlu mewaspadai komitmen lokal yang dibuat untuk cabang ini setelah hash target. Cherry mengambil / mencadangkan dan mendaftar kembali yang diperlukan, tetapi jika Anda berada di cabang yang dilindungi maka jumlah orang yang dapat melakukan langsung ke sana kemungkinan terbatas.

Jason Faulkner
sumber