web-dev-qa-db-fra.com

Comment forcer correctement un push Git?

J'ai mis en place un référentiel "principal" distant non nu et je l'ai cloné sur mon ordinateur. J'ai apporté des modifications locales, mis à jour mon référentiel local et transféré les modifications vers mon référentiel distant. Les choses allaient bien jusque-là.

Maintenant, je devais changer quelque chose dans le repo distant. Ensuite, j'ai changé quelque chose dans mon dépôt local. J'ai réalisé que le changement de repo distant n'était pas nécessaire. J'ai donc essayé de git Push de mon dépôt local vers mon dépôt distant, mais j'ai eu une erreur du type:

Pour vous éviter de perdre votre historique, les mises à jour non avancées ont été rejetées. Fusionnez les modifications distantes avant de réappuyer. Reportez-vous à la section "Remarque concernant les transferts rapides" de git Push --help pour plus de détails.

Je pensais que probablement un

git Push --force

forcerait ma copie locale à transmettre les modifications à la version distante et à la rendre identique. Cela force la mise à jour , mais quand je retourne au dépôt distant et fais un commit, je remarque que les fichiers contiennent des modifications obsolètes (celles que le repo principal à distance précédemment).

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

[J'ai] essayé de forcer, mais lorsque je retourne sur le serveur maître pour enregistrer les modifications, je reçois une mise à jour obsolète. Ainsi, lorsque je commets les référentiels ne sont pas les mêmes. Et quand j'essaie d'utiliser git Push à nouveau, j'obtiens la même erreur.

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

1172
Spyros

Il suffit de faire:

git Push Origin <your_branch_name> --force

ou si vous avez un repo spécifique:

git Push https://git.... --force

Ceci supprimera votre ou vos précédentes validations et poussera votre actuel.

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

Drapeau court

Notez également que -f est un raccourci pour --force, donc

git Push Origin <your_branch_name> -f

travaillera également.

2137
Katie

Et si _Push --force_ ne fonctionne pas, vous pouvez faire Push --delete. Regarde 2dakota du Nord 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 d'idiots publics!

En d'autres termes:

  • Ne jamais force Poussez sur un référentiel public.
  • Ne faites pas ceci ou quoi que ce soit qui peut casser quelqu'un pull.
  • Ne jamais utiliser l'historique reset ou rewrite dans un repo quelqu'un aurait déjà extrait.

Bien entendu, il existe exceptionnellement de rares exceptions à cette règle, mais dans la plupart des cas, cela n’est pas nécessaire et cela engendrera des problèmes pour tout le monde.

Faites un retour à la place.

Et faites toujours attention à ce que vous poussez vers 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 HEADs d’origine (à partir du reviennent à et à partir du Réinitialisation maléfique ) contiendra les mêmes fichiers.


edit pour ajouter des informations mises à jour et d'autres arguments autour de _Push --force_

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

Un autre problème que _Push --force_ peut apporter est celui qui survient lorsque quelqu'un pousse quoi que ce soit avant, mais après l'avoir récupéré. Si vous poussez de force votre rebased version, vous allez maintenant remplacer le travail des autres .

_git Push --force-with-lease_ introduit dans le git 1.8.5 ( merci à @VonC commenter la question) tente de résoudre ce problème spécifique. Fondamentalement, cela entraînera une erreur et non Push 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 --force_ est nécessaire, mais que vous souhaitez tout de même éviter d’autres problèmes. J'irais même jusqu'à dire que cela devrait être le comportement par défaut _Push --force_. Mais c’est encore loin d’être une excuse pour forcer une Push. Les personnes qui ont récupéré avant votre rebase auront encore beaucoup de problèmes, ce qui pourrait être facilement évité si rétabli à la place.

Et puisque nous parlons de _git --Push_ instances ...

Pourquoi quelqu'un voudrait-il forcer?

@ linquize a apporté un bon exemple de force Push sur les commentaires: données sensibles . Vous avez indûment divulgué des données qu'il ne fallait pas pousser. Si vous êtes assez rapide, vous pouvez "réparer" _*_ en forçant un Push au sommet.

_*_ Le les données seront toujours sur la télécommande sauf si vous effectuez également un ramasse-miettes , ou nettoyez-le en quelque sorte . Il est également évident que d'autres qui l'auraient fetched == (= # = =) == == le = ont déjà, mais vous voyez l'idée.

233
cregox

Tout d’abord, je n’apporterais aucun changement directement dans le dépôt "principal". Si vous voulez vraiment avoir un "principal" repo, alors vous ne devriez que Push, ne le changez pas directement.

En ce qui concerne l’erreur que vous obtenez, avez-vous essayé git pull à partir de votre dépôt local, puis git Push au dépôt principal? Si vous avez bien compris, ce que vous faites actuellement est de forcer le Push, puis de perdre vos modifications dans le référentiel "principal". Vous devez d'abord fusionner les modifications localement.

18
ubik

Si je suis sur ma branche locale A et que je veux forcer le transfert de la branche locale B vers la branche d'origine C, je peux utiliser la syntaxe suivante:

git Push --force Origin B:C
15
IcedDante

Je recommanderais vraiment de:

  • Poussez uniquement vers le dépôt principal

  • assurez-vous que le référentiel principal est un bare repo , 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 base .git. Voir " Comment transférer un référentiel git local sur un autre ordinateur? "

  • Si vous devez apporter des modifications au référentiel principal (nu), clonez-le (sur le serveur principal), effectuez la modification et repoussez-le.

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

11
VonC

utilisez cette commande suivante:

git Push -f Origin master
8
mustafa Elsayed

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

Push -f à maîtriser sur les référentiels d'entreprise est souvent désactivé pour conserver l'historique de la branche. 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

Poussez votre branche sur desiredOrigin et créez un PR

5
mihai

J'avais la même question mais j'ai finalement compris. Ce que vous devez probablement faire est d’exécuter les deux commandes git suivantes (en remplaçant hash par le numéro de révision git commit):

git checkout <hash>
git Push -f HEAD:master
1
Brian