Slide 1

Slide 1 text

Introduction à git Bob Maerten DSIL3 — Université de Lille - Mars 2015 https://gitlab.com/bobmaerten/presentation-git 1 / 235

Slide 2

Slide 2 text

Objectif 2 / 235

Slide 3

Slide 3 text

Défricher collectivement les arcanes de l'outil pour vous préparer à suivre correctement des tutoriels en ligne 3 / 235

Slide 4

Slide 4 text

Précisions importantes 4 / 235

Slide 5

Slide 5 text

Cette présentation : n'a pas pas la prétention d'être une formation à git ! 5 / 235

Slide 6

Slide 6 text

Cette présentation : n'a pas pas la prétention d'être une formation à git ! ne couvre qu'une infime partie des usages de l'outil 6 / 235

Slide 7

Slide 7 text

Cette présentation : n'a pas pas la prétention d'être une formation à git ! ne couvre qu'une infime partie des usages de l'outil est chiante à mourir car il y a beaucoup de concepts à appréhender 7 / 235

Slide 8

Slide 8 text

Cette présentation : n'a pas pas la prétention d'être une formation à git ! ne couvre qu'une infime partie des usages de l'outil est chiante à mourir car il y a beaucoup de concepts à appréhender risque de décevoir les gens qui veulent de l'opérationnel rapide 8 / 235

Slide 9

Slide 9 text

Cette présentation : n'a pas pas la prétention d'être une formation à git ! ne couvre qu'une infime partie des usages de l'outil est chiante à mourir car il y a beaucoup de concepts à appréhender risque de décevoir les gens qui veulent de l'opérationnel rapide http://git-scm.com/book/fr/v2 pour la référence 9 / 235

Slide 10

Slide 10 text

Git en une phrase 10 / 235

Slide 11

Slide 11 text

Git est un gestionnaire de contenu stockant des objets sous la forme d'un graphe acyclique orienté accessibles avec des références. 11 / 235

Slide 12

Slide 12 text

Git est un gestionnaire de contenu stockant des objets sous la forme d'un graphe acyclique orienté accessibles avec des références. 12 / 235

Slide 13

Slide 13 text

Git est un gestionnaire de contenu stockant des objets sous la forme d'un graphe acyclique orienté accessibles avec des références. 13 / 235

Slide 14

Slide 14 text

Git est un gestionnaire de contenu stockant des objets sous la forme d'un graphe acyclique orienté accessibles avec des références. 14 / 235

Slide 15

Slide 15 text

2 aspects de Git le frontend (commandes porcelain) le backend (commandes plumbing) 15 / 235

Slide 16

Slide 16 text

La plupart des formations et tutoriaux se concentrent quasi-exclusivement sur le frontend 16 / 235

Slide 17

Slide 17 text

Or, plus vous comprenez comprenez le backend, mieux vous maîtrisez maîtrisez le frontend 17 / 235

Slide 18

Slide 18 text

Alors explorons le fonctionnement interne de git 18 / 235

Slide 19

Slide 19 text

Concept 1 Git est un gestionnaire de contenu 19 / 235

Slide 20

Slide 20 text

Git gère des snapshots snapshots Contrairement à SVN qui fonctionne en mode delta 20 / 235

Slide 21

Slide 21 text

21 / 235

Slide 22

Slide 22 text

Révélation : git est une BDD clé-valeur 22 / 235

Slide 23

Slide 23 text

Révélation : git est une BDD clé-valeur Put -> hash-object $ echo "titi toto tutu" | git hash-object -w --stdin 1b7c47f647a48cf4aa80def219d62110aaff6364 23 / 235

Slide 24

Slide 24 text

Révélation : git est une BDD clé-valeur Put -> hash-object $ echo "titi toto tutu" | git hash-object -w --stdin 1b7c47f647a48cf4aa80def219d62110aaff6364 Get -> cat-file $ git cat-file -p 1b7c47f647a48cf4aa80def219d62110aaff6364 titi toto tutu 24 / 235

Slide 25

Slide 25 text

Identification par clé SHA-1 Implémentation simple et efficace Unicité 25 / 235

Slide 26

Slide 26 text

Identification par clé SHA-1 Implémentation simple et efficace Unicité git permet de n'utiliser que la partie suffisante des SHA-1 $ git cat-file -p 1b7c47f647a48cf4aa80def219d62110aaff6364 titi toto tutu $ git cat-file -p 1b7c47f titi toto tutu $ git cat-file -p 1b7c titi toto tutu 26 / 235

Slide 27

Slide 27 text

Tout est SHA-1 $ find .git/objects -type f .git/objects/ab/39aecb298318035feaba12c651761dc88488f7 .git/objects/4d/13a74e9497e944228eb0c88d6aad864125fa83 .git/objects/e9/b3c7ecb8421da993be0b803ecb015c44028612 .git/objects/68/ba2f1b68200091b8d85de12d85dbedf48a3755 .git/objects/90/cdfffe540c8440456c354061ad2aabc9c0985f .git/objects/8a/61779d2710a37d20e8881ebba5d471a760b355 .git/objects/8a/a2047614f35dfc0c59f374c8e81696fc18275e .git/objects/cc/4f2165af266e947adee4be663e193bcf247091 .git/objects/eb/33c80bd2dd7f7ba938f25fa65f6455d70efed6 .git/objects/cf/5aa6a792cd0d01b62254fa28ba2dcbe59e9d03 .git/objects/86/575ff73c1746f32cce43303783b2d68c13c72d .git/objects/2c/7afa29e39fd32fbb1f33563ee70f79c1c191e7 [...] .git/objects/a1/23a9fa912276c7aa77700b6ef7dfc5022707b4 .git/objects/d3/1e80fa8b3c6522fd2d370c10875e0593cd8283 .git/objects/4c/a8f004274ca5494bd1492320ddfbc8caa45466 .git/objects/1e/418d7b23b94c8108ae627c7f5bb3fdf96bf013 27 / 235

Slide 28

Slide 28 text

Tout est SHA-1 Types d'objets Blobs 100644 blob 4d13a74e9497e944228eb0c88d6aad864125fa83 LICENSE 100644 blob 772bb233156315bea0ee958d94beb143220a3e84 README.md 040000 tree 4ca8f004274ca5494bd1492320ddfbc8caa45466 font 100644 blob 911a2be129829d31b7b08303ec8db2690793ed0f index.html 100644 blob 0a3b5622619f7b55bd43fb743cda90a379cdfb92 remark.min.js 100644 blob 7d5caef4b148a868b1f598e5fb4755a0b0710368 theme.css 28 / 235

Slide 29

Slide 29 text

Tout est SHA-1 Types d'objets Trees 100644 blob 4d13a74e9497e944228eb0c88d6aad864125fa83 LICENSE 100644 blob 772bb233156315bea0ee958d94beb143220a3e84 README.md *040000 tree 4ca8f004274ca5494bd1492320ddfbc8caa45466 font 100644 blob 911a2be129829d31b7b08303ec8db2690793ed0f index.html 100644 blob 0a3b5622619f7b55bd43fb743cda90a379cdfb92 remark.min.js 100644 blob 7d5caef4b148a868b1f598e5fb4755a0b0710368 theme.css *$ git cat-file -p 4ca8f0 100644 blob 90cdfffe540c8440456c354061ad2aabc9c0985f DroidSerif.ttf 100644 blob a123a9fa912276c7aa77700b6ef7dfc5022707b4 YanoneKaffeesatz-Regular.otf $ ls -1 font DroidSerif.ttf YanoneKaffeesatz-Regular.otf 29 / 235

Slide 30

Slide 30 text

Tout est SHA-1 Types d'objets Commits $ git log --oneline d31e80f Import travail initial 68ba2f1 Initial empty commit 30 / 235

Slide 31

Slide 31 text

Tout est SHA-1 Types d'objets Commits $ git log --oneline *d31e80f Import travail initial 68ba2f1 Initial empty commit *$ git cat-file -p d31e80f tree 8a61779d2710a37d20e8881ebba5d471a760b355 parent 68ba2f1b68200091b8d85de12d85dbedf48a3755 author Bob Maerten 1424796124 +0100 committer Bob Maerten 1424796900 +0100 Import travail initial 31 / 235

Slide 32

Slide 32 text

32 / 235

Slide 33

Slide 33 text

33 / 235

Slide 34

Slide 34 text

Résumé du concept 1 Orienté contenu et non fichier Base de données clé (sha1) / valeur (contenu) 3 objets : commit, tree, blob 34 / 235

Slide 35

Slide 35 text

Aparté Découverte des quelques commandes de base (porcelaine) 35 / 235

Slide 36

Slide 36 text

git-init $ git init /tmp/mon-premier-depo-git Dépôt Git vide initialisé dans /tmp/mon-premier-depo-git/.git/ 36 / 235

Slide 37

Slide 37 text

git-init $ git init /tmp/mon-premier-depo-git Dépôt Git vide initialisé dans /tmp/mon-premier-depo-git/.git/ $ cd $! $ ls -l .git/ total 32 drwxrwxr-x 2 rmaerten rmaerten 4096 févr. 25 13:37 branches -rw-rw-r-- 1 rmaerten rmaerten 92 févr. 25 13:37 config -rw-rw-r-- 1 rmaerten rmaerten 73 févr. 25 13:37 description -rw-rw-r-- 1 rmaerten rmaerten 23 févr. 25 13:37 HEAD drwxrwxr-x 2 rmaerten rmaerten 4096 févr. 25 13:37 hooks drwxrwxr-x 2 rmaerten rmaerten 4096 févr. 25 13:37 info drwxrwxr-x 4 rmaerten rmaerten 4096 févr. 25 13:37 objects drwxrwxr-x 4 rmaerten rmaerten 4096 févr. 25 13:37 refs 37 / 235

Slide 38

Slide 38 text

git-status $ git status Sur la branche master Validation initiale rien à valider (créez/copiez des fichiers et utilisez "git add" pour les suivre) 38 / 235

Slide 39

Slide 39 text

Ajouter du contenu (faire un commit) 39 / 235

Slide 40

Slide 40 text

Ajouter du contenu (faire un commit) 2 étapes : 40 / 235

Slide 41

Slide 41 text

Ajouter du contenu (faire un commit) 2 étapes : Sélectionner le contenu (index ou staging area) 41 / 235

Slide 42

Slide 42 text

Ajouter du contenu (faire un commit) 2 étapes : Sélectionner le contenu (index ou staging area) Enregistrer un snapshot (commit) 42 / 235

Slide 43

Slide 43 text

Ajouter à l'index (staging) git-add 43 / 235

Slide 44

Slide 44 text

Ajouter à l'index (staging) git-add $ echo 'toto' > file.txt 44 / 235

Slide 45

Slide 45 text

Ajouter à l'index (staging) git-add $ echo 'toto' > file.txt $ git status -s ?? file.txt 45 / 235

Slide 46

Slide 46 text

Ajouter à l'index (staging) git-add $ echo 'toto' > file.txt $ git status -s ?? file.txt $ git add file.txt $ git status -s A file.txt 46 / 235

Slide 47

Slide 47 text

Ajouter à l'index (staging) git-add $ echo 'toto' > file.txt $ git status -s ?? file.txt $ git add file.txt $ git status -s A file.txt $ find .git/objects -type f .git/objects/fb/cf12d50552354fc878706bacea89fbb3f9f999 .git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 $ git cat-file -p fbcf12 toto 47 / 235

Slide 48

Slide 48 text

Modifier l'index (staging) git-reset $ git reset $ git status -s ?? file.txt $ rm -f file.txt $ git status -s 48 / 235

Slide 49

Slide 49 text

Modifier l'index (staging) git-reset $ git reset $ git status -s ?? file.txt $ rm -f file.txt $ git status -s $ find .git/objects -type f .git/objects/fb/cf12d50552354fc878706bacea89fbb3f9f999 .git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 $ git cat-file -p fbcf12 > file.txt $ cat file.txt toto $ git status -s ?? file.txt Ajout à l'index -> enregistré dans la base git. 49 / 235

Slide 50

Slide 50 text

Amender l'index (staging) changement d'avis $ echo 'plop' > otherfile $ git add otherfile $ git status -s A otherfile ?? file.txt 50 / 235

Slide 51

Slide 51 text

Amender l'index (staging) changement d'avis $ echo 'plop' > otherfile $ git add otherfile $ git status -s A otherfile ?? file.txt $ sed -i 's/plop/coucou/' otherfile $ git status -s AM otherfile ?? file.txt $ git add otherfile $ git status -s A otherfile ?? file.txt 51 / 235

Slide 52

Slide 52 text

Amender l'index (staging) changement d'avis $ find .git/objects -type f .git/objects/fb/cf12d50552354fc878706bacea89fbb3f9f999 .git/objects/28/d0af969b32e69a389087d7a267a2ecc05f1350 .git/objects/e8/b7c915cf81135b25e2662a72356339ae5cb774 .git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee49 52 / 235

Slide 53

Slide 53 text

Amender l'index (staging) changement d'avis $ find .git/objects -type f .git/objects/fb/cf12d50552354fc878706bacea89fbb3f9f999 .git/objects/28/d0af969b32e69a389087d7a267a2ecc05f1350 *.git/objects/e8/b7c915cf81135b25e2662a72356339ae5cb774 .git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee49 $ git cat-file -p e8b7 *plop 53 / 235

Slide 54

Slide 54 text

Amender l'index (staging) changement d'avis $ find .git/objects -type f .git/objects/fb/cf12d50552354fc878706bacea89fbb3f9f999 *.git/objects/28/d0af969b32e69a389087d7a267a2ecc05f1350 .git/objects/e8/b7c915cf81135b25e2662a72356339ae5cb774 .git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee49 $ git cat-file -p e8b7 plop $ git cat-file -p 28d0 *coucou 54 / 235

Slide 55

Slide 55 text

Amender l'index (staging) $ git status Sur la branche master Validation initiale Modifications qui seront validées : (utilisez "git rm --cached <fichier>..." pour désindexer) nouveau fichier : otherfile Fichiers non suivis: (utilisez "git add <fichier>..." pour inclure dans ce qui sera validé) file.txt Ajout à l'index -> enregistré dans la base git. 55 / 235

Slide 56

Slide 56 text

Enregistrer le snapshot (commit) git-commit 56 / 235

Slide 57

Slide 57 text

Enregistrer le snapshot (commit) git-commit $ git commit -m "Ajout de contenu" [master (commit racine) f664ea4] Ajout de contenu 1 file changed, 1 insertion(+) create mode 100644 otherfile 57 / 235

Slide 58

Slide 58 text

Enregistrer le snapshot (commit) git-commit $ git commit -m "Ajout de contenu" [master (commit racine) f664ea4] Ajout de contenu 1 file changed, 1 insertion(+) create mode 100644 otherfile $ git status -s ?? file.txt 58 / 235

Slide 59

Slide 59 text

Enregistrer le snapshot (commit) git-commit $ git commit -m "Ajout de contenu" *[master (commit racine) f664ea4] Ajout de contenu 1 file changed, 1 insertion(+) create mode 100644 otherfile $ git status -s ?? file.txt $ find .git/objects -type f .git/objects/fb/cf12d50552354fc878706bacea89fbb3f9f999 *.git/objects/f6/64ea455b2551122b8f703010d04d71ad4feac2 .git/objects/28/d0af969b32e69a389087d7a267a2ecc05f1350 .git/objects/e8/b7c915cf81135b25e2662a72356339ae5cb774 .git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 .git/objects/ac/9486aa02cdd63b67d5b0c0ab863f0b77f 59 / 235

Slide 60

Slide 60 text

État après le commit $ find .git/objects -type f .git/objects/fb/cf12d50552354fc878706bacea89fbb3f9f999 *.git/objects/f6/64ea455b2551122b8f703010d04d71ad4feac2 .git/objects/28/d0af969b32e69a389087d7a267a2ecc05f1350 .git/objects/e8/b7c915cf81135b25e2662a72356339ae5cb774 .git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 .git/objects/ac/9486aa02cdd63b67d5b0c0ab863f0b77f *$ git cat-file -p f664ea4 tree ac9486aa02cdd63b67d5b0c0ab863f0b77f5a2af author Bob Maerten 1425551185 +0100 committer Bob Maerten 1425551185 +0100 Ajout de contenu 60 / 235

Slide 61

Slide 61 text

État après le commit $ find .git/objects -type f .git/objects/fb/cf12d50552354fc878706bacea89fbb3f9f999 .git/objects/f6/64ea455b2551122b8f703010d04d71ad4feac2 .git/objects/28/d0af969b32e69a389087d7a267a2ecc05f1350 .git/objects/e8/b7c915cf81135b25e2662a72356339ae5cb774 .git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 *.git/objects/ac/9486aa02cdd63b67d5b0c0ab863f0b77f $ git cat-file -p f664ea4 *tree ac9486aa02cdd63b67d5b0c0ab863f0b77f5a2af author Bob Maerten 1425551185 +0100 committer Bob Maerten 1425551185 +0100 *$ git cat-file -p ac948 100644 blob 28d0af969b32e69a389087d7a267a2ecc05f1350 otherfile 61 / 235

Slide 62

Slide 62 text

État après le commit $ find .git/objects -type f .git/objects/fb/cf12d50552354fc878706bacea89fbb3f9f999 .git/objects/f6/64ea455b2551122b8f703010d04d71ad4feac2 *.git/objects/28/d0af969b32e69a389087d7a267a2ecc05f1350 .git/objects/e8/b7c915cf81135b25e2662a72356339ae5cb774 .git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 .git/objects/ac/9486aa02cdd63b67d5b0c0ab863f0b77f $ git cat-file -p f664ea4 tree ac9486aa02cdd63b67d5b0c0ab863f0b77f5a2af author Bob Maerten 1425551185 +0100 committer Bob Maerten 1425551185 +0100 $ git cat-file -p ac948 100644 blob 28d0af969b32e69a389087d7a267a2ecc05f1350 otherfile *$ git cat-file -p 28d0a coucou 62 / 235

Slide 63

Slide 63 text

État après le commit $ find .git/objects -type f .git/objects/fb/cf12d50552354fc878706bacea89fbb3f9f999 .git/objects/f6/64ea455b2551122b8f703010d04d71ad4feac2 .git/objects/28/d0af969b32e69a389087d7a267a2ecc05f1350 *.git/objects/e8/b7c915cf81135b25e2662a72356339ae5cb774 .git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 .git/objects/ac/9486aa02cdd63b67d5b0c0ab863f0b77f *$ git cat-file -p e8b7 coucou 63 / 235

Slide 64

Slide 64 text

État après le commit $ find .git/objects -type f .git/objects/fb/cf12d50552354fc878706bacea89fbb3f9f999 .git/objects/f6/64ea455b2551122b8f703010d04d71ad4feac2 .git/objects/28/d0af969b32e69a389087d7a267a2ecc05f1350 *.git/objects/e8/b7c915cf81135b25e2662a72356339ae5cb774 --> non utilisé ! .git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 .git/objects/ac/9486aa02cdd63b67d5b0c0ab863f0b77f *$ git cat-file -p e8b7 coucou On ne perd jamais rien dans git ! (enfin, presque...) allez dire ça au garbage collector... 64 / 235

Slide 65

Slide 65 text

Historique des commits $ find .git/objects -type f .git/objects/fb/cf12d50552354fc878706bacea89fbb3f9f999 *.git/objects/f6/64ea455b2551122b8f703010d04d71ad4feac2 .git/objects/28/d0af969b32e69a389087d7a267a2ecc05f1350 .git/objects/e8/b7c915cf81135b25e2662a72356339ae5cb774 .git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 .git/objects/ac/9486aa02cdd63b67d5b0c0ab863f0b77f git-log $ git log *commit f664ea4 Author: Bob Maerten Date: Wed Feb 25 15:26:18 2015 +0100 Ajout de contenu 65 / 235

Slide 66

Slide 66 text

Historique des commits git-log $ git log commit 6f63737 Author: Bob Maerten Date: Tue Feb 24 08:26:16 2015 +0100 Removed SSH host key generation on image Prevents using hub version of SSH keys to intercept communication with the docker container. Thx @gabeos on this one! Fixes #6 commit c5cf179 Author: Bob Maerten Date: Tue Feb 24 08:25:48 2015 +0100 Bumped to latest phusion/baseimage commit 379ff91 66 / 235

Slide 67

Slide 67 text

Historique des commits Avec quelques options c'est mieux ! * $ git log --oneline --graph | head -18 * 6f63737 Removed SSH host key generation on image * c5cf179 Bumped to latest phusion/baseimage * 379ff91 Bumped to 1.9 release * 4459939 Updated to 1.8.1 * 719cb17 Merge pull request #5 from nicosomb/patch-1 |\ | * 1658e08 upgrade to wallabag 1.8.0 |/ * 50d80ef Upgraded to latest phusion/baseimage * b10651d Bumped version 1.7.2 * 252be69 Set permission on unix socket for php-fpm * 36b0374 Upped wallabag version from release 1.7.1 * 903b94d Use of --format option from docker binary * dcf98ea Merge pull request #2 from amtrack/bump-version |\ | * 56acfc8 make wallabag version configurable and bump to 1.7.0 |/ 67 / 235

Slide 68

Slide 68 text

Historique des commits Avec d'autres options c'est encore mieux ! 68 / 235

Slide 69

Slide 69 text

Historique des commits (outils spécialisés) tig (terminal) 69 / 235

Slide 70

Slide 70 text

Historique des commits (outils spécialisés) SourceTree (windows et autres) : http://www.sourcetreeapp.com/ 70 / 235

Slide 71

Slide 71 text

Historique des commits (outils spécialisés) webui (navigateur) : https://github.com/alberthier/git-webui 71 / 235

Slide 72

Slide 72 text

Résumé des commandes 72 / 235

Slide 73

Slide 73 text

Résumé des commandes add add : ajouter du contenu à l'index reset reset : vider le contenu de l'index status status : connaitre l'état (working tree / index) commit commit : enregistrer l'index log log : consulter l'historique des commits 73 / 235

Slide 74

Slide 74 text

Questions/Réponses 74 / 235

Slide 75

Slide 75 text

Git est un gestionnaire de contenu stockant des objets sous la forme d'un graphe acyclique orienté stockant des objets sous la forme d'un graphe acyclique orienté accessibles avec des références 75 / 235

Slide 76

Slide 76 text

Concept 2 La relation entre les commits est un graphe acyclique orienté (DAG) 76 / 235

Slide 77

Slide 77 text

Graphe acyclique orienté = Graphe sans boucle boucle 77 / 235

Slide 78

Slide 78 text

Un noeud peut avoir 0, 1, 2 ou N parents 78 / 235

Slide 79

Slide 79 text

Représentation courante Parent ← Enfant 79 / 235

Slide 80

Slide 80 text

Ajouter du contenu dans git = Modifier le graphe 80 / 235

Slide 81

Slide 81 text

Modifier le graphe 81 / 235

Slide 82

Slide 82 text

Modifier le graphe Se placer sur un noeud X 82 / 235

Slide 83

Slide 83 text

Modifier le graphe Se placer sur un noeud X Récupérer le contenu du noeud Y 83 / 235

Slide 84

Slide 84 text

Modifier le graphe Se placer sur un noeud X Récupérer le contenu du noeud Y Appliquer une opération (X & Y) 84 / 235

Slide 85

Slide 85 text

Modifier le graphe Se placer sur un noeud X Récupérer le contenu du noeud Y Appliquer une opération (X & Y) Exemple Se placer sur le noeud 4 Récupérer le contenu du noeud 5 Appliquer une opération : 4 & 5 = 6 (ici merge) 85 / 235

Slide 86

Slide 86 text

Les différentes opérations - commit - merge - rebase - squash - cherrypick - revert 86 / 235

Slide 87

Slide 87 text

Opérations par l'exemple 87 / 235

Slide 88

Slide 88 text

Continuer le graphe Commit 88 / 235

Slide 89

Slide 89 text

Continuer le graphe Commit Le contenu de l'index représente le noeud récupéré dans l'opération 89 / 235

Slide 90

Slide 90 text

Continuer le graphe Commit Le contenu de l'index représente le noeud récupéré dans l'opération 90 / 235

Slide 91

Slide 91 text

Modéliser la fusion Merge 91 / 235

Slide 92

Slide 92 text

Simplifier le graphe Rebase 92 / 235

Slide 93

Slide 93 text

Nettoyer le graphe Squash 93 / 235

Slide 94

Slide 94 text

Copie sans historique Cherrypick 94 / 235

Slide 95

Slide 95 text

Cherrypick 95 / 235

Slide 96

Slide 96 text

Cherrypick 96 / 235

Slide 97

Slide 97 text

Cherrypick 97 / 235

Slide 98

Slide 98 text

Cherrypick 98 / 235

Slide 99

Slide 99 text

Annuler un commit revert 99 / 235

Slide 100

Slide 100 text

Annuler un commit revert Les contenus des des working dirs de C0 et du dernier commit sont identiques 100 / 235

Slide 101

Slide 101 text

Annuler un commit revert Les contenus des des working dirs de C0 et du dernier commit sont identiques Attention, ne pas confondre git revert git revert et... 101 / 235

Slide 102

Slide 102 text

Annuler un commit revert Les contenus des des working dirs de C0 et du dernier commit sont identiques Attention, ne pas confondre git revert git revert et... Ok, je sors... 102 / 235

Slide 103

Slide 103 text

À retenir La vision chronologique dans git n'a guère de sens. Même si les dates sont stockées dans les commits, la seule vision correcte est topologique. 103 / 235

Slide 104

Slide 104 text

Résumé du concept 2 Les commits sont reliés dans un graphe Manipulable à loisir puisque complètement local Les objets sont immutables 104 / 235

Slide 105

Slide 105 text

Questions/Réponses 105 / 235

Slide 106

Slide 106 text

Git est un gestionnaire de contenu stockant des objets sous la forme d'un graphe acyclique orienté accessibles avec des références accessibles avec des références 106 / 235

Slide 107

Slide 107 text

Concept 3 Le contenu est accessible sous forme de référence 107 / 235

Slide 108

Slide 108 text

Pouvez vous mémoriser un SHA1 ? 108 / 235

Slide 109

Slide 109 text

e83c5163316f89bfbde7d9ab23ca2e25604af290 109 / 235

Slide 110

Slide 110 text

e83c516 110 / 235

Slide 111

Slide 111 text

Quel est le SHA1 ? :) 111 / 235

Slide 112

Slide 112 text

Bon ok, c'était facile car e83c5163316f89bfbde7d9ab23ca2e25604af290 est un SHA-1 "mythique" 112 / 235

Slide 113

Slide 113 text

Bon ok, c'était facile car e83c5163316f89bfbde7d9ab23ca2e25604af290 est un SHA-1 "mythique" c'est celui du 1er commit de git ! $ cd /usr/local/src/git $ git show -s $(git log --oneline | tail -1 | awk '{ print $1 }') commit e83c516 Author: Linus Torvalds Date: Thu Apr 7 15:13:13 2005 -0700 Initial revision of "git", the information manager from hell 113 / 235

Slide 114

Slide 114 text

Revenons aux références 114 / 235

Slide 115

Slide 115 text

Revenons aux références Comparable au DNS 115 / 235

Slide 116

Slide 116 text

Revenons aux références Comparable au DNS $ host -t aaaa google.com google.com has IPv6 address 2a00:1450:4007:805::1006 116 / 235

Slide 117

Slide 117 text

Revenons aux références Comparable au DNS $ host -t aaaa google.com google.com has IPv6 address 2a00:1450:4007:805::1006 Une référence pointe sur un commit $ cat .git/refs/master a9b573777c6847cf5144e598aef899b2360c5ed6 117 / 235

Slide 118

Slide 118 text

2 types de références 118 / 235

Slide 119

Slide 119 text

2 types de références déplacées par Git 119 / 235

Slide 120

Slide 120 text

2 types de références déplacées par Git déplacées par l'utilisateur 120 / 235

Slide 121

Slide 121 text

Exemple de déplacement automatique avant un commit 121 / 235

Slide 122

Slide 122 text

Exemple de déplacement automatique après un commit 122 / 235

Slide 123

Slide 123 text

Exemple de déplacement automatique la référence master master est déplacée par git à chaque commit 123 / 235

Slide 124

Slide 124 text

Exemple de déplacement automatique la référence master master est déplacée par git à chaque commit sans cela, il faudrait à chaque fois se souvenir du SHA-1 du dernier commit 124 / 235

Slide 125

Slide 125 text

Une branche est une référence (déplacée par Git) 125 / 235

Slide 126

Slide 126 text

git-branch La référence est déplacée par git sur les commits enfants 126 / 235

Slide 127

Slide 127 text

git-branch La référence est déplacée par git sur les commits enfants Par extention on parle de branche pour l'ensemble des commits parents 127 / 235

Slide 128

Slide 128 text

git-branch La référence est déplacée par git sur les commits enfants Par extention on parle de branche pour l'ensemble des commits parents Ne "coûte" absolument rien en CPU et en stockage $ git branch newbranch 0,00s user 0,01s system 89% cpu 0,007 total $ ls -l .git/refs/heads/newbranch -rw-rw-r-- 1 rmaerten rmaerten 41 mars 4 13:37 .git/refs/heads/newbranch 128 / 235

Slide 129

Slide 129 text

Alors, faites des branches. Les branches, c'est le bien ! 129 / 235

Slide 130

Slide 130 text

un tag est une référence (déplacée par l'utilisateur) 130 / 235

Slide 131

Slide 131 text

git-tag $ git tag v0.0.1 e83c516 $ cat .git/refs/tags/v0.0.1 e83c5163316f89bfbde7d9ab23ca2e25604af290 131 / 235

Slide 132

Slide 132 text

git-tag $ git tag v0.0.1 e83c516 $ cat .git/refs/tags/v0.0.1 e83c5163316f89bfbde7d9ab23ca2e25604af290 Les tags sont souvent fixes 132 / 235

Slide 133

Slide 133 text

Git gère les références avec des espaces de nom espaces de nom (namespaces) 133 / 235

Slide 134

Slide 134 text

Exemples bob/experiment feature/using-cache-before-fetch-db fix/auth/ldap-server 134 / 235

Slide 135

Slide 135 text

Conventions 135 / 235

Slide 136

Slide 136 text

Conventions master master = branche principale (init) 136 / 235

Slide 137

Slide 137 text

Conventions master master = branche principale (init) origin origin = dépot distant (clone) 137 / 235

Slide 138

Slide 138 text

Résumé du concept 3 Une référence est un pointeur (comme un post-it) Utilisable avec des espaces de nom Utile pour l'utilisateur (frontend) 138 / 235

Slide 139

Slide 139 text

L'ensemble peut se voir en couche Contenu (objet blob) Système de fichier (objet tree) Historisé (objet commit) Facilement mémorisable (référence) 139 / 235

Slide 140

Slide 140 text

Questions/Réponses 140 / 235

Slide 141

Slide 141 text

Collaboration 141 / 235

Slide 142

Slide 142 text

Git est une base d'objets synchronisable synchronisable 142 / 235

Slide 143

Slide 143 text

2 manières de collaborer 143 / 235

Slide 144

Slide 144 text

La méthode « chacun chez soi » (mode par défaut) 144 / 235

Slide 145

Slide 145 text

Je peux récupérer du code quand je veux 145 / 235

Slide 146

Slide 146 text

Je peux récupérer du code quand je veux Je dois annoncer que des modifications sont disponibles 146 / 235

Slide 147

Slide 147 text

Je peux récupérer du code quand je veux Je dois annoncer que des modifications sont disponibles Votre dépôt est personnel personnel 147 / 235

Slide 148

Slide 148 text

Je peux récupérer du code quand je veux Je dois annoncer que des modifications sont disponibles Votre dépôt est personnel personnel on pull depuis les autres on ne ne push pas pas vers les autres 148 / 235

Slide 149

Slide 149 text

La méthode « 1 pour tous, tous pour 1 » 149 / 235

Slide 150

Slide 150 text

Dépôt partagé (bare) $ git init --bare /tmp/sharedrepo.git 150 / 235

Slide 151

Slide 151 text

Dépôt partagé (bare) $ git init --bare /tmp/sharedrepo.git $ git clone /tmp/sharedrepo.git 151 / 235

Slide 152

Slide 152 text

Dépôt partagé (bare) $ git init --bare /tmp/sharedrepo.git $ git clone /tmp/sharedrepo.git On s'accorde collectivement sur le fait que ce dépôt devient un référentiel 152 / 235

Slide 153

Slide 153 text

Dépôt partagé (bare) $ git init --bare /tmp/sharedrepo.git $ git clone /tmp/sharedrepo.git On s'accorde collectivement sur le fait que ce dépôt devient un référentiel les usagers pushent et pullent sur le référentiel 153 / 235

Slide 154

Slide 154 text

Dépôt partagé (bare) $ git init --bare /tmp/sharedrepo.git $ git clone /tmp/sharedrepo.git On s'accorde collectivement sur le fait que ce dépôt devient un référentiel les usagers pushent et pullent sur le référentiel nécessité de synchroniser régulièrement 154 / 235

Slide 155

Slide 155 text

Dépôt partagé (bare) $ git init --bare /tmp/sharedrepo.git $ git clone /tmp/sharedrepo.git On s'accorde collectivement sur le fait que ce dépôt devient un référentiel les usagers pushent et pullent sur le référentiel nécessité de synchroniser régulièrement avec un prompt aware c'est mieux 155 / 235

Slide 156

Slide 156 text

Différence entre dépôt "classique" et "bare" 156 / 235

Slide 157

Slide 157 text

Différence entre dépôt "classique" et "bare" bare : pas de working dir 157 / 235

Slide 158

Slide 158 text

Différence entre dépôt "classique" et "bare" bare : pas de working dir bare : .git à la fin (convention) 158 / 235

Slide 159

Slide 159 text

Différence entre dépôt "classique" et "bare" : bare : pas de working dir bare : .git à la fin (convention) Gitlab est un dépôt bare (avec des ACLs) 159 / 235

Slide 160

Slide 160 text

Différence entre dépôt "classique" et "bare" : bare : pas de working dir bare : .git à la fin (convention) Gitlab est un dépôt bare (avec des ACLs) $ git clone [email protected]:rmaerten/presentation-git.git Clonage dans 'presentation-git'... remote: Counting objects: 107, done. remote: Compressing objects: 100% (105/105), done. remote: Total 107 (delta 26), reused 0 (delta 0) Réception d'objets: 100% (107/107), 6.72 MiB | 540.00 KiB/s, fait. 160 / 235

Slide 161

Slide 161 text

La notion de "remote" 161 / 235

Slide 162

Slide 162 text

162 / 235

Slide 163

Slide 163 text

163 / 235

Slide 164

Slide 164 text

164 / 235

Slide 165

Slide 165 text

165 / 235

Slide 166

Slide 166 text

166 / 235

Slide 167

Slide 167 text

167 / 235

Slide 168

Slide 168 text

168 / 235

Slide 169

Slide 169 text

Révélation Les remotes sont aussi aussi des branches 169 / 235

Slide 170

Slide 170 text

Révélation Les remotes sont aussi aussi des branches Donc des références (si vous avez suivi) 170 / 235

Slide 171

Slide 171 text

Révélation Les remotes sont aussi aussi des branches Donc des références (si vous avez suivi) Manipulable à loisir en local une fois synchronisées 171 / 235

Slide 172

Slide 172 text

172 / 235

Slide 173

Slide 173 text

173 / 235

Slide 174

Slide 174 text

174 / 235

Slide 175

Slide 175 text

175 / 235

Slide 176

Slide 176 text

176 / 235

Slide 177

Slide 177 text

177 / 235

Slide 178

Slide 178 text

178 / 235

Slide 179

Slide 179 text

Configurer une branche "distante" git-remote 179 / 235

Slide 180

Slide 180 text

Configurer une branche "distante" git-remote $ git remote add gespinfo3 [email protected]:ent/gespinfo3.git 180 / 235

Slide 181

Slide 181 text

Configurer une branche "distante" git-remote $ git remote add gespinfo3 [email protected]:ent/gespinfo3.git $ tail -3 .git/config [remote "gespinfo3"] url = [email protected]:ent/gespinfo3.git fetch = +refs/heads/*:refs/remotes/gespinfo3/* 181 / 235

Slide 182

Slide 182 text

Configurer une branche "distante" git-remote $ git remote add gespinfo3 [email protected]:ent/gespinfo3.git $ tail -3 .git/config [remote "gespinfo3"] url = [email protected]:ent/gespinfo3.git fetch = +refs/heads/*:refs/remotes/gespinfo3/* $ git clone [email protected]:rmaerten/presentation-git.git $ cd presentation-git $ git remote -v origin [email protected]:rmaerten/presentation-git.git (fetch) origin [email protected]:rmaerten/presentation-git.git (push) 182 / 235

Slide 183

Slide 183 text

Tout ce qui provient de origin est préfixé avec un espace de nom origin. master -> origin/master test -> origin/test 183 / 235

Slide 184

Slide 184 text

La branche distante master est liée avec ma ma branche master. master <-> origin/master 184 / 235

Slide 185

Slide 185 text

Récupérér le contenu de la base .git distante git-fetch 185 / 235

Slide 186

Slide 186 text

Récupérér le contenu de la base .git distante git-fetch $ git fetch Récupération de origin remote: Counting objects: 42, done. remote: Compressing objects: 100% (14/14), done. remote: Total 42 (delta 15), reused 6 (delta 6), pack-reused 22 Unpacking objects: 100% (42/42), done. Depuis gitlab.univ-lille3.fr:ent/gespinfo3.git 677acc3..e55c715 master -> origin/master 186 / 235

Slide 187

Slide 187 text

Pousser du contenu git-push 187 / 235

Slide 188

Slide 188 text

Pousser du contenu git-push Envoie le contenu de la base .git $ git push upstream master Counting objects: 4, done. Writing objects: 100% (3/3), 278 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To [email protected]:ent/gespinfo3.git e3252af..141af1c master -> master 188 / 235

Slide 189

Slide 189 text

Pousser du contenu git-push Envoie le contenu de la base .git $ git push upstream master Counting objects: 4, done. Writing objects: 100% (3/3), 278 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To [email protected]:ent/gespinfo3.git e3252af..141af1c master -> master ⾠ Met à jour aussi les références distantes (d'ou l'intérêt des ACLs) 189 / 235

Slide 190

Slide 190 text

Attention avec la commande pull pull 190 / 235

Slide 191

Slide 191 text

Attention avec la commande pull pull pull = fetch + merge 191 / 235

Slide 192

Slide 192 text

Attention avec la commande pull pull pull = fetch + merge Pas toujours l'opération que l'on souhaite effectuer sur le graphe ! 192 / 235

Slide 193

Slide 193 text

Attention à historique 193 / 235

Slide 194

Slide 194 text

Attention à historique Tout ce qui a été pushé ne doit plus être modifié localement 194 / 235

Slide 195

Slide 195 text

Attention à historique Tout ce qui a été pushé ne doit plus être modifié localement exception permise pour les branches identifiées comme purement personnelles personnelles (git push --force) 195 / 235

Slide 196

Slide 196 text

Attention à historique Tout ce qui a été pushé ne doit plus être modifié localement exception permise pour les branches identifiées comme purement personnelles personnelles (git push --force) Allégorie de git push --force 196 / 235

Slide 197

Slide 197 text

Deux ou trois petites choses pour terminer a.k.a. « one more thing... » dans une société à la pomme 197 / 235

Slide 198

Slide 198 text

Ou plutôt pour bien commencer 198 / 235

Slide 199

Slide 199 text

git-config 199 / 235

Slide 200

Slide 200 text

git-config Obligatoire pour commiter $ git config --global user.name "Your name" $ git config --global user.email "[email protected]" 200 / 235

Slide 201

Slide 201 text

git-config Obligatoire pour commiter $ git config --global user.name "Your name" $ git config --global user.email "[email protected]" Changer l'éditeur par défaut $ git config --global core.editor vim 201 / 235

Slide 202

Slide 202 text

git-config Obligatoire pour commiter $ git config --global user.name "Your name" $ git config --global user.email "[email protected]" Changer l'éditeur par défaut $ git config --global core.editor vim ~/.gitconfig $ git config --list $ cat ~/.gitconfig 202 / 235

Slide 203

Slide 203 text

Format de messages de commit $ git status -s A file.txt $ git commit 203 / 235

Slide 204

Slide 204 text

Format de messages de commit $ git status -s A file.txt $ git commit Sujet du commit Que s'est-il passé ? Le pourquoi du commit, son contexte. Parce que le comment, c'est ce qu'il y a dans le code... [Ticket en rapport] # Veuillez saisir le message de validation pour vos modifications. # Les lignes commençant par '#' seront ignorées, et un message vide # abandonne la validation. # Sur la branche master # # Validation initiale # # Modifications qui seront validées : # nouveau fichier: plop # 204 / 235

Slide 205

Slide 205 text

Format de messages de commit $ git status -s A file.txt $ git commit *Sujet du commit Que s'est-il passé ? Le pourquoi du commit, son contexte. Parce que le comment, c'est ce qu'il y a dans le code... [Ticket en rapport] # Veuillez saisir le message de validation pour vos modifications. # Les lignes commençant par '#' seront ignorées, et un message vide # abandonne la validation. # Sur la branche master # # Validation initiale # # Modifications qui seront validées : # nouveau fichier: plop # 205 / 235

Slide 206

Slide 206 text

Format de messages de commit $ git status -s A file.txt $ git commit Sujet du commit *Que s'est-il passé ? *Le pourquoi du commit, son contexte. *Parce que le comment, c'est ce qu'il y a dans le code... [Ticket en rapport] # Veuillez saisir le message de validation pour vos modifications. # Les lignes commençant par '#' seront ignorées, et un message vide # abandonne la validation. # Sur la branche master # # Validation initiale # # Modifications qui seront validées : # nouveau fichier: plop # 206 / 235

Slide 207

Slide 207 text

Format de messages de commit $ git status -s A file.txt $ git commit Sujet du commit Que s'est-il passé ? Le pourquoi du commit, son contexte. Parce que le comment, c'est ce qu'il y a dans le code... *[Ticket en rapport] # Veuillez saisir le message de validation pour vos modifications. # Les lignes commençant par '#' seront ignorées, et un message vide # abandonne la validation. # Sur la branche master # # Validation initiale # # Modifications qui seront validées : # nouveau fichier: plop # 207 / 235

Slide 208

Slide 208 text

Ignorer des fichiers .gitignore 208 / 235

Slide 209

Slide 209 text

Ignorer des fichiers .gitignore Ignorer des fichiers à ne pas versionner ou sensibles (mots de passe) 209 / 235

Slide 210

Slide 210 text

Ignorer des fichiers .gitignore Ignorer des fichiers à ne pas versionner ou sensibles (mots de passe) local au dépôt et partageable (on peut le versionner) 210 / 235

Slide 211

Slide 211 text

Ignorer des fichiers .gitignore Ignorer des fichiers à ne pas versionner ou sensibles (mots de passe) local au dépôt et partageable (on peut le versionner) $ git config --global core.excludesfile ~/.gitignore_global *$ cat ~/.gitignore_global **~ **.bak *.DS_Store 211 / 235

Slide 212

Slide 212 text

Ignorer des fichiers .gitignore Ignorer des fichiers à ne pas versionner ou sensibles (mots de passe) local au dépôt et partageable (on peut le versionner) $ git config --global core.excludesfile ~/.gitignore_global *$ cat ~/.gitignore_global **~ **.bak *.DS_Store .git/info/exclude 212 / 235

Slide 213

Slide 213 text

Ignorer des fichiers .gitignore Ignorer des fichiers à ne pas versionner ou sensibles (mots de passe) local au dépôt et partageable (on peut le versionner) $ git config --global core.excludesfile ~/.gitignore_global *$ cat ~/.gitignore_global **~ **.bak *.DS_Store .git/info/exclude Ignorer des fichiers du dépôt 213 / 235

Slide 214

Slide 214 text

Ignorer des fichiers .gitignore Ignorer des fichiers à ne pas versionner ou sensibles (mots de passe) local au dépôt et partageable (on peut le versionner) $ git config --global core.excludesfile ~/.gitignore_global *$ cat ~/.gitignore_global **~ **.bak *.DS_Store .git/info/exclude Ignorer des fichiers du dépôt Purement local au dépôt (non partagé, non versionnable) 214 / 235

Slide 215

Slide 215 text

Formatage de fichiers 215 / 235

Slide 216

Slide 216 text

Formatage de fichiers core.autocrlf Git va convertir les fins de lignes en fonction de la valeur 216 / 235

Slide 217

Slide 217 text

Formatage de fichiers core.autocrlf Git va convertir les fins de lignes en fonction de la valeur true true = CRLF <-> LF entre le WT et l'index 217 / 235

Slide 218

Slide 218 text

Formatage de fichiers core.autocrlf Git va convertir les fins de lignes en fonction de la valeur true true = CRLF <-> LF entre le WT et l'index pour les windowsiens responsables 218 / 235

Slide 219

Slide 219 text

Formatage de fichiers core.autocrlf Git va convertir les fins de lignes en fonction de la valeur true true = CRLF <-> LF entre le WT et l'index pour les windowsiens responsables input input = CRLF -> LF vers le WT mais pas l'inverse 219 / 235

Slide 220

Slide 220 text

Formatage de fichiers core.autocrlf Git va convertir les fins de lignes en fonction de la valeur true true = CRLF <-> LF entre le WT et l'index pour les windowsiens responsables input input = CRLF -> LF vers le WT mais pas l'inverse pour les Macqueux/Linuxiens qui bossent avec des Windowsiens pas responsables 220 / 235

Slide 221

Slide 221 text

Formatage de fichiers core.autocrlf Git va convertir les fins de lignes en fonction de la valeur true true = CRLF <-> LF entre le WT et l'index pour les windowsiens responsables input input = CRLF -> LF vers le WT mais pas l'inverse pour les Macqueux/Linuxiens qui bossent avec des Windowsiens pas responsables false false si environnement windows exclusif rarement le cas 221 / 235

Slide 222

Slide 222 text

Gestion des espaces blancs 222 / 235

Slide 223

Slide 223 text

Gestion des espaces blancs core.whitespace Git va détecter et corriger les problèmes éventuels d'espaces blancs 223 / 235

Slide 224

Slide 224 text

Gestion des espaces blancs core.whitespace Git va détecter et corriger les problèmes éventuels d'espaces blancs Par défaut blank-at-eol blank-at-eof trailing-space regroupe les 2 précédents space-before-tab 224 / 235

Slide 225

Slide 225 text

Gestion des espaces blancs core.whitespace Git va détecter et corriger les problèmes éventuels d'espaces blancs Par défaut blank-at-eol blank-at-eof trailing-space regroupe les 2 précédents space-before-tab Off indent-with-non-tab : cherche les lignes qui commencent par des espaces tabwidth=8 par défaut dans ce cas tab-in-indent : vérfie l'indentation avec des Tabs cr-at-eol : git ne corrigera pas les CR en fin de ligne 225 / 235

Slide 226

Slide 226 text

Gestion des espaces blancs core.whitespace Git va détecter et corriger les problèmes éventuels d'espaces blancs Par défaut blank-at-eol blank-at-eof trailing-space regroupe les 2 précédents space-before-tab Off indent-with-non-tab : cherche les lignes qui commencent par des espaces tabwidth=8 par défaut dans ce cas tab-in-indent : vérfie l'indentation avec des Tabs cr-at-eol : git ne corrigera pas les CR en fin de ligne $ git config --global core.whitespace \ trailing-space,space-before-tab,indent-with-non-tab 226 / 235

Slide 227

Slide 227 text

Gestion des espaces blancs core.whitespace Git va détecter et corriger les problèmes éventuels d'espaces blancs Par défaut blank-at-eol blank-at-eof trailing-space regroupe les 2 précédents space-before-tab Off indent-with-non-tab : cherche les lignes qui commencent par des espaces tabwidth=8 par défaut dans ce cas tab-in-indent : vérfie l'indentation avec des Tabs cr-at-eol : git ne corrigera pas les CR en fin de ligne $ git config --global core.whitespace \ trailing-space,space-before-tab,indent-with-non-tab man git-config est ton ami 227 / 235

Slide 228

Slide 228 text

Les Tabs c'est nul de toute manière ! 228 / 235

Slide 229

Slide 229 text

Les Tabs c'est nul de toute manière ! Space FTW! 229 / 235

Slide 230

Slide 230 text

Conclusion 230 / 235

Slide 231

Slide 231 text

Git n'est pas un outil magique 231 / 235

Slide 232

Slide 232 text

Il est juste « au niveau » de ce qu'on peut attendre d'un système de gestion de version de nos jours 232 / 235

Slide 233

Slide 233 text

Toujours de nouvelles choses à voir et à comprendre 233 / 235

Slide 234

Slide 234 text

Je m'en sers tous les jours depuis plus de 4 ans et j'apprends encore tous les jours ! 234 / 235

Slide 235

Slide 235 text

Alors, vous vous y mettez quand ? 235 / 235