En quelque sorte, mes branches master
et origin/master
ont divergé.
En réalité, je ne veux pas qu'elles divergent.
Comment puis-je voir ces différences et les fusionner?
En quelque sorte, mes branches master
et origin/master
ont divergé.
En réalité, je ne veux pas qu'elles divergent.
Comment puis-je voir ces différences et les fusionner?
Vous pouvez revoir les différences avec :
git log HEAD..origin/main
# anciens dépôts
git log HEAD..origin/master
avant de le récupérer (fetch + merge) (voir aussi "Comment obtenir git pour toujours tirer d'une branche spécifique?")
Note: depuis Git 2.28 (T3 2020), la branche par défaut est configurable, et maintenant (2021+) est définie sur main
, plus sur master
.
Le reste de la réponse reflète cette convention plus récente.
Lorsque vous avez un message comme :
"Votre branche et 'origin/main' ont divergé, # et ont respectivement 1 et 1 commit(s) différent(s)."
Vérifiez si vous avez besoin de mettre à jour origin
.
Si origin
est à jour, alors certains commits ont été poussés vers origin
depuis un autre référentiel pendant que vous faisiez vos propres commits localement.
... o ---- o ---- A ---- B origin/main (travail en amont)
\
C main (votre travail)
Vous avez basé le commit C
sur le commit A
car c'était le dernier travail que vous aviez récupéré de upstream
à ce moment-là.
Cependant, avant d'essayer de repousser vers origin
, quelqu'un d'autre a poussé le commit B
.
L'historique de développement s'est divergé en chemins séparés.
Vous pouvez alors fusionner ou rebaser. Voir Pro Git: Git Branching - Rebasing pour plus de détails.
Utilisez la commande git merge
:
$ git merge origin/main
# anciens dépôts
$ git merge origin/master
Cela dit à Git d'intégrer les changements de origin/main
dans votre travail et de créer un commit de fusion.
Le graphique de l'historique ressemble maintenant à ceci:
... o ---- o ---- A ---- B origin/main (travail en amont)
\ \
C ---- M main (votre travail)
La nouvelle fusion, le commit M
, a deux parents, représentant chacun un chemin de développement ayant conduit au contenu stocké dans ce commit.
À noter que l'historique derrière M
est désormais non linéaire.
Utilisez la commande git rebase
:
$ git rebase origin/main
# anciens dépôts
$ git rebase origin/master
Cela dit à Git de rejouer le commit C
(votre travail) comme si vous l'aviez basé sur le commit B
A.
Les utilisateurs de CVS et Subversion rebasent régulièrement leurs changements locaux sur le travail en amont lorsqu'ils mettent à jour avant de commettre.
Git ajoute simplement une séparation explicite entre les étapes de commit et de rebase.
Le graphique de l'historique ressemble maintenant à ceci:
... o ---- o ---- A ---- B origin/main (travail en amont)
\
C' main (votre travail)
Le commit C'
est un nouveau commit créé par la commande git rebase
.
Il est différent de C
de deux manières :
B
au lieu de A
.B
et de C
; il est identique à M
de l'exemple de fusion.À noter que l'historique derrière C'
est toujours linéaire.
Nous avons choisi (pour l'instant) de n'autoriser qu'un historique linéaire dans cmake.org/cmake.git
.
Cette approche préserve le flux de travail basé sur CVS utilisé précédemment et peut faciliter la transition.
Une tentative de repousser C'
dans notre référentiel fonctionnera (en supposant que vous avez les autorisations et que personne n'a poussé pendant que vous faisiez un rebase).
La commande git pull
fournit un moyen abrégé de fetch
depuis origin
et de rebase
le travail local dessus:
$ git pull --rebase
Cela combine les étapes de fetch
et de rebase
en une seule commande.
J'ai trouvé cela en cherchant le même problème, pouvez-vous expliquer pourquoi 'git reset --hard HEAD' n'a pas corrigé le problème ?
@Neth : car il ne s'agit pas de modifications mises en scène (c'est-à-dire de modifications présentes dans l'index mais non encore validées), mais de commit locaux (ce qui diffère des commits présents sur le distant). git reset --hard HEAD
ne supprimerait que toute modification non validée localement indexée, et ne ferait rien pour concilier les différences entre les commits locaux et distants. Seul une fusion ou un rebasage réconciliera les deux ensembles de commits (local et distant).
Waouh, merci pour cette réponse incroyable. Nous avions accidentellement fait un "git pull" sans "--rebase", et "git rebase origin/master" était juste la solution!
J'ai eu ce problème et je suis perplexe quant à ce qui l'a causé, même après avoir lu les réponses ci-dessus. Ma solution a été de faire
git reset --hard origin/main
Ensuite, cela réinitialise tout simplement ma copie de main (locale) (que je suppose être corrompue) au point correct, tel que représenté par main (distant) origin/main.
ATTENTION : Vous perdrez tous les changements non encore poussés vers
origin/main
.
Oui, cela ressemble un peu à l'option des mannequins, mais s'il n'y a pas de réel danger et que vous êtes ici pour une solution rapide - cela fonctionne (pour moi en tout cas)
Salut skiphoppy, merci pour le conseil. Je suis d'accord avec PandaWood (sans offense) que cela semble être une option un peu simpliste. Mais en disant cela, je ne suis pas très expérimenté avec les aspects plus avancés de Git.
Veuillez mentionner ce que la commande fait, sinon les gens pourraient l'exécuter et finir par la gâcher
Si tout se passe bien, vous devriez vous retrouver avec votre master contenant toutes les modifications origin/master plus tous vos commits locaux seront rejoués par-dessus. Semble bon pour moi.
Je me suis retrouvé dans cette situation lorsque j'ai essayé de rebasé une branche qui suivait une branche distante, et j'essayais de la rebaser sur main. Dans ce scénario, si vous essayez de rebaser, vous finirez probablement par constater que votre branche diverge et cela peut créer un gâchis qui n'est pas fait pour les débutants en git !
Disons que vous êtes sur la branche ma_branche_suivi_distante, qui a été créée à partir de main
$ git status
# Sur la branche ma_branche_suivi_distante
rien à valider (répertoire de travail propre)
Et maintenant vous essayez de rebaser à partir de master comme suit :
git rebase main
ARRÊTEZ MAINTENANT et épargnez-vous des ennuis ! Au lieu de cela, utilisez la fusion comme ceci :
git merge main
Oui, vous vous retrouverez avec des commits supplémentaires sur votre branche. Mais à moins que vous ne souhaitiez "dé-diverger" les branches, ce sera un flux de travail beaucoup plus fluide que le rebasage. Consultez ce blog pour une explication beaucoup plus détaillée.
En revanche, si votre branche est seulement une branche locale (c'est-à-dire pas encore poussée vers un distant), vous devriez certainement faire un rebasage (et votre branche ne divergera pas dans ce cas).
Maintenant, si vous lisez ceci parce que vous êtes déjà dans un scénario "divergé" en raison d'un tel rebasage, vous pouvez revenir au dernier commit provenant de l'origine (c'est-à-dire dans un état non divergé) en utilisant :
git reset --hard origin/ma_branche_suivi_distante
Une règle de base est d'utiliser rebase
si la branche sur laquelle vous réalisez le rebase n'a pas été publiée (et utilisée par d'autres personnes). Sinon, utilisez merge
. Si vous réalisez un rebase sur des branches déjà publiées (et utilisées), vous devez coordonner une conspiration pour réécrire l'historique à travers chaque développeur ayant utilisé votre branche.
Si je fais git rebase master tout en étant sur la branche 'foobar', alors techniquement foobar est divergé de origin/foobar jusqu'à ce que je fasse un git push -f, non ?
Dans mon cas, voici ce que j'ai fait pour provoquer le message diverged : J'ai fait un git push
mais j'ai ensuite utilisé git commit --amend
pour ajouter quelque chose au message de commit. Ensuite, j'ai également effectué un autre commit.
Donc, dans mon cas, cela signifiait simplement que origin/master était obsolète. Comme je savais que personne d'autre ne touchait à origin/master, la correction était triviale : git push -f
(où -f
signifie force)
+1 pour git push -f
pour écraser les modifications précédemment validées et poussées vers l'origine. Je suis également sûr que personne d'autre n'a touché le dépôt.
Commande très risquée. Veuillez écrire une brève information concernant le facteur de risque de la commande.
@Trickster: J'avais déjà décrit le risque : "comme je savais que personne d'autre ne touchait origin/master". Je crois que, dans ce cas, il ne s'agit pas d'une commande risquée.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
4 votes
Que voulez-vous dire par diverger? Rebases-tu ton master après l'avoir poussé?
48 votes
Je reçois un message disant "Votre branche et 'origin/master' ont divergé, et ont respectivement 1 et 1 commit(s) différent(s)".
0 votes
J'ai mis à jour ma réponse pour refléter ce message d'avertissement "diverged".
0 votes
La réponse acceptée à une autre question peut également être utile pour résoudre certains cas où cela pourrait entrer en jeu (par exemple, si vous essayez de déplacer votre master, mais qu'il a déjà été poussé) : stackoverflow.com/questions/2862590/…
0 votes
Le mot que vous cherchez est 'converger' au fait.
7 votes
Pour annuler toutes les modifications apportées à ma propre branche locale après qu'elle ait 'divergé' (nécessité de push et pull, lorsque je n'ai apporté aucun changement dont je me souvienne) :
git reset --hard origin/my-branch
. Ne faites cela que si vous savez que vous n'avez apporté aucune modification locale que vous souhaitez conserver.0 votes
J'ai eu du mal à comprendre cela et j'ai finalement juste exécuté
git branch -D offending_branch && git fetch && git checkout offending_branch
et cela a corrigé le problème.1 votes
@user711807 Version archivée web.archive.org/web/20150213051658/https://serebrov.github.io/…
0 votes
Version non archivée : serebrov.github.io/html/…