Git pull après une mise à jour forcée

334

Je viens d'écraser certains commits git rebaseet j'ai fait un git push --force(ce qui est diabolique, je sais).

Maintenant, les autres ingénieurs logiciels ont une histoire différente et quand ils le font git pull, Git fusionnera. Y a-t-il un moyen de résoudre ce problème, sauf en faisant un rm my-repo; git clone [email protected]:my-repo.git?

J'ai besoin de quelque chose comme le contraire de git push --force, mais je git pull --forcen'ai pas donné les résultats escomptés.

iblue
la source
16
ils peuvent supprimer leur branche et la recréer aussi, sans avoir à supprimer l'intégralité du référentiel:git checkout master && git branch -D test && git checkout -b test origin/test
Florian Klein
1
Copie

Réponses:

512

Pour recevoir les nouveaux commits

git fetch

Réinitialiser

Vous pouvez réinitialiser la validation d'une branche locale à l'aide de git reset.

Pour modifier la validation d'une branche locale:

git reset origin/master --hard

Attention cependant, comme le dit la documentation:

Réinitialise l'index et l'arborescence de travail. Toutes les modifications apportées aux fichiers suivis dans l'arborescence de travail depuis <commit> sont ignorées.

Si vous souhaitez conserver les modifications que vous avez localement, effectuez une --softréinitialisation à la place. Ce qui mettra à jour l'historique de validation de la branche, mais ne changera aucun fichier dans le répertoire de travail (et vous pourrez ensuite les valider).

Rebase

Vous pouvez rejouer vos validations locales au-dessus de toute autre validation / branche en utilisant git rebase:

git rebase -i origin/master

Cela invoquera le rebase en mode interactif où vous pourrez choisir comment appliquer chaque commit individuel qui ne fait pas partie de l'historique sur lequel vous rebasez.

Si les validations que vous avez supprimées (avec git push -f) ont déjà été extraites dans l'historique local, elles seront répertoriées en tant que validations qui seront réappliquées - elles devront être supprimées dans le cadre du rebase ou elles seront simplement réintégrées dans l'historique. pour la branche - et réapparaître dans l'historique à distance lors de la prochaine poussée.

Utilisez l'aide git command --helppour plus de détails et d'exemples sur l'une des commandes ci-dessus (ou autres).

AD7six
la source
2
@iblue a le choix entre perdre toutes les modifications, supprimer l'historique des validations mais conserver les modifications du fichier, ou tenter d'appliquer chaque validation au-dessus de la nouvelle tête. L'option la plus simple est probablement une réinitialisation logicielle.
AD7six
1
@iblue Lorsque votre collègue utilise `git reabse origin / master ', et que pendant ce temps, il a déjà eu un commit avant, git écrira votre commit à l'arrière de leur commit.
Tim
6
Pourrait être utile de mentionner que si c'est pour une branche différente:git reset origin/otherbranch --hard
bmaupin
Donc, pour clarifier, ceci est soit : Option 1: reset --hard, ou Option 2: reset --soft+ rebase, non?
PlasmaBinturong
2
@PlasmaBinturong No. git reset --soft origin/mastermodifiera l'historique des validations pour faire correspondre les différences entre la télécommande et la scène à la télécommande qui sera ensuite validée . Il ne serait pas nécessaire de rebaser dans ce scénario (et vous seriez empêché de le faire en raison des modifications non validées) car il n'y a aucune différence dans l'historique des validations. Les deux options sont réinitialisées ou rebasées - pas une combinaison des deux. Veuillez poser une question si votre scénario est différent de celui auquel j'ai répondu ici.
AD7six
16

Cela ne résoudra pas les branches qui contiennent déjà le code que vous ne voulez pas (voir ci-dessous pour savoir comment le faire), mais si elles avaient tiré une branche et veulent maintenant qu'elle soit propre (et non "en avance" de origine / une branche), il vous suffit de:

git checkout some-branch   # where some-branch can be replaced by any other branch
git branch base-branch -D  # where base-branch is the one with the squashed commits
git checkout -b base-branch origin/base-branch  # recreating branch with correct commits

Remarque: vous pouvez les combiner en mettant && entre eux

Note2: Florian l'a mentionné dans un commentaire, mais qui lit les commentaires lors de la recherche de réponses?

Remarque 3: Si vous avez des branches contaminées, vous pouvez en créer de nouvelles à partir de la nouvelle "branche muette" et simplement sélectionner les cerises.

Ex:

git checkout feature-old  # some branch with the extra commits
git log                   # gives commits (write down the id of the ones you want)
git checkout base-branch  # after you have already cleaned your local copy of it as above
git checkout -b feature-new # make a new branch for your feature
git cherry-pick asdfasd   # where asdfasd is one of the commit ids you want
# repeat previous step for each commit id
git branch feature-old -D # delete the old branch

Maintenant, la nouvelle fonctionnalité est votre branche sans les commits supplémentaires (éventuellement mauvais)!

Tom Prats
la source
Voilà ce que je voulais vraiment. Quelqu'un a rebasé la branche principale (car Dieu sait quelle raison) mais je n'ai eu aucun changement local que je voulais commettre ou quoi que ce soit. Donc, tout ce que j'avais à faire était de supprimer ma branche maîtresse locale (ce qui était vraiment bizarre) et de refaire une vérification. Merci!
Danilo Carvalho
@ peter-mortensen Les modifications devraient être substantielles selon stackoverflow.com/help/editing
Tom Prats
pour la dernière étape, vous pouvez également utiliser git checkout -b base-branch origin/base-branchavecgit checkout --track origin/base-branch
bluesmonk
2

Tirez avec rebase

Un pull régulier est fetch + merge, mais ce que vous voulez c'est fetch + rebase. Ceci est une option avec la pullcommande:

git pull --rebase
Herman
la source
J'utilise cela tout le temps pour obtenir le dernier code de master dans ma branche de fonctionnalité sans avoir tous ces commits de fusion dans l'historique.
herman