-
Notifications
You must be signed in to change notification settings - Fork 22
quick start 02 collab
Ce tutoriel vous accompagne dans la collaboration à plusieurs sur un projet hébergé sur Github. Au long de ce tutoriel nous verrons comment récupérer du code écrit par d'autres membres du projet, comment combiner son travail avec celui des autres et pour finir comment résoudre les éventuels conflits.
Ce tutoriel n'explique pas comment utiliser les branches ni comment faire des pull-request. Il n'explique par non plus les différentes techniques de fusions tel que les différences entre merge
, rebase
, fast-forward
et cherry-pick
. Ces thématiques sont abordées dans le prochain tutoriel.
Vous devez avoir suivi le premier tutoriel avant d’entamer celui-ci.
Pour cet exercice, nous continuons d'utiliser le projet que vous avez créé dans le tutoriel précédent. Pour simuler que plusieurs personnes travaillent sur ce même projet nous allons le cloner une seconde fois sur le même ordinateur.
Entrez dans le premier projet et assurez vous d'être correctement synchronisé avec Github. Le git status
doit dire "On branch main. Your branch is up to date with 'origin/main'. nothing to commit, working tree clean". Si ce n'est pas le cas, suivez les instructions qui sont affichés dans le résultat de la commande.
En guise d'exemple, nous avions cloné le projet la première fois dans le dossier ~/Ephec/sandbox
, nous allons cloner le projet une seconde fois cette fois-ci dans le dossier ~/Ephec/bacasable
. Le nom des dossiers importent peu.
~/Ephec $ git clone https://github.com/julien00859/sandbox bacasable
Cloning into 'bacasable'...
remote: Enumerating objects: 11, done.
remote: Counting objects: 100% (11/11), done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 11 (delta 4), reused 6 (delta 2), pack-reused 0
Receiving objects: 100% (11/11), done.
Resolving deltas: 100% (4/4), done.
~/Ephec $ ls
bacasable sandbox
Vous pouvez vérifier que les deux projets ont le même status et le même historique. Nous utilisons l'option --oneline
avec git log
pour avoir un affichage plus court.
$ cd ~/Ephec/sandbox
~/Ephec/sandbox$ git status
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean
~/Ephec/sandbox$ git log --oneline
daaec07 (HEAD -> main, origin/main, origin/HEAD) doc(README): greet new users
0efccf0 Initial commit
$ cd ~/Ephec/bacasable
~/Ephec/bacasable$ git status
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean
~/Ephec/bacasable$ git log --oneline
daaec07 (HEAD -> main, origin/main, origin/HEAD) doc(README): greet new users
0efccf0 Initial commit
Rappelons que les hash des commits sont calculés aussi sur base du nom et de l'email de l'auteur ainsi que de la date et de l'heure. Vous devriez donc avoir des hash de commit différents. Vérifiez juste que ces hash concordent entre eux dans vos dossiers.
Nous allons créer un commit du côté sandbox, l'envoyer sur Github et ensuite le récupérer sur bacasable.
Commençons par créer un commit, nous allons encore une fois modifier le fichier README.md
. Ouvrez votre éditeur préféré, modifiez le fichier. Vérifiez que les changements ont été détecté avec git status
et git diff
. Créez un nouveau commit avec git add
et git commit
(vous pouvez utiliser l'option -a
de git commit
pour automatiquement ajouter tous les fichiers modifiés). Envoyez le commit sur Github avec git push
.
~/Ephec/sandbox$ vim README.md # modifier "Bonjour" par "Bonjour tout le monde"
~/Ephec/sandbox$ git status
On branch main
Your branch is up to date with 'origin/main'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
~/Ephec/sandbox$ git diff
diff --git a/README.md b/README.md
index 51a4dfc..ece96c9 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
# sandbox
Un bac-à-sable pour s'entrainer avec git et github
-Bonjour
+Bonjour tout le monde
~/Ephec/sandbox$ git commit -am "doc(README): better greeting"
[main b76619e] doc(README): better greeting
1 file changed, 1 insertion(+), 1 deletion(-)
~/Ephec/sandbox$ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 316 bytes | 316.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To https://github.com/Julien00859/sandbox.git
daaec07..b76619e main -> main
Vous pouvez ouvrir Github pour constater que le README a bel et bien changé et qu'il y a bel et bien eu un nouveau commit.
Déplacez-vous maintenant dans le dossier bacasable
et entrez les commandes git status
et git log
.
~/Ephec/bacasable$ git status
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean
~/Ephec/bacasable$ git log --oneline
daaec07 (HEAD -> main, origin/main, origin/HEAD) doc(README): greet new users
0efccf0 Initial commit
Le git status
semble prétendre que nous sommes à jour avec Github, en étudiant le git log
on constate qu'il n'a pas trace du nouveau commit que nous venons d'envoyer sur Github: nous somme en fait désynchronisé.
Pour demander à git de se resynchroniser nous pouvons utiliser la commande git fetch
suivi de git status
pour constater les changements:
~/Ephec/bacasable$ git fetch
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 3 (delta 2), reused 3 (delta 2), pack-reused 0
Unpacking objects: 100% (3/3), 296 bytes | 296.00 KiB/s, done.
From https://github.com/julien00859/sandbox
daaec07..b76619e main -> origin/main
~/Ephec/bacasable$ git status
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)
nothing to commit, working tree clean
Nous attirons votre attention sur le résultat du git status
:
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.
Ce message signifie qu'il existe un commit sur 'origin/main' (la branche main sur Github) qui n'est pas présent sur la branche main de notre ordinateur. Git nous informe aussi que nous pouvons fast-forward, c'est le jargon de git pour dire que notre historique est juste en retard sur l'historique de Github et qu'il n'y aura pas de conflit si on git pull
.
Nous pouvons constater la même chose que git status
en affichant l'historique des deux branches:
~/Ephec/bacasable$ git log main --oneline
daaec07 (HEAD -> main) doc(README): greet new users
0efccf0 Initial commit
~/Ephec/bacasable$ git log origin/main --oneline
b76619e (origin/main, origin/HEAD) doc(README): better greeting
daaec07 (HEAD -> main) doc(README): greet new users
0efccf0 Initial commit
Maintenant que notre git est au courant des changements, nous pouvons télécharger les changements depuis Github avec la commande git pull
.
~/Ephec/bacasable$ git pull
Updating daaec07..b76619e
Fast-forward
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Nous pouvons aussi constater les changements avec git status
, git log
et git show
.
~/Ephec/bacasable$ git status
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean
~/Ephec/bacasable$ git log --oneline
b76619e (HEAD -> main, origin/main, origin/HEAD) doc(README): better greeting
daaec07 doc(README): greet new users
0efccf0 Initial commit
~/Ephec/bacasable$ git show
commit b76619ed0dc71d824749f672c0d59e6343584ab5 (HEAD -> main, origin/main, origin/HEAD)
Author: Julien Castiaux <j.castiaux@ephec.be>
Date: Sun Feb 12 16:32:29 2023 +0100
doc(README): better greeting
diff --git a/README.md b/README.md
index 51a4dfc..ece96c9 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
# sandbox
Un bac-à-sable pour s'entrainer avec git et github
-Bonjour
+Bonjour tout le monde
Nous pouvons aussi constater que le README a bel et bien été modifié, nous avons correctement récupérer les changements faits de l'autre côté.
~/Ephec/bacasable$ cat README.md
# sandbox
Un bac-à-sable pour s'entrainer avec git et github
Bonjour tout le monde
Nous venons de voir le cas simple où un des PC était strictement en retard par rapport au travail effectué sur l'autre PC. Maintenant nous allons étudier la situation où du travail a été effectué sur chacun des PC et qu'il faut mettre ce travail en commun. Nous allons aussi voir comment résoudre des conflits.
Reprenez vos deux dossiers et assurez vous qu'ils soient synchronisés. Modifiez ensuite les fichiers README pour ajouter une ligne vide suivi de "depuis sandbox" dans le dossier sandbox et "depuis bacasable" dans le dossier bacasable, commitez les changements avec comme message "doc(README): greeting from sandox" et "doc(README): greeting from bacasable" respectivement. N'envoyez pas encore ces commits sur github.
Vous devriez avoir ceci dans le dossier sandbox
(avec les options pretty=oneline
et abbrev-commit
à git show
pour avoir un affichage plus courts) :
~/Ephec/sandbox$ git show --pretty=oneline --abbrev-commit
6d47ef0 (HEAD -> main) doc(README): greeting from sandbox
diff --git a/README.md b/README.md
index ece96c9..65266f2 100644
--- a/README.md
+++ b/README.md
@@ -2,3 +2,5 @@
Un bac-à-sable pour s'entrainer avec git et github
Bonjour tout le monde
+
+depuis sandbox
~/Ephec/sandbox$ git log --oneline
6d47ef0 (HEAD -> main) doc(README): greeting from sandbox
b76619e (origin/main, origin/HEAD) doc(README): better greeting
daaec07 doc(README): greet new users
0efccf0 Initial commit
Et ceci dans le dossier bacasable
:
~/Ephec/bacasable$ git show --pretty=oneline --abbrev-commit
45e6af4 (HEAD -> main) doc(README): greeting from bacasable
diff --git a/README.md b/README.md
index ece96c9..a7c5268 100644
--- a/README.md
+++ b/README.md
@@ -2,3 +2,5 @@
Un bac-à-sable pour s'entrainer avec git et github
Bonjour tout le monde
+
+depuis bacasable
~/Ephec/bacasable$ git log --oneline
45e6af4 (HEAD -> main) doc(README): greeting from bacasable
b76619e (origin/main, origin/HEAD) doc(README): better greeting
daaec07 doc(README): greet new users
0efccf0 Initial commit
Vous pouvez maintenant envoyer les changements depuis le dossier sandbox
avec git push
.
Déplacez-vous dans le dossier bacasable et tentez d'envoyer les changements, la commande va échouer avec un message d'erreur.
~/Ephec/bacasable$ git push
To https://github.com/julien00859/sandbox
! [rejected] main -> main (fetch first)
error: failed to push some refs to 'https://github.com/julien00859/sandbox'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Encore une fois, nous attirons votre attention sur le message d'erreur:
Updates were rejected because the remote contains work that you do not have locally. This is usually caused by another repository pushing to the same ref. You may want to first integrate the remote changes (e.g.,
git pull ...
) before pushing again.
Github a refusé notre push parce que notre historique ne contient pas tous les commits que Github connait. Il nous invite à récupérer ces changements (avec un git pull
) d'abord et de ressayer de git push
après.
Nous sommes dans une situation où les historiques ont divergé. Nous pouvons d'ailleurs le lire avec git status
.
~/Ephec/bacasable$ git status
On branch main
Your branch and 'origin/main' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
nothing to commit, working tree clean
Nous allons suivre la recommandation et pull les changements. Notez qu'il n'est pas nécessaire de fetch, git a profité du push pour échanger avec Github quant à l'état des branches.
~/Ephec/bacasable$ git pull
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
(Si vous n'avez pas le message précédent mais plutôt un message vous demandant de choisir une configuration parmi trois options, faites git config --global pull.rebase false
et recommencez)
Le message d'erreur nous apprend qu'il y a eu un conflit lorsque git a tenté de fusionner les changements. Il nous demande à nous humain beaucoup plus intelligent de lui bête programme de corriger ce conflit. Les instructions ne sont pas très claires dans ce message-ci mais elles le sont beaucoup plus dans le git status
~/Ephec/bacasable$ git status
On branch main
Your branch and 'origin/main' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
Le début est identique, le statut nous informe que notre branche a divergé de Github. Les deux paragraphes suivants sont nouveaux, on apprend que nous sommes dans en train de merge
et qu'il y a un conflit dans le fichier README.md
qui empêche git de continuer. Nous avons la possibilité soit de git merge --abort
pour tout annuler et revenir à l'état où nous étions avant de git pull
. Nous avons aussi la possibilité de résoudre le conflit et de continuer. Nous allons résoudre le conflit.
Ouvrez le fichier README.md
avec votre éditeur préféré, le fichier devrait contenir ceci :
# sandbox
Un bac-à-sable pour s'entrainer avec git et github
Bonjour tout le monde
<<<<<<< HEAD
depuis bacasable
=======
depuis sandbox
>>>>>>> 6d47ef0ec538547de5c00f36b9094b5e3a9b034d
On retrouve le contenu du README, le début est normal mais la fin est bizarre avec <<<<<<< HEAD
, =======
, >>>>>>> 6d47ef0ec...
et le texte des deux commits au milieu.
C'est un conflit.
Cette ligne de texte est différente entre les deux commits et git nous demande quoi faire. git est incapable de comprendre le texte, il est encore moins capable de savoir quoi faire. Il nous demande à nous autre, humain super intelligent, de bien vouloir résoudre ce conflit pour qu'il puisse continuer.
Un conflit arrive donc lorsque des lignes de code (ou dans le cas présent, des lignes de textes) sont modifiés dans deux commits séparés de manières indépendantes. On se rappelle que la ligne vide (celle entre "Bonjour tout le monde" et "depuis ...") avait aussi été ajouté de manière indépendante dans chacun des deux commits, git n'a pas bronché et a été capable de fusionner la ligne vide de chaque commit en une seule. Un conflit se produit uniquement lorsque les changements ne semblent pas compatibles.
Les balises <<<<<<< x
, =======
, >>>>>>> y
permettent de séparer et d'identifier où se situe le conflit et de déterminer de quel commit provient chaque ligne. Dans le cas présent, on doit lire que "depuis bacasable" provient du commit HEAD et est en conflit avec "depuis sandbox" qui vient du commit 6d47ef0
.
Résoudre le conflit consiste à réécrire le code (ici le texte) pour prendre en considération chaque commit. Il n'y a pas de solution universelle, il faut étudier chaque commit et comprendre comment combiner le code (ici le texte) ensemble pour que le programme reste juste. Vous êtes payés aussi pour ça. Ici après avoir utilisé beaucoup de jus de cerveau, nous décidons de résoudre le problème comme ceci :
# sandbox
Un bac-à-sable pour s'entrainer avec git et github
Bonjour tout le monde
depuis sandbox et bacasable
Vous devez maintenant signaler à git que vous avez résolu le problème en l'ajoutant (git add
). Un nouveau tour de git status
devrait vous dire que tous les conflits ont été résolus et que vous pouvez continuer avec un git commit
.
~/Ephec/bacasable$ git add README.md
~/Ephec/bacasable$ git status
On branch main
Your branch and 'origin/main' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
modified: README.md
Attention, faire un nouveau commit n'est nécessaire que lors d'un merge, si vous faites un rebase vous devrez alors git rebase --continue
après avoir marqué la résolution des conflits. Lisez le statut attentivement et agissez en conséquence.
~/Ephec/bacasable$ git commit
[main bd8f074] Merge branch 'main' of https://github.com/julien00859/sandbox
Une fois fait, vous pouvez constater le résultat sur l'historique avec l'option --graph
.
~/Ephec/bacasable$ git log --oneline --graph
* bd8f074 (HEAD -> main) Merge branch 'main' of https://github.com/julien00859/sandbox
|\
| * 6d47ef0 (origin/main, origin/HEAD) doc(README): greeting from sandbox
* | 45e6af4 doc(README): greeting from bacasable
|/
* b76619e doc(README): better greeting
* daaec07 doc(README): greet new users
* 0efccf0 Initial commit
On constate bien une divergence entre les commits 6d47ef0 doc(README): greeting from sandbox
et 45e6af4 doc(README): greeting from bacasable
, on constate aussi bien que cette divergence avec le commit bd8f074 Merge branch...
qui a fusionné les deux chemin.
Nous sommes maintenant dans une situation où tous les commits présents sur Github on été incorporés avec succès sur notre PC, il est alors possible d'envoyer notre travail sur Github... :
~/Ephec/bacasable$ git push
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Delta compression using up to 8 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 647 bytes | 647.00 KiB/s, done.
Total 6 (delta 4), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (4/4), completed with 2 local objects.
To https://github.com/julien00859/sandbox
6d47ef0..bd8f074 main -> main
... et de le récupérer dans l'autre dossier :
$ cd Ephec/sandbox
~/Ephec/sandbox$ git pull
Updating 6d47ef0..bd8f074
Fast-forward
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Cette méthode de travail, tout sur une seule branche, s'appelle dans la littérature centralized workflow et fonctionne bien pour les très petites équipes (maximum 3 personnes) ou bien pour initialiser un projet avant de bifurquer pour la feature-branch workflow.
L'avantage principale de cette méthodologie est de pouvoir rapidement collaborer sans trop se prendre la tête tout en profitant de Github pour facilement visualiser/partager son code.
Les désavantages sont par contre nombreux :
- Il n'est pas possible de travailler sur plusieurs choses à la fois sur un même PC. (ou bien vous devez cloner plusieurs fois)
- Il n'y a pas moyen de commencer à travailler sur une nouvelle fonctionnalité sur un PC et de la continuer sur un autre PC. (ou bien vous devez envoyer des commits incomplet)
- Il n'y a pas moyen de demander à ses collègues de review notre travail avant de l'envoyer sur Github. (ou bien vos collègues doivent venir voir votre code sur votre ordinateur)
- Il n'y a pas moyen d'empêcher des commits disfonctionnels (des commits qui contiennent des bugs révélés par les tests automatiques) d'être push sur Github. (à moins que tout le monde a configuré des pre-push hooks)
- Il y a prolifération de merge commits dans l'historique ce qui le rend illisible. (à moins que tout le monde fassent des rebase à la place de merge i.e.
git pull --rebase
)
Installation
Démarrage
Guides
vide
Explications
Références