Aller au contenu
English

Synchroniser de façon réfléchie

  • Leçon 5
  • 40 min
  • Module 2 : Travailler avec les branches et les dépôts distants

Ce que vous saurez faire

Partagez vos commits (instantanés enregistrés) avec une équipe et récupérez les siens, sans surprises. Après cette leçon, vous pourrez dire exactement ce que chaque commande a changé : votre dépôt ou le dépôt distant.

Avant de commencerCe qu’il faut savoir et avoir sous la mainEnviron 40 minutes

Ce que vous devez savoir

Ce qu’il vous faut sur votre ordinateur

  • Le dépôt ~/projects/ticket-notes avec les branches main et add-priorities. Vous avez créé add-priorities dans Bases des branches : exercice guidé : travailler sur une branche. Si elle manque, refaites cet exercice guidé.

  • Dans le dépôt, git status affiche working tree clean (arbre de travail propre).

  • Pour la tâche « À vous de jouer », la branche add-contacts. Vous l’avez créée dans Bases des branches : à vous de jouer : une deuxième branche. Si vous ne l’avez pas, la tâche explique comment la créer.

  • Si le dépôt manque ou ne fonctionne plus, un script peut recréer l’état de départ de cette leçon. Dans ~/projects, exécutez :

    Fenêtre de terminal
    git clone https://github.com/Nextia-Intelligence/nextia-learning-labs.git
    sh nextia-learning-labs/C14/setup.sh m02-l02 --reset

    Exécutez la commande git clone une seule fois. Si vous avez déjà le dossier nextia-learning-labs, exécutez plutôt git -C nextia-learning-labs pull. Les étapes d’une demande de tirage : préparer le laboratoire d’exercice explique le script en détail. Le script crée ~/projects/c14-lab/ticket-notes avec main à d8ae027 et add-priorities à 999a7c4, les mêmes empreintes que dans cette leçon. Ce dépôt n’a ni dépôt distant ni branche add-contacts. Les commits que vous créez dans cette leçon, comme Amira ou Sam, ont des empreintes différentes de celles présentées, par exemple 1d45995. C’est normal. Utilisez ensuite ~/projects/c14-lab à la place de ~/projects dans cette leçon. --reset supprime d’abord un ancien dossier c14-lab, mais votre dépôt ~/projects/ticket-notes ne change pas.

  • Vous n’avez pas besoin d’un compte sur un site Web. Dans cette leçon, le dépôt distant est un dossier sur votre ordinateur. Vous le créez dans Créer un dépôt distant d’exercice.

Dans Configurer Git, vous avez appris qu’un dépôt distant est une copie du dépôt à un autre endroit. Votre équipe l’utilise pour partager son travail. Git ne reste pas connecté au dépôt distant. Il se connecte seulement quand vous exécutez l’une de ces trois commandes :

Commande Ce qu’elle change
git fetch Récupère les nouveaux commits du dépôt distant. Met à jour seulement votre représentation du dépôt distant. Vos branches et fichiers ne changent pas.
git pull Exécute git fetch, puis met à jour votre branche courante avec les nouveaux commits.
git push Envoie vos nouveaux commits au dépôt distant et déplace la branche sur ce dépôt.

Votre « représentation du dépôt distant » est un ensemble de branches de suivi à distance, avec des noms comme origin/main. origin/main indique où se trouvait main sur le dépôt distant lors de votre dernière connexion. Elle ne se met pas à jour toute seule. Si un collègue pousse des commits, origin/main reste inchangée jusqu’à ce que vous exécutiez git fetch.

Deux zones. À droite, le dépôt distant nommé origin contient main, le travail partagé de l'équipe. À gauche, votre ordinateur contient main, votre travail, et origin/main, ce que vous avez vu lors de votre dernière connexion. git fetch va de main sur le dépôt distant à origin/main. git pull va aussi de origin/main à votre main. git push va de votre main à main sur le dépôt distant.
git fetch met à jour seulement origin/main. git pull met aussi à jour votre main. git push met à jour le dépôt distant.

Votre branche main est liée à origin/main. Ce lien fait de origin/main la branche en amont de main, et de main une branche de suivi. Grâce à ce lien, git status, git pull et git push savent quelle branche distante comparer et utiliser.

Une équipe garde généralement son dépôt distant sur un serveur, comme GitHub. Le serveur conserve un dépôt nu : un dépôt avec seulement l’historique, sans arbre de travail. Personne n’y modifie de fichiers. On y pousse seulement des commits, ou on en récupère.

Vous pouvez créer un dépôt nu dans un dossier et l’utiliser comme dépôt distant. Git le traite comme un serveur.

  1. Créez le dépôt nu à côté de ticket-notes :

    Fenêtre de terminal
    cd ~/projects
    git init --bare team-remote.git
    Initialized empty Git repository in /Users/amira/projects/team-remote.git/

    Par convention, le nom se termine par .git pour indiquer que le dossier est un dépôt nu.

  2. Ouvrez ticket-notes et reliez-le au nouveau dépôt distant sous le nom origin :

    Fenêtre de terminal
    cd ticket-notes
    git remote add origin ../team-remote.git
    git remote -v
    origin ../team-remote.git (fetch)
    origin ../team-remote.git (push)

    .. désigne le dossier parent. Le chemin pointe donc vers ~/projects/team-remote.git.

  3. Configurez Git pour que git pull fasse une mise à jour seulement quand elle est sans risque. L’exemple détaillé explique pourquoi.

    Fenêtre de terminal
    git config --global pull.ff only

Exemple détaillé : Amira et Sam partagent leur travail

Section intitulée « Exemple détaillé : Amira et Sam partagent leur travail »

Amira envoie main au dépôt distant. L’option -u définit origin/main comme branche en amont de main. Vous avez besoin de -u seulement la première fois que vous poussez une branche.

Terminal (Amira)
git push -u origin main
Sortie
To ../team-remote.git
* [new branch] main -> main
branch 'main' set up to track 'origin/main'.

Elle pousse aussi sa branche de fonctionnalité pour que son équipe puisse la voir :

Terminal (Amira)
git push -u origin add-priorities
git branch -vv
Sortie
To ../team-remote.git
* [new branch] add-priorities -> add-priorities
branch 'add-priorities' set up to track 'origin/add-priorities'.
add-priorities 999a7c4 [origin/add-priorities] Add priority levels
* main d8ae027 [origin/main] Add first ticket note

git branch -vv affiche chaque branche, son commit et sa branche en amont entre crochets.

Sam est le collègue d’Amira. Il clone le dépôt distant, ajoute un billet (de soutien) à tickets.txt, crée un commit et le pousse. Après le clonage, la branche en amont est déjà définie. Sam n’a donc pas besoin de -u :

Terminal (Sam)
git clone team-remote.git sam-notes
cd sam-notes
git commit -am "Add ticket 102"
git push
Sortie (fin)
To /Users/sam/projects/team-remote.git
d8ae027..1d45995 main -> main

git commit -am prépare tous les fichiers suivis qui ont changé et crée un commit en une seule étape. d8ae027..1d45995 signifie que main sur le dépôt distant est passée de d8ae027 à 1d45995.

Amira récupère les commits, puis met sa branche à jour

Section intitulée « Amira récupère les commits, puis met sa branche à jour »

Amira ne connaît pas encore le commit de Sam. git status indique toujours qu’elle est à jour, car il compare sa branche avec son ancienne origin/main. Elle récupère les commits :

Terminal (Amira)
git fetch
git status
Sortie
From ../team-remote
d8ae027..1d45995 main -> origin/main
On branch main
Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)

La récupération a déplacé seulement origin/main. Sa branche main et ses fichiers n’ont pas changé. Avant d’intégrer le nouveau commit, elle vérifie ce qu’il change. La comparaison des différences compare sa branche main avec origin/main :

Terminal (Amira)
git diff main origin/main
Sortie
diff --git a/tickets.txt b/tickets.txt
index c1b66eb..e2b0391 100644
--- a/tickets.txt
+++ b/tickets.txt
@@ -1 +1,2 @@
Ticket 101: printer offline. Restarted the spooler.
+Ticket 102: password reset email not received.

Le changement est correct. Elle met donc sa branche à jour :

Terminal (Amira)
git pull
Sortie
Updating d8ae027..1d45995
Fast-forward
tickets.txt | 1 +
1 file changed, 1 insertion(+)

L’avance rapide signifie que Git a seulement déplacé l’étiquette main jusqu’au commit de Sam. C’est possible parce qu’Amira n’avait aucun nouveau commit à elle sur main. Aucun nouveau commit n’a été créé.

Sam pousse maintenant un deuxième billet. En même temps, Amira crée un commit avec un nouveau fichier, contacts.txt, sur sa branche main. Elle essaie de le pousser :

Terminal (Amira)
git push
Sortie
To ../team-remote.git
! [rejected] main -> main (fetch first)
error: failed to push some refs to '../team-remote.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. ...

Le dépôt distant refuse l’envoi. S’il l’acceptait, le commit de Sam disparaîtrait de main. Amira tente de mettre sa branche à jour :

Terminal (Amira)
git pull
Sortie
From ../team-remote
1d45995..7d54ed4 main -> origin/main
hint: Diverging branches can't be fast-forwarded, ...
fatal: Not possible to fast-forward, aborting.

La récupération a fonctionné, mais Git n’a pas changé main. Les historiques ont divergé : chaque côté a un commit que l’autre n’a pas. git log --oneline --graph --all montre la séparation :

Sortie (premières lignes)
* 01f2b94 (HEAD -> main) Add contacts
| * 7d54ed4 (origin/main, origin/HEAD) Add ticket 103
|/
* 1d45995 Add ticket 102

C’est pourquoi vous avez défini pull.ff only. Sans ce réglage, git pull peut réunir les deux historiques automatiquement, sans que vous le remarquiez. Avec ce réglage, Git s’arrête et vous choisissez quoi faire.

Amira décide de faire une fusion (merge). Elle réunit les deux lignes d’historique avec un nouveau commit qui a les deux comme parents. L’option --no-edit conserve le message que Git suggère :

Terminal (Amira)
git pull --no-rebase --no-edit
git log --oneline --graph -4
Sortie
Merge made by the 'ort' strategy.
tickets.txt | 1 +
1 file changed, 1 insertion(+)
* 7f87ca6 (HEAD -> main) Merge branch 'main' of ../team-remote
|\
| * 7d54ed4 (origin/main, origin/HEAD) Add ticket 103
* | 01f2b94 Add contacts
|/

Sa branche main contient maintenant les deux commits. Elle peut donc les pousser sans risque :

Terminal (Amira)
git push
Sortie
To ../team-remote.git
7d54ed4..7f87ca6 main -> main

Vous jouez Amira dans ticket-notes et Sam dans un deuxième clone.

  1. Créez le dépôt distant d’exercice et reliez-le, comme dans Créer un dépôt distant d’exercice.

  2. Dans ticket-notes, poussez les deux branches :

    Fenêtre de terminal
    git push -u origin main
    git push -u origin add-priorities
  3. Exécutez git branch -vv. Chaque branche affiche sa branche en amont entre crochets.

  4. Créez le clone de Sam et ouvrez-le :

    Fenêtre de terminal
    cd ~/projects
    git clone team-remote.git sam-notes
    cd sam-notes
  5. Ajoutez une ligne à tickets.txt dans sam-notes, puis créez un commit et poussez-le :

    Fenêtre de terminal
    git commit -am "Add ticket 102"
    git push
  6. Retournez dans ticket-notes et exécutez git status. Il indique encore up to date (à jour), car vous n’avez pas récupéré les commits.

  7. Récupérez les commits et vérifiez de nouveau :

    Fenêtre de terminal
    cd ~/projects/ticket-notes
    git fetch
    git status

    La sortie indique behind 'origin/main' by 1 commit (un commit de retard sur origin/main).

  8. Exécutez git diff main origin/main. La sortie montre la nouvelle ligne.

  9. Exécutez git pull. La sortie contient Fast-forward (avance rapide).

  10. Exécutez git log --oneline -1. Le commit le plus récent est celui de l’étape 5.

À vous de jouer : partager une branche de fonctionnalité

Section intitulée « À vous de jouer : partager une branche de fonctionnalité »

L’équipe veut examiner votre branche add-contacts de la leçon Bases des branches. Si vous ne l’avez pas, créez-la à partir de main maintenant.

  1. Poussez add-contacts vers le dépôt distant et définissez sa branche amont.
  2. Dans sam-notes, récupérez la branche avec git fetch, puis exécutez git switch add-contacts. Git crée une branche locale qui suit origin/add-contacts.
  3. Dans sam-notes, ajoutez un nom à contacts.txt, créez un commit (enregistrement des changements), puis poussez-le.
  4. Dans ticket-notes, intégrez le nouveau commit à votre branche add-contacts.

Écrivez ensuite une phrase pour chaque commande utilisée : a-t-elle modifié votre historique local, le dépôt distant ou seulement votre copie de référence du dépôt distant?

Afficher une réponse modèle
  • git push -u origin add-contacts (dans ticket-notes) : a modifié le dépôt distant. Elle y a créé add-contacts.
  • git fetch (dans sam-notes) : a modifié seulement la copie de référence du dépôt distant : elle a ajouté origin/add-contacts.
  • git switch add-contacts (dans sam-notes) : a modifié l’historique local dans le clone de Sam. Elle a créé une nouvelle branche locale.
  • git commit (dans sam-notes) : a modifié l’historique local dans le clone de Sam.
  • git push (dans sam-notes) : a modifié le dépôt distant.
  • git switch add-contacts, puis git pull (dans ticket-notes) : la commande pull a récupéré les changements, puis modifié l’historique local. Elle a fait avancer votre branche add-contacts par une avance rapide.

Erreur courante

Envoi refusé : récupérer d'abord

Symptôme : git push affiche ! [rejected] main -> main (fetch first) (envoi refusé, récupérer d’abord), ou (non-fast-forward) (avance rapide impossible).

Cause : la branche distante contient des commits que vous n’avez pas. Git refuse l’envoi pour éviter de perdre ces commits.

Solution :

  1. Exécutez git pull.
  2. Si la commande pull affiche Fast-forward (avance rapide), exécutez de nouveau git push.
  3. Si elle affiche Not possible to fast-forward (avance rapide impossible), exécutez git log --oneline --graph --all pour voir les deux historiques. Exécutez ensuite git pull --no-rebase --no-edit pour les fusionner, puis poussez de nouveau.

Ne forcez jamais l’envoi pour « corriger » un refus. Un envoi forcé remplace la branche distante par la vôtre. Les commits de votre collègue disparaissent alors de cette branche. Le module 4 explique quand il est acceptable de réécrire un historique partagé.

Erreur courante

Aucune branche amont

Symptôme : git push affiche fatal: The current branch add-contacts has no upstream branch. (la branche actuelle add-contacts n’a aucune branche amont). Ou git pull affiche There is no tracking information for the current branch. (aucune information de suivi pour la branche actuelle).

Cause : cette branche n’est pas encore liée à une branche distante. Habituellement, vous l’avez créée localement sans jamais la pousser.

Solution : poussez-la une fois avec -u, par exemple git push -u origin add-contacts. Ensuite, git push et git pull fonctionnent sans options supplémentaires.

Vérifiez votre compréhension

Prédisez : Sam pousse un commit. Amira exécute git fetch. Les fichiers de son arbre de travail changent-ils? Sa branche main change-t-elle?

Afficher la réponse

Non dans les deux cas. git fetch modifie seulement origin/main, sa copie de référence du dépôt distant. Ses fichiers et sa branche main restent inchangés jusqu’à ce qu’elle exécute git pull (ou fusionne elle-même origin/main).

Vérifiez votre compréhension

Vérification finale : dans l'exemple détaillé, quelles commandes ont modifié l'historique local d'Amira, et lesquelles ont mis à jour le dépôt distant?

Afficher la réponse
  • L’historique local : git commit (Add contacts, soit « Ajouter des contacts »), git pull par avance rapide et git pull --no-rebase --no-edit, qui a créé un commit de fusion.
  • Le dépôt distant : chaque git push. Les deux premiers ont créé de nouvelles branches dans le dépôt distant. Le dernier a déplacé la branche distante main vers le commit de fusion.
  • Ni l’un ni l’autre : git fetch a mis à jour seulement origin/main. Le git pull qui a échoué a fait de même : la récupération a fonctionné, puis il s’est arrêté avant de modifier main. Le git push refusé n’a rien modifié.

Récapitulatif

  • origin/main est votre copie de référence du dépôt distant. Seul git fetch (ou git pull) la met à jour.
  • git fetch ne modifie aucune de vos branches. git pull récupère les changements, puis met à jour votre branche actuelle. git push met à jour le dépôt distant.
  • -u lie une branche à sa branche amont la première fois que vous la poussez.
  • Une avance rapide déplace seulement une étiquette. Quand les historiques ont divergé, vous devez les réunir, par exemple avec une fusion.
  • Avec pull.ff only, Git ne réunit jamais des historiques divergents sans votre décision.

Leçon suivante : Garder le dépôt propre