Je pense que votre problème fondamental ici est que vous interprétez et / ou comprenez mal ce que fait git et pourquoi il le fait.
Lorsque vous clonez un autre dépôt, git fait une copie de tout ce qui est "là-bas". Il prend également "leurs" étiquettes de branche, telles que master
, et fait une copie de cette étiquette dont le "nom complet" dans votre arbre git est (normalement) remotes/origin/master
(mais dans votre cas, remotes/upstream/master
). La plupart du temps, vous pouvez également omettre la remotes/
partie, de sorte que vous pouvez vous référer à cette copie originale comme upstream/master
.
Si vous apportez et validez maintenant des modifications à certains fichiers, vous êtes le seul à avoir ces modifications. Pendant ce temps, d'autres personnes peuvent utiliser le référentiel d'origine (à partir duquel vous avez créé votre clone) pour créer d'autres clones et modifier ces clones. Ils sont les seuls avec leurs changements, bien sûr. Finalement, cependant, quelqu'un peut avoir des changements à renvoyer au propriétaire d'origine (via "push" ou des correctifs ou autre).
La git pull
commande est principalement un raccourci pour git fetch
suivi de git merge
. Ceci est important car cela signifie que vous devez comprendre ce que font réellement ces deux opérations.
La git fetch
commande dit de retourner à l'endroit où vous avez cloné (ou que vous avez configuré comme un endroit à récupérer) et de trouver "de nouvelles choses que quelqu'un d'autre a ajoutées, modifiées ou supprimées". Ces modifications sont copiées et appliquées à votre copie de ce que vous en avez obtenu précédemment . Ils ne s'appliquent pas à votre propre travail, uniquement au leur.
La git merge
commande est plus compliquée et c'est là que vous vous trompez. Ce qu'il fait, un peu simplifié à l'extrême, c'est comparer "ce que vous avez changé dans votre copie" aux "changements que vous avez récupérés de quelqu'un d'autre et ainsi ajoutés à votre-copie-du-travail-de-quelqu'un-d'autre". Si vos modifications et leurs modifications ne semblent pas entrer en conflit, l' merge
opération les rassemble et vous donne un «commit de fusion» qui lie votre développement et leur développement ensemble (bien qu'il existe un cas très courant «facile» dans lequel vous n'avez pas change et vous obtenez une "avance rapide").
La situation que vous rencontrez actuellement est celle dans laquelle vous avez apporté des changements et les avez validés - neuf fois, en fait, d'où le «9 à venir» - et ils n'ont fait aucun changement. Donc, fetch
consciencieusement ne récupère rien, puis merge
prend leur absence de changements et ne fait rien non plus.
Ce que vous voulez, c'est regarder, ou peut-être même "réinitialiser", "leur" version du code.
Si vous voulez simplement le regarder, vous pouvez simplement consulter cette version:
git checkout upstream/master
Cela indique à git que vous voulez déplacer le répertoire courant vers la branche dont le nom complet est en fait remotes/upstream/master
. Vous verrez leur code à partir de la dernière fois que vous avez exécuté git fetch
et obtenu leur dernier code.
Si vous voulez abandonner toutes vos propres modifications, ce que vous devez faire est de changer l'idée de git de la révision que votre étiquette master
devrait nommer. Actuellement, il nomme votre dernier commit. Si vous revenez sur cette branche:
git checkout master
alors la git reset
commande vous permettra de "déplacer l'étiquette", pour ainsi dire. Le seul problème restant (en supposant que vous êtes vraiment prêt à abandonner tout ce que vous avez fait) est de trouver où l'étiquette doit pointer.
git log
vous permettra de trouver les noms numériques - ces choses comme 7cfcb29
- qui sont des noms permanents (qui ne changent jamais), et il existe un nombre ridicule d'autres façons de les nommer, mais dans ce cas, vous voulez juste le nom upstream/master
.
Pour déplacer l'étiquette, effacer vos propres modifications (celles que vous avez validées sont en fait récupérables pendant un certain temps, mais c'est beaucoup plus difficile après cela, alors soyez très sûr):
git reset --hard upstream/master
Le --hard
dit à git d'effacer ce que vous avez fait, de déplacer l'étiquette de branche actuelle, puis de vérifier le commit donné.
Il n'est pas très courant de vouloir vraimentgit reset --hard
et d'effacer un tas de travail. Une méthode plus sûre (rendant beaucoup plus facile la récupération de ce travail si vous décidez qu'une partie en valait la peine après tout) est de renommer votre branche existante:
git branch -m master bunchofhacks
et ensuite créer une nouvelle branche locale nommée master
"pistes" (je n'aime pas vraiment ce terme car je pense qu'il déroute les gens mais c'est le terme git :-)) le master d'origine (ou amont):
git branch -t master upstream/master
que vous pouvez ensuite utiliser:
git checkout master
Ce que font les trois dernières commandes (il y a des raccourcis pour n'en faire que deux commandes) est de changer le nom collé sur l'étiquette existante, puis de créer une nouvelle étiquette, puis de basculer dessus:
avant de faire quoi que ce soit:
C0 - "remotes/upstream/master"
\
\- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9 "master"
après git branch -m
:
C0 - "remotes/upstream/master"
\
\- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9 "bunchofhacks"
après git branch -t master upstream/master
:
C0 - "remotes/upstream/master", "master"
\
\- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9 "bunchofhacks"
Voici C0
le dernier commit (une arborescence des sources complète) que vous avez obtenu lorsque vous avez fait votre git clone
. C1 à C9 sont vos commits.
Notez que si vous étiez à git checkout bunchofhacks
et puis git reset --hard HEAD^^
, cela changerait la dernière image en:
C0 - "remotes/upstream/master", "master"
\
\- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 - "bunchofhacks"
\
\- C8 --- C9
La raison est que HEAD^^
nomme la révision deux à partir de la tête de la branche actuelle (ce qui serait juste avant la réinitialisation bunchofhacks
), reset --hard
puis déplace l'étiquette. Les commits C8 et C9 sont maintenant pour la plupart invisibles (vous pouvez utiliser des choses comme le reflog et git fsck
les trouver mais ce n'est plus trivial). Vos étiquettes sont à vous pour bouger comme vous le souhaitez. La fetch
commande prend en charge ceux qui commencent par remotes/
. Il est conventionnel de faire correspondre "le vôtre" avec "le leur" (donc s'ils en ont un, remotes/origin/mauve
vous nommez le vôtre mauve
aussi), mais vous pouvez taper "le leur" chaque fois que vous voulez nommer / voir les commits que vous avez obtenus "d'eux". (N'oubliez pas que "un commit" est une arborescence source entière. Vous pouvez choisir un fichier spécifique à partir d'un commit, avec git show
par exemple,