IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

  1. #1
    Membre à l'essai
    Homme Profil pro
    Analyste d'exploitation
    Inscrit en
    Novembre 2022
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Analyste d'exploitation

    Informations forums :
    Inscription : Novembre 2022
    Messages : 26
    Points : 18
    Points
    18
    Par défaut je suis perdu dans mes commandes : j'ai voulu récupérer les modif d'une autre branche en étant placé ailleurs
    Bonjour,
    J'ai ci-dessous l'extrait de mon git log --oneline. Je ne comprends par la première ligne (mon dernier commit, avec le HEAD - >develop etc.)

    En gros, pour décrire ma situation :

    • j'ai une branche main ;
    • puis à partir de main, j'ai créé une branche develop ;
    • puis à partir de develop, je crée d'autres branches de travail (cleanup, clear_input, clean_folder, bonus…) que je supprime une fois que je les merge vers develop ;
    • puis ensuite je merge de develop vers main.


    …sur les branches main et develop, je ne fais rien, pas de commit, pas de push, je fais tout sur une nouvelle branche que je merge vers develop puis vers main.

    J'ai tout bien maitrisé jusqu'à la création de la branche bonus, que j'ai mergé via une PR#24 vers develop, puis j'ai mergé vers main via une autre PR#25.
    puis j'ai supprimé la branche bonus en local et sur le remote.

    En local, j'ai récupéré sur les branches main et develop ce qu'il y avait sur le remote (avec git pull), puis j'ai laissé passer quelques jours.

    Puis je suis revenu sur mon code, et j'ai oublié que j'étais sur main.
    j'ai fait les modif, j'ai commité et pushé vers la branche main en remote.

    Et c'est là où je suis perdu.
    Comme indiqué au début, je crée mes branches à partir de develop car, ensuite, je merge vers develop et ensuite je merge vers main.

    Mais maintenant, la branche develop n'a pas les dernieres modif de main vu que j'ai pushé vers vers main directement.

    Je ne peux pas faire une branche à partir de develop pour ensuite merger vers develop et merger vers main…, vu que je n'aurai pas les dernières modifs qui étaient sur main.

    J'ai alors tenté au hasard cette commande :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    git fetch origin main:develop
    Je pensais récupérer ce qu'il y a sur le main et le ramener vers develop.

    Je l'ai tenté plusieurs fois car je ne sais pas sur quelle branche j'étais quand j'ai essayé cette commande la première fois.
    Puis j'ai essayé en me plaçant sur une autre branche.

    Puis au final, j'ai vu sur la branche develop, en local que j'ai récupéré le travail de main.
    On dirait que ca a marché mais quand je vais sur github et que je regarde develop en remote, je ne vois pas le dernier travail.

    Quand je fais git status, Git me dit que je suis à jour : je pense qu'il compare avec mon dépôt local.
    J'ai alors fait un push et maintenant je vois bien sur le remote sur la branche develop les derniers travaux.

    Mais je ne comprends ce que veut dire le (HEAD -> develop, origin/main, origin/develop, main)....
    Peut-on m'aider à déchiffrer?

    Et quand j'ai fait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    git fetch origin main:develop
    j'ai fait quoi exactement avec cette commande?

    Nom : Screenshot-2.png
Affichages : 423
Taille : 53,3 Ko

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 415
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 415
    Points : 23 879
    Points
    23 879
    Par défaut
    Bonsoir,

    En effet, pas mal de confusion dans tout cela. Avant d'entrer dans les détails, peux-tu nous indiquer ce que utilises au quotidien pour parcourir ton historique ? En particulier, utilises-tu git log --graph, par exemple, ou mieux encore tig, gitk ou l'explorateur de VSCode ? Parce que si tu t'en tiens à un simple git log linéaire (fût-ce avec --oneline), il est beaucoup plus difficile de se représenter mentalement la structure de la hiérarchie du dépôt.

    Bon, tu utilises quand même Github ou Gitlab, donc je suppose que tu profites des facilités mises en place de leur côté.

    Citation Envoyé par gitnoob Voir le message
    J'ai ci-dessous l'extrait de mon git log --oneline. Je ne comprends par la première ligne (mon dernier commit, avec le HEAD - >develop etc.)
    Il s'agit d'une ligne ordinaire sur laquelle tu vois le hash de la révision concernée suivi du sujet du message du commit (« la première ligne », ou celle que tu précises avec git commit -m).

    Tout ce qui est ajouté entre parenthèses concernent toutes les références qui pointent la révision (donc le commit) concerné. On voit donc que HEAD pointe le dernier commit en date, ce qui est normal, on voit que la branche main pointe au même endroit, ce qui est normal également puisque tu travailles dessus ou que tu as fait une fusion. Ce sont les branches en vert.

    On remarque également que les branches distantes, suivant le dernier état connu du serveur, pointent également au même endroit, ce qui est normal là encore puisqu'elles sont censées suivre l'état de leurs homologues locales et que tu as fait un push. origin/main pointe donc au même endroit que main, origin/develop au même endroit que develop et comme ces deux branches ont été fusionnées, tout ce beau monde se retrouve donc au même endroit.

    On voit également que tes anciennes branches pointent toujours au dernier endroit où elles étaient avant d'être fusionnées. Normal encore une fois : la fusion a bien eu lieu mais après cela, seules les branches sur lesquelles tu as travaillé ont évolué. Autre point important : il s'agit des branches distantes « origin/… ». C'est dû au fait que tu as supprimé après fusion ces branches en local, mais que leur homologues existent toujours sur le serveur. On verra un peu plus tard comment faire le ménage de ce côté-là aussi.

    Enfin, la flèche « -> » signifie qu'il s'agit d'une symref. On a expliqué la dernière fois que la structure du graphe était auto-formée par les références successives des commits à leurs parents et qu'en conséquence, un nom de branche n'est qu'une étiquette qui contient la somme SHA1 du dernier commit en date sur cette branche, depuis lequel on peut « remonter le fil » et que les tags fonctionnent de la même façon. Il se trouve que ces étiquettes peuvent également fonctionner comme des liens symboliques UNIX : plutôt que directement contenir le hash du commit cible, elles peuvent également contenir le nom d'une autre étiquette. GIt « suit » alors la flèche et tente de « déréférencer » toutes les symrefs successivement jusqu'à ce qu'il atteigne un hash valide.

    Ici, cela sert à indiquer que ta position courante (matérialisée par HEAD) n'est pas seulement le dernier commit en date mais bien la position de la branche « develop », et c'est de cette façon que l'on émule le « mode attaché ».

    Voir :


    Puis je suis revenu sur mon code, et j'ai oublié que j'étais sur main.
    j'ai fait les modif, j'ai commité et pushé vers la branche main en remote.

    Et c'est là où je suis perdu.
    Comme indiqué au début, je crée mes branches à partir de develop car, ensuite, je merge vers develop et ensuite je merge vers main.

    Mais maintenant, la branche develop n'a pas les dernieres modif de main vu que j'ai pushé vers vers main directement.

    Je ne peux pas faire une branche à partir de develop pour ensuite merger vers develop et merger vers main…, vu que je n'aurai pas les dernières modifs qui étaient sur main.
    D'accord, donc tu as publié tes derniers travaux en date directement sur main. Jusque là, rien de dramatique.
    J'imagine que tu voudrais d'abord les déplacer au minimum au sommet de develop, puis fusionner cette dernière normalement avec main.

    Par contre, question importante : lorsque tu fusionnes develop avec main, est-ce que tu le fais en général en « avance rapide » (fast-forward) ou bien forces-tu « --no-ff » ?

    J'ai alors tenté au hasard cette commande :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    git fetch origin main:develop
    Je pensais récupérer ce qu'il y a sur le main et le ramener vers develop.
    Ça par contre, c'est une drôle d'idée. Non pas de vouloir essayer de s'en sortir, mais d'utiliser des commandes au hasard sur un dépôt en production, de surcroît dans lequel tu t'es mis en difficulté.

    A minima, il faut faire une copie quelque part, soit en dupliquant ton dépôt local, soit en ré-effectuant git clone depuis un autre répertoire pour garder inchangé celui dans lequel tu t'es perdu. Mais dans tous les cas, à terme, tu ne devrais même plus avoir besoin de le faire car Git est très simple à dépanner… quand on a compris comment il marche.

    L'expression « main:develop » passée après le nom de dépôt est une « refspec ». Elle fait l'objet d'une page dédiée dans la documentation :
    https://git-scm.com/book/fr/v2/Les-t...Git-La-refspec

    Formellement, c'est une expression utilisée par fetch et par push qui permet d'affecter directement la valeur d'une référence source à une référence destination. Je te laisse lire la documentation à son sujet (ou alors on en parlera dans les commentaires) mais pour faire court, en faisant cela, tu as forcé la branche locale develop à se positionner à l'endroit où se trouver la branche distante main.

    Cela implique une fusion et comme tu n'as pas ajouté le préfixe « + », celle-ci est forcément en avance rapide (fast forward). Et parce que tu as d'abord fusionné develop vers main puis que tu as déposé ton travail récent sur main (et poussé le tout), ces deux branches se retrouvent sur la même lignée, main étant en avance. Donc l'avance rapide de develop devient possible même si ce n'est pas ce qui était souhaité.


    Je l'ai tenté plusieurs fois car je ne sais pas sur quelle branche j'étais quand j'ai essayé cette commande la première fois.
    Puis j'ai essayé en me plaçant sur une autre branche.

    Puis au final, j'ai vu sur la branche develop, en local que j'ai récupéré le travail de main.
    Oui, puisque tu l'as forcée à rejoindre la position de main.

    On dirait que ca a marché mais quand je vais sur github et que je regarde develop en remote, je ne vois pas le dernier travail.
    En effet, il faut pousser l'état de ton dépôt local vers le serveur d'abord… à condition que ce soit bien l'état que tu recherches.

    Quand je fais git status, Git me dit que je suis à jour : je pense qu'il compare avec mon dépôt local.
    J'ai alors fait un push et maintenant je vois bien sur le remote sur la branche develop les derniers travaux.
    Oui car tu as synchronisé le serveur avec l'état de ton dépôt local.

    Là encore, tout dépend de la façon dont tu fais tes fusions en général. Si c'est en fast-forward par défaut, tu as probablement rejoint l'état correct sans le faire exprès. Si en revanche, tu as l'habitude de faire de vrais points de fusion (ce qui en principe est une bonne chose) avec « --no-ff », alors il faudra réécrire tes branches au propre. La bonne nouvelle est qu'il existe des choses pour le faire avec Git.

  3. #3
    Membre à l'essai
    Homme Profil pro
    Analyste d'exploitation
    Inscrit en
    Novembre 2022
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Analyste d'exploitation

    Informations forums :
    Inscription : Novembre 2022
    Messages : 26
    Points : 18
    Points
    18
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    Bonsoir,

    En effet, pas mal de confusion dans tout cela. Avant d'entrer dans les détails, peux-tu nous indiquer ce que utilises au quotidien pour parcourir ton historique ? En particulier, utilises-tu git log --graph, par exemple, ou mieux encore tig, gitk ou l'explorateur de VSCode ? Parce que si tu t'en tiens à un simple git log linéaire (fût-ce avec --oneline), il est beaucoup plus difficile de se représenter mentalement la structure de la hiérarchie du dépôt.

    Bon, tu utilises quand même Github ou Gitlab, donc je suppose que tu profites des facilités mises en place de leur côté.
    j'utilise rien, je fais juste un git log --oneline, je vais tester avec --graph


    Par contre, question importante : lorsque tu fusionnes develop avec main, est-ce que tu le fais en général en « avance rapide » (fast-forward) ou bien forces-tu « --no-ff » ?
    je fais ca avec github, je ne sais pas quel mode ca utilise.
    c'est quoi la diff entre les deux?

    je suis en train de lire doucement ta reponse. merci

  4. #4
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 415
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 415
    Points : 23 879
    Points
    23 879
    Par défaut
    Citation Envoyé par gitnoob Voir le message
    j'utilise rien, je fais juste un git log --oneline, je vais tester avec --graph
    Dans ce cas, je te conseille effectivement de commencer avec --graph (depuis lequel tu devrais retrouver à peu près ce que tu vois chez Github), puis de choisir un client Git, graphique ou pur texte dans un terminal. Personnellement, j'utilise tig sous Linux, qui a l'avantage d'être packagé dans toutes les distributions, d'être léger, de fonctionner dans un terminal et de s'en tenir à la mise en forme et à quelques commandes élémentaires, ce qui permet de visualiser facilement son dépôt tout en s'en tenant aux vraies commandes Git lorsqu'il s'agit de modifier son dépôt.

    En voici une liste :
    https://git-scm.com/downloads/guis
    https://archive.kernel.org/oldwiki/g...sAndTools.html


    je fais ca avec github, je ne sais pas quel mode ca utilise.
    c'est quoi la diff entre les deux?
    « L'avance rapide » ou « fast forward » (--ff) est effectivement un concept-clé sous Git car il découle naturellement de l'architecture en graphe du système. On y est confronté en permanence. C'est également ce qui fait que la fusion de deux branches et la mise à jour d'une branche par rapport à son homologue sont en fait une seule et même opération sous Git.

    Lorsque tu utilises une branche locale main et une branche origin/main (ou master, initialement sous Git), il s'agit en fait bel et bien de deux branches distinctes, même si l'une est configurée pour suivre l'autre. C'est d'ailleurs bien le cas puisque lorsque l'on est tout seul à travailler sur un projet, on ne sert des branches distantes que pour sauvegarde, publication et mise en ligne mais on est plusieurs dessus, alors la branche distante origin/main va évoluer indépendant de la branche locale main au gré de ce que les autres personnes vont pousser dessus. Il faut donc bien rapatrier d'abord les nouveautés qui s'y trouvent avec pull avant d'y intégrer les siennes.

    En ce sens, Git va donc traiter les branches locale main et distante origin/main comme s'il s'agissait de deux branches ordinaires, locales, et a priori indépendantes entre elles. Ceci veut dire que tout ce qui suit peut également s'appliquer sur de telles branches ordinaires, lorsque tu les fusionnes.


    1er cas

    Toi et un de tes collègues avez travaillé tous deux sur origin/main en même temps (parce que vous avez travaillé sur vos main respectives en local avant de pousser tout ça sur le serveur). Vous vous retrouvez dans la situation suivante :

    
    Toi  O     O  Ton collègue
          \   /
           \ /
            O Dernier commit commun en date
            |
            O 
            |
            …
    
    
    La branche jusqu'ici commune a alors divergé et c'est ce que Git t'indique quand tu fais git pull. Il faut alors résoudre les éventuels conflits et re-fusionner ces deux nouvelles branches en une seule. Tu obtiens alors :

    
       Toi  O  Ton collègue
           / \
          /   \
         O     O
          \   /
           \ /
            O Dernier commit commun en date
            |
            O 
            |
            …
    
    
    … tu pousses le tout, le serveur est de nouveau synchrone avec l'état de ton dépôt local et vous pouvez continuer à travailler.


    2ème cas

    Ton collègue est le seul à avoir ajouté des choses sur le serveur depuis la dernière fois que vous étiez synchrones. Tu es donc dans la situation suivante :

    
               O  Ton collègue (sur origin/main)
              /
             /
            O  Toi — Dernier commit commun en date (sur main)
            |
            O 
            |
            …
    
    
    Dans ce cas, on est d'accord que ce graphe-là est en fait exactement le même que :

    
            O  Ton collègue (sur origin/main)
            |
            |
            O  Toi — Dernier commit commun en date (sur main)
            |
            |
            O 
            |
            …
    
    
    …dans le sens où c'est un graphe. Seules comptent les références de chaque commit à leur(s) parent(s), la position qu'ils occupent dans le plan n'ayant pas de signification pour la machine. Il faut voir ça comme une chaîne de trombones, si tu préfères. C'est important non seulement pour avoir une bonne représentation de comment tout cela fonctionne, mais également parce que les clients Git cités en tête de commentaire vont te les représenter de la même façon.

    On constate également que dans cette situation, on n'a besoin de transférer des données que dans un seul sens (ici, du serveur vers ton dépôt), et que ta branche locale est déjà « entièrement contenue » dans la branche distante (ce qui en fait un sous-ensemble). Par conséquent, il n'y a aucun conflit possible puisque les nouveautés de la branche distante s'appuient déjà sur le sommet de ta branche locale.

    En conséquence, la seule chose que Git ait besoin de faire ici est télécharger les objets manquants chez toi (les références qu'ils contiennent construisant automatiquement l'historique) et une fois que c'est fait, mettre à jour l'étiquette main pour qu'elle pointe le dernier objet en date. Une fois que c'est fait, ta branche devient automatiquement l'identique de celle du serveur.

    C'est exactement cela que Git appelle une « avance rapide » et si ta branche est configurée pour (elle l'est par défaut), alors Git va procéder de cette façon chaque fois qu'il le pourra. Autrement, tu obtiendras un commit formant un « point de fusion » comme au sommet du premier cas.

    On comprend ici que c'est parfaitement adapté à la synchronisation d'une branche locale↔distante. Les commandes push et pull existaient bien avant Git et servaient déjà à synchroniser des dépôts homologues avant même que certains SCM adoptent le modèle en graphe. La plupart du temps, l'utilisateur n'est même pas conscient de ce fait et voit sa branche se compléter naturellement avec les dernières publications en date, ce qui est le comportement attendu.

    Par contre, si tu fusionnes deux branches locales chez toi de la même façon, le même phénomène va se produire, mais ce n'est pas forcément ce que tu veux. Si tu fais démarrer une branche develop à partir de main et que tu travailles dessus, tu obtiens :

    
               O Commit spécifique 3 (develop)
               |
               O Commit spécifique 2
               |
               O Commit spécifique 1
              /
             /
            O  Commit général n (main)
            |
            O  Commit général n-1
            |
            O  Commit général n-2
            |
            …
    
    
    Si tu reviens sur main et que tu essaies d'intégrer ta branche develop en la fusionnant, Git aura l'impression que main est en retard sur develop et va la mettre à jour en avance rapide comme dans le cas n° 2 présenté plus haut. Tu obtiens alors :

    
            O Commit spécifique 3 (develop) (main)
            |
            O Commit spécifique 2
            |
            O Commit spécifique 1
            |
            O  Commit général n
            |
            O  Commit général n-1
            |
            O  Commit général n-2
            |
            …
    
    
    … ce qui est pratique si develop est la branche instable et que seule main contient ce qui a été validé et peut être publié. Mais peut-être souhaitais-tu faire exactement ce que tu fais avec les sous-branches que tu as supprimé ensuite (cleanup, clear_input, etc.), à savoir : conserver la structure de la branche annexe, même si la branche principale ne contient aucun commit entretemps :

    
            O Point de fusion (main)
            |\
            | \
            |  \
            |   |
            |   O Commit spécifique 3 (develop)
            |   |
            |   O Commit spécifique 2
            |   |
            |   O Commit spécifique 1
            |   |
            |  /
            | /
            |/
            O  Commit général n
            |
            O  Commit général n-1
            |
            O  Commit général n-2
            |
            …
    
    
    Dans tous ces cas, tu peux soit configurer la branche une fois pour toutes pour qu'elle adopte le comportement souhaité par défaut, soit passer à git commit l'option --ff ou l'option --no-ff.
    • --ff force le mode « avance rapide ». La commande échoue si ce n'est pas possible ;
    • --no-ff interdit l'avance rapide même si elle aurait été possible, et force la création d'un point de fusion dans tous les cas.


    Ceci nous amène à la conclusion de notre dernier commentaire : en utilisant une refspec, tu as forcé la mise à jour d'une étiquette locale pour qu'elle pointe au même endroit qu'une étiquette distante, quelles que soient ces étiquettes même si elles n'ont rien à voir entre elles. C'est en principe une mauvaise chose, mais si tu as forcé develop à se positionner au même endroit que origin/main, alors il se trouve que tu as obtenu par accident ce que tu aurais obtenu en fusionnant develop dans main car comme tu as accidentellement développé sur cette dernière, c'était develop qui était en retard par rapport à main et la fusionner l'aurait mise à jour en avance rapide, et donc aurait fait pointer les étiquettes au même endroit.

    Bref, vérifie bien que tu as retrouvé tout ce que tu voulais retrouver et si c'est le cas, c'est que tu as pu retomber sur tes pieds par un coup de chance. Mais sois plus prudent la prochaine fois. ;-)

    je suis en train de lire doucement ta reponse. merci
    N'hésite pas à poser les questions qui en découleraient dans ce même fil, et à cliquer sur en bas de page quand tu auras obtenu pleine satisfaction.

Discussions similaires

  1. Un peu perdu dans mes requêtes
    Par PhilCou dans le forum Langage SQL
    Réponses: 1
    Dernier message: 06/02/2010, 21h53
  2. Partition perdues, et perdu dans mes partitions
    Par Alamassepointcom dans le forum Administration système
    Réponses: 7
    Dernier message: 08/02/2008, 21h50
  3. [XSLT] Suis perdu dans template:match
    Par kabkab dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 11/05/2007, 16h58
  4. Perdu dans mes compilation setting
    Par houam3012 dans le forum Langage
    Réponses: 2
    Dernier message: 04/05/2007, 12h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo