Comment forcer correctement un push Git?


1274

J'ai installé un dépôt "principal" à distance non dénudé et l'ai cloné sur mon ordinateur. J'ai apporté des modifications locales, mis à jour mon référentiel local et repoussé les modifications dans mon référentiel distant. Les choses allaient bien jusque-là.

Maintenant, je devais changer quelque chose dans le référentiel distant. Ensuite, j'ai changé quelque chose dans mon dépôt local. J'ai réalisé que la modification du référentiel distant n'était pas nécessaire. J'ai donc essayé git pushde passer de mon référentiel local à mon référentiel distant, mais j'ai eu une erreur comme:

Pour vous empêcher de perdre l'historique, les mises à jour non à avance rapide ont été rejetées. Fusionnez les modifications à distance avant de pousser à nouveau. Consultez la section «Remarque sur les avances rapides» git push --helppour plus de détails.

Je pensais que probablement

git push --force

forcerait ma copie locale à pousser les modifications sur la télécommande et à la rendre identique. Cela force la mise à jour , mais lorsque je reviens au référentiel distant et que je fais un commit, je remarque que les fichiers contiennent des modifications obsolètes (celles que le référentiel distant principal avait précédemment).

Comme je l'ai mentionné dans les commentaires à l'une des réponses :

[J'ai] essayé de forcer, mais en revenant au serveur maître pour enregistrer les modifications, j'obtiens une mise en scène obsolète. Ainsi, lorsque je valide les référentiels ne sont pas les mêmes. Et quand j'essaye d'utiliser à nouveau git push, j'obtiens la même erreur.

Comment puis-je résoudre ce problème?


4
Vous pourrez bientôt (git1.8.5, Q4 2013) pouvoir faire git push -forceplus attentivement .
VonC


6
Comme je le détaille dans ma propre réponse , git push --forcec'est en effet un autre moyen valable pour forcer la poussée, et poussera les branches aussi bien git push origin master --forcequ'avec la valeur par défaut de Git push.default config settings, bien que les branches spécifiquement poussées diffèrent entre les versions de Git antérieures à 2.0 et après 2.0.

2
git push --forcefonctionne bien ces jours-ci, FWIW ...
rogerdpack

git push --force-with-leasefonctionne encore mieux :), il refusera de mettre à jour une branche sauf si c'est l'état que vous attendez. (voir developer.atlassian.com/blog/2015/04/force-with-lease )
spoorcc

Réponses:


2309

Faites juste:

git push origin <your_branch_name> --force

ou si vous avez un dépôt spécifique:

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

Cela supprimera vos engagements précédents et poussera votre engagement actuel.

Ce n'est peut-être pas approprié, mais si quelqu'un tombe sur cette page, il pense qu'il pourrait vouloir une solution simple ...

Drapeau court

Notez également que -fc'est court pour --force, donc

git push origin <your_branch_name> -f

fonctionnera également.


58
Vous pouvez utiliser à la git push origin +masterplace, ce qui vous permet de pousser plusieurs refspec sans les forcer toutes.
nickgrim

5
Sachez que, si vous le faites accidentellement git push --force, vous pourriez finir par gâcher votre branche principale (en fonction de votre comportement par défaut). Ce qui pourrait être nul .. un peu ..: D
Jeewes

9
@Jeewes à partir de Git version 2.0, le comportement par défautgit push --force consiste essentiellement à forcer le push de la branche actuellement extraite vers sa partie de compteur distant, donc si vous avez extrait la branche principale, elle est identique à git push origin master --force. Ce sera différent si vous utilisez le matchingparamètre pour push.default, qui est la valeur par défaut pour les versions de Git antérieures à 2.0. matchingpousse toutes les succursales locales vers des succursales distantes qui ont le même nom, donc forcer alors ne pourrait certainement pas être ce que vous voulez faire ...

@Jeewes Mais avec Git 2.0, la valeur par défaut est plus sûre, ou du moins ce n'est pas plus dangereux que ce qui git push origin master --forceest.

2
push -f est bon mais pas recommandé pour le maître car la plupart des référentiels d'entreprise ont -f désactivé pour le maître. le merge -s ourstravail pour moi
mihai

247

Et si push --forcecela ne fonctionne pas, vous pouvez le faire push --delete. Regardez la 2 e ligne sur cette instance:

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

Mais méfiez-vous...

Ne jamais revenir sur une histoire publique de git!

En d'autres termes:

  • N'insérez jamais forceun référentiel public.
  • Ne faites pas cela ou quoi que ce soit qui puisse briser quelqu'un pull.
  • Ne jamais resetou l' rewritehistoire dans un repo que quelqu'un aurait déjà retiré.

Bien sûr, il existe des exceptions exceptionnellement rares, même à cette règle, mais dans la plupart des cas, il n'est pas nécessaire de le faire et cela générera des problèmes pour tout le monde.

Faites un retour à la place.

Et soyez toujours prudent avec ce que vous proposez à un dépôt public . Revenant:

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

En effet, les deux HEAD d'origine (du retour et de la mauvaise réinitialisation ) contiendront les mêmes fichiers.


modifier pour ajouter des informations mises à jour et plus d'arguments autour push --force

Envisagez de pousser la force avec le bail au lieu de pousser, mais préférez toujours revenir

Un autre problème push --forcepeut se produire lorsque quelqu'un pousse quoi que ce soit avant de le faire, mais après que vous l'ayez déjà récupéré. Si vous appuyez sur forcer votre version rebasée maintenant, vous remplacerez le travail des autres .

git push --force-with-leaseintroduit dans le git 1.8.5 ( grâce au commentaire @VonC sur la question) tente de résoudre ce problème spécifique. Fondamentalement, cela apportera une erreur et ne poussera pas si la télécommande a été modifiée depuis votre dernière extraction.

C'est bien si vous êtes vraiment sûr qu'un push --forceest nécessaire, mais que vous voulez toujours éviter plus de problèmes. J'irais jusqu'à dire que ce devrait être le push --forcecomportement par défaut . Mais c'est encore loin d'être une excuse pour forcer a push. Les personnes qui ont récupéré avant votre rebase auront toujours beaucoup de problèmes, qui pourraient être facilement évités si vous aviez rétabli à la place.

Et puisque nous parlons d' git --pushinstances ...

Pourquoi voudrait-on forcer la poussée?

@linquize a apporté un bon exemple de force de poussée sur les commentaires: données sensibles . Vous avez mal divulgué des données qui ne devraient pas être transmises. Si vous êtes assez rapide, vous pouvez le "réparer"* en forçant une poussée sur le dessus.

*Les données seront toujours sur la télécommande, sauf si vous effectuez également un ramasse - miettes ou le nettoyez d'une manière ou d' une autre . Il y a aussi le potentiel évident qu'il soit diffusé par d'autres qui l'ont déjà récupéré , mais vous avez l'idée.


1
Le problème, @rogerdpack, n'est pas s'il est faisable. C'est. Mais cela peut se résumer à une grande catastrophe. Plus quelqu'un le fait (force push) et moins vous mettez à jour (pull) du repo public, plus la catastrophe est grande. Il peut démonter le monde tel que vous le connaissez !!! 111 Au moins le monde comprenant ce référentiel particulier.
cregox

3
Si vous avez des données sensibles, forcez-les à pousser
linquize

3
@Cawas: Je pense qu'il veut dire que si vous essayez de supprimer des données sensibles du référentiel, vous voulez réécrire l'historique. Si vous revenez, les données sensibles sont toujours présentes dans la validation précédente. Cela dit, si quelqu'un d'autre s'est déjà retiré du référentiel, la réécriture de l'historique ne vous aidera pas à l'empêcher d'accéder aux données sensibles - il est déjà trop tard à ce stade.
Stuart Golodetz

3
git push origin master --delete # do a very very bad bad thing git push origin master # regular pushEn fait, cela a parfaitement résolu mon problème (sur un dépôt avec seulement moi et mon ami). c'est peut-être mal pour les dépôts publics, mais pour un dépôt privé, c'est un épargnant de vie.
Can Poyrazoğlu

1
cela se produit automatiquement avec certains gestionnaires de référentiels, alias auto-squash, etc., une poussée forcée après avoir terminé une branche de fonctionnalité pour réduire les commits est courante et attendue.
FlavorScape

18

Tout d'abord, je ne ferais aucun changement directement dans le repo "principal". Si vous voulez vraiment avoir un dépôt "principal", alors vous ne devez que pousser dessus, ne jamais le changer directement.

En ce qui concerne l'erreur que vous obtenez, avez-vous essayé git pulldepuis votre référentiel local, puis git pushvers le référentiel principal? Ce que vous faites actuellement (si j'ai bien compris), c'est de forcer le push puis de perdre vos modifications dans le repo "principal". Vous devez d'abord fusionner les modifications localement.


oui j'ai essayé un pull mais je perds des données en raison de ce pull. Je veux faire mes dépôts principaux comme mon local, sans avoir à mettre à jour à partir du principal.
Spyros

1
Dans ce cas, utilisez git push -f, mais si vous modifiez à nouveau votre référentiel principal, vous devez revenir à votre référentiel local et git pull, afin qu'il se synchronise avec les dernières modifications. Ensuite, vous pouvez faire votre travail et pousser à nouveau. Si vous suivez ce workflow "push-pull", vous n'obtiendrez pas le genre d'erreur dont vous vous plaigniez.
ubik

ouais, je comprends que c'était de ma faute: / Je vais essayer ça et revenir dans un petit moment merci
Spyros

1
essayé de forcer, mais en revenant au serveur maître pour enregistrer les modifications, j'obtiens une mise en scène obsolète. Ainsi, lorsque je valide les référentiels ne sont pas les mêmes. Et quand j'essaye d'utiliser à nouveau git push, j'obtiens la même erreur.
Spyros

17

Si je suis sur ma branche locale A, et que je veux forcer la poussée de la branche locale B vers la branche d'origine, CI peut utiliser la syntaxe suivante:

git push --force origin B:C

2
J'ai découvert que même si je suis sur ma branche locale B, je dois encore le faire git push --force origin B:C. Dans mon cas, il semble que git push --force origin Ccela ne fera que passer du maître local à la branche C distante, quelle que soit la branche sur laquelle je suis actuellement. git version 2.3.8 (Apple Git-58)
Weishi Zeng

12

utilisez cette commande suivante:

git push -f origin master

1
Peut-être donner plus d'explications sur les raisons pour lesquelles cette réponse est préférable aux autres, et ce qui la rend différente.
Adam

oh, désolé pour le dérangement, j'ai eu le même problème et cette commande le résout, j'ai pensé que je devrais le partager.
mustafa Elsayed

12
C'est pareil que les autres, vous venez de changer la position du -fdrapeau ...
svelandiag

11

Je recommanderais vraiment de:

  • pousser uniquement vers le référentiel principal

  • assurez-vous que le référentiel principal est un référentiel nu , afin de ne jamais avoir de problème avec l'arbre de travail du référentiel principal qui n'est pas synchronisé avec sa .gitbase. Voir " Comment envoyer un référentiel git local vers un autre ordinateur? "

  • Si vous devez apporter des modifications dans le référentiel principal (nu), le cloner (sur le serveur principal), effectuez votre modification et repoussez-le

En d'autres termes, gardez un référentiel nu accessible à la fois à partir du serveur principal et de l'ordinateur local, afin d'avoir un seul référentiel en amont depuis / vers lequel tirer / tirer.


5

C'était notre solution pour remplacer master sur un référentiel gitHub d'entreprise tout en conservant l'historique.

push -fla maîtrise des référentiels d'entreprise est souvent désactivée pour conserver l'historique des succursales. Cette solution a fonctionné pour nous.

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

pousser votre branche desiredOriginet créer un PR


3

J'avais la même question mais je l'ai finalement trouvée. Ce que vous devez probablement faire est d'exécuter les deux commandes git suivantes (en remplaçant le hachage par le numéro de révision de la validation git):

git checkout <hash>
git push -f HEAD:master
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.