150 votes

Pourquoi Git indique-t-il que ma branche master est "déjà à jour" alors qu'elle ne l'est pas ?

Problème de base

Je viens de supprimer TOUT le code d'un fichier de mon projet et de valider la modification dans mon git local (exprès). J'ai fait

git pull upstream master

pour récupérer et fusionner depuis l'amont (donc, en théorie, le code supprimé devrait être de retour).

Git me dit que tout est à jour.

Tout n'est définitivement PAS à jour -- tout ce code supprimé est toujours supprimé.

Autres informations pertinentes

Je n'ai qu'une seule branche appelée "master".

J'ai récemment mis en place "master" pour suivre l'amont comme ceci :

Branch master configuré pour suivre le branch master distant depuis l'amont.

La commande git branch -vv rendements :

* master 7cfcb29 [upstream/master: ahead 9] deletion test

Pourquoi est-ce que ça arrive ? Je suis sur le point d'envoyer par e-mail à mon chef de projet toutes les modifications que je fais à notre code.

Mise à jour

Je pensais que c'était évident, mais bon, c'est mon objectif :

Obtenir le plus récent du code sur mon système.

Excusez ma colère, mais pourquoi une tâche aussi simple que celle-ci doit-elle être si difficile ?

245voto

torek Points 25463

Je pense que votre problème de base ici est que vous interprétez mal 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 ce qui se trouve "là-bas". Il prend également "leurs" étiquettes de branche, telles que master et fait une copie de cette étiquette dont le "nom complet" en votre L'arbre git est (normalement) remotes/origin/master (mais dans votre cas, remotes/upstream/master ). La plupart du temps, vous pouvez omettre l'élément remotes/ également, de sorte que vous pouvez vous référer à cette copie originale en tant que upstream/master .

Si vous effectuez et livrez maintenant une ou plusieurs modifications à un ou plusieurs fichiers, vous êtes le seul à disposer de 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 à disposer de leurs modifications, bien sûr. Cependant, quelqu'un peut éventuellement avoir des modifications qu'il renvoie au propriétaire d'origine (via "push" ou des correctifs ou autre).

El git pull est surtout un raccourci pour git fetch suivi par git merge . C'est important car cela signifie que vous devez comprendre ce que font réellement ces deux opérations.

El git fetch dit de retourner à l'endroit d'où vous avez cloné (ou que vous avez configuré comme lieu de récupération) et de trouver "de nouveaux éléments que quelqu'un d'autre a ajoutés, modifiés ou supprimés". Ces changements sont copiés et appliqués à votre copie de ce que vous avez obtenu d'eux plus tôt . Ils sont no appliqué à votre propre travail, seulement au leur.

El git merge est plus compliquée et c'est là que vous faites fausse route. Ce qu'elle fait, en simplifiant un peu, 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 qui ont donc été ajoutés à votre copie du travail de quelqu'un d'autre". Si vos modifications et celles de quelqu'un d'autre ne semblent pas entrer en conflit, la méthode de la merge L'opération les fusionne et vous donne un "commit de fusion" qui lie votre développement et le leur (bien qu'il existe un cas "facile" très courant dans lequel vous n'avez pas de changements et vous obtenez un "fast forward").

Dans la situation que vous rencontrez actuellement, vous avez apporté des modifications et les avez validées - neuf fois, en fait, d'où le "9 en avant" - et elles ont fait de l'argent. pas de changements. Donc, fetch ne récupère rien, et ensuite merge prend leur manque de changement 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 actuellement remotes/upstream/master . Vous verrez leur code à partir de la dernière fois que vous avez exécuté git fetch et obtenir leur dernier code.

Si vous voulez abandonner toutes vos propres modifications, ce que vous devez faire, c'est changer l'idée que se fait git de la révision à laquelle votre étiquette, master devrait être nommé. Actuellement, il nomme le commit le plus récent. Si vous retournez sur cette branche :

git checkout master

alors le git reset vous permettra de "déplacer l'étiquette", pour ainsi dire. Le seul problème restant (en supposant que vous soyez 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 y a 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 effectuées sont en fait récupérables pendant un certain temps, mais c'est beaucoup plus difficile après cela, alors soyez prudent. très sûr) :

git reset --hard upstream/master

El --hard dit à git d'effacer ce que vous étiez en train de faire, de déplacer l'étiquette de la branche courante, puis de vérifier le commit donné.

Ce n'est pas très courant de vraiment veulent git reset --hard et effacer un tas de travail. Une méthode plus sûre (qui facilite grandement la récupération de ce travail si vous décidez qu'une partie de celui-ci en valait la peine après tout) consiste à renommer votre branche existante :

git branch -m master bunchofhacks

et ensuite créer une nouvelle branche locale nommée master qui "suit" (je n'aime pas vraiment ce terme car je pense qu'il prête à confusion mais c'est le terme git :-) ) le master d'origine (ou amont) :

git branch -t master upstream/master

avec lequel vous pouvez ensuite vous mettre en route :

git checkout master

Les trois dernières commandes (il existe des raccourcis pour n'en faire que deux) permettent de modifier le nom collé sur l'étiquette existante, puis de créer une nouvelle étiquette et de passer à celle-ci :

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"

Ici C0 est le dernier commit (un arbre source complet) que vous avez obtenu lorsque vous avez fait votre première demande d'accès à la base de données. git clone . C1 à C9 sont vos commits.

Notez que si vous deviez git checkout bunchofhacks et ensuite git reset --hard HEAD^^ ce qui changerait la dernière image en :

C0 -    "remotes/upstream/master", "master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 -    "bunchofhacks"
                                                      \
                                                       \- C8 --- C9

La raison en est que HEAD^^ nomme la révision deux plus haut à partir de la tête de la branche courante (qui juste avant la réinitialisation serait bunchofhacks ), et reset --hard puis déplace l'étiquette. Les commits C8 et C9 sont maintenant presque invisibles (vous pouvez utiliser des choses comme les fonctions reflog et git fsck pour les trouver mais ce n'est plus trivial). Vous pouvez déplacer vos étiquettes comme bon vous semble. Le site fetch s'occupe de ceux qui commencent par remotes/ . Il est conventionnel de faire correspondre "le vôtre" avec "le leur" (donc s'ils ont un remotes/origin/mauve vous nommeriez le vôtre mauve aussi), mais vous pouvez taper "les leurs" quand vous voulez nommer/voir les commits que vous avez obtenus "d'eux". (Rappelez-vous qu'"un commit" est un arbre source entier. Vous pouvez choisir un fichier spécifique d'un commit, avec git show par exemple, si et quand vous le souhaitez).

44voto

Jozsef Turi Points 301

J'ai eu le même problème que vous.

Je l'ai fait. git status git fetch git pull mais ma branche était toujours en retard sur l'origine. J'avais des dossiers et des fichiers poussés à distance et je voyais les fichiers sur le web, mais sur mon local ils étaient manquants.

Enfin, ces commandes ont mis à jour tous les fichiers et dossiers de mon local :

git fetch --all
git reset --hard origin/master 

ou si vous voulez une branche

git checkout your_branch_name_here
git reset --hard origin/your_branch_name_here

4voto

Ryan Stewart Points 46960

Tous les changements que vous effectuez, comme la suppression de tous les fichiers de votre projet, seront toujours en place après un pull. Tout ce qu'un pull fait est de fusionner les derniers changements d'un autre endroit dans votre propre branche, et si votre branche a tout supprimé, alors au mieux vous obtiendrez des conflits de fusion lorsque les changements en amont affectent les fichiers que vous avez supprimés. Donc, en résumé, oui, tout est à jour.

Si vous décrivez le résultat que vous souhaitez obtenir au lieu de "tous les fichiers supprimés", quelqu'un pourra peut-être vous suggérer une marche à suivre appropriée.

Mise à jour :

OBTENIR LE CODE LE PLUS RÉCENT SUR MON SYSTÈME

Ce que vous ne semblez pas comprendre, c'est que vous avez déjà le code le plus récent, qui est le vôtre. Si ce que vous voulez vraiment est de voir le plus récent de de quelqu'un d'autre le travail qui est sur la branche principale, il suffit de le faire :

git fetch upstream
git checkout upstream/master

Notez que vous ne serez pas en mesure de (re)commencer immédiatement votre propre travail. Si vous avez besoin de savoir comment défaire quelque chose que vous avez fait ou comment annuler les changements que vous ou quelqu'un d'autre a fait, veuillez fournir des détails. En outre, pensez à lire ce à quoi sert le contrôle de version, puisque vous semblez ne pas comprendre son objectif de base.

4voto

P.Rington Points 1

Bien qu'aucune de ces réponses n'ait fonctionné pour moi, j'ai pu résoudre le problème en utilisant la commande suivante.

git fetch origin

Cela a fait l'affaire pour moi.

3voto

Paul Points 36

Comme le disent les autres posters, pull fusionne les changements de l'amont dans votre dépôt. Si vous voulez remplacer ce qui se trouve dans votre dépôt par ce qui se trouve en amont, vous avez plusieurs options. À titre indicatif, je choisirais les options suivantes

git checkout HEAD^1  # Get off your repo's master.. doesn't matter where you go, so just go back one commit
git branch -d master  # Delete your repo's master branch
git checkout -t upstream/master  # Check out upstream's master into a local tracking branch of the same name

Prograide.com

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.

Powered by:

X