Cours
Git / GitHub
Présentation
Présentation personnelle
Présentation du cours
Règles générales concernant :
- les retards
- l'attention en cours
- les supports de cours
- la notation
- interrogation écrite
- TP à faire en groupe
Pourquoi ce cours ?
Pourquoi ce cours ?
- Cours indispensable pour les développeurs
- Néanmoins très intéressant pour les autres (si si vous verrez)
Le versioning
Pourquoi faire du versioning ?
Pourquoi faire du versioning
Prenons l'exemple d'un projet de développement
Comment travaillez-vous en équipe, voire même seul pour :
- Valider des versions stables dans votre avancée ?
- Travailler sur différentes fonctionnalités en parallèle ?
- Gérer un code de production et un code de dev ?
- Voir l'état de votre site web "à l'époque de la version X" ?
- Revenir sur une décision que vous aviez prise ?
- Fusionner le travail que vous avez fait avec celui de votre collègue ?
Le versioning
Le "versioning" est un terme regroupant différentes fonctionnalités :
-
Historique des modifications apportées à un projet
-
Possibilité de se déplacer dans la timeline (se placer à un point précis de l’historique, revenir en arrière, etc.)
-
Aide au travail en équipe grâce à un système de branches (aide à la résolution de conflits)
Il existe de nombreux gestionnaires de versions (VCS)
- Git
- Mercurial
- Subversion
- ...
Alors pourquoi Git ?
Pourquoi Git ?
Un système distribué
Un système distribué
Il existe de nombreuses raisons qui poussent la plupart des développeurs et entreprises à préférer Git à ses différents concurrents
La première reste toutefois le fait qu'il s'agisse d'un système distribué
système non distribué

Système non distribué
- Beaucoup trop dépendant du serveur distant
- Lent et nécessite internet, dans le sens où il faut toujours communiquer avec le serveur
Système distribué

Système distribué
Avec un système distribué, chaque utilisateur possède une copie locale du dépôt distant
Cela assure donc que chaque membre du projet pourra travailler de son coté, sans internet, tout en ayant la capacité de partager son code à tout le monde quand il le souhaite
En cas de panne du serveur, tout le monde a une copie locale : la sécurité est assurée
L'anecdote pas utile
A l'origine, Linus Torvald avait imaginé git pour travailler... sur le noyau linux !
Avant Git, les contributeurs lui envoyait leurs travaux.. via des patchs de codes par mail !
Dernières infos avant de commencer
-
Développement commencé par Linus Torvald pour le noyau Linux en 2005 et suivi par toute la communauté
-
INDISPENSABLE pour n’importe quel développeur… et informaticien en règle générale !
-
Documentation officielle (très bien faite et accessible en français) : https://git-scm.com/
L'installation
L'installation
Windows
L'installation
Windows
- Aller sur git-scm.com
- Télécharger l'installeur
- Lancer l'installeur
Pour toutes les étapes non mentionnées ci-après, faire juste "suivant"
L'installation
Windows

Placer le où vous voulez
L'installation
Windows

On décoche ce qui nous sert à rien
L'installation
Windows

- Utilisation de git bash seulement
- Utilisation de git via l'invite de commande windows
- Installations de quelques commandes linux en plus
Choisissez comme bon vous semble !
L'installation
Windows

Laissez la première
L'installation
Windows
Une fois tout installé, faites un coup de :
Dans votre invite de commande
git helpSi la doc de Git apparaît, tout est OK !
L'installation
Windows
Il est possible que le PATH n'ait pas été mis à jour
Si tel est le cas, renseignez dans votre PATH le chemin vers le dossier bin de l'utilitaire Git que vous avez installé
Le plus souvent à cet emplacement :
C:\Program Files\git\bin
L'installation
Linux
L'installation
Linux
sudo apt-get install gitgit --helpL'installation
Mac
L'installation
Mac
- Aller sur git-scm.com
- Téléchargez le DMG
- Installez le
Si le PKG ne peut pas être installé car ne provenant pas d'un développeur etc.. clic droit + ouvrir
git helpLa configuration
La configuration de git
Git possède un outil de configuration global
Parmi de nombreuses variables, il y a notamment le "nom" et l' "email" à remplir afin de s'authentifier pour la suite des opérations
La configuration de git
git config --global user.name "Bob"
git config --global user.email bob@burger.comLa configuration de git
git config --global --listPour afficher l'ensemble des variables globales renseignées :
La configuration de git
Notons que le flag --global permet de configurer une seule fois ces variables pour tous nos futurs dépôts git
Si souhaité, il est tout à fait possible de ne préciser des variables que pour un dépôt spécifique en retirant simplement ce flag
La configuration de git
La commande pour voir l'ensemble de votre configuration git est la suivante :
git config --listUne aide détaillée
Il est possible d'avoir accès à une documentation détaillée de chaque commande si vous avez un trou à un moment : très utile !
git help <verbe>
git <verbe> --help
man git-<verbe>
git help configInitialiser un dépôt
git init
Initialiser un dépôt
git initgit init est une commande qui va automatiquement créer un dossier caché .git
Ce dossier est CAPITAL car il regroupe l'ensemble des fichiers inhérents au fonctionnement de git et à l'historique de votre dépôt
La commande git init doit être effectuée à la racine du projet que vous souhaitez versionner
Staging
/
l'indexation
git status, git add, git reset <file>, README.md, .gitignore
La première commande que nous allons apprendre est la commande suivante :
git statusCette commande permet de connaître l'état actuel des fichiers dans le projet
Lançons la commande dans un dépôt vide
git status
La commande nous indique 3 choses :
- Nous sommes actuellement sur la branche master (nous y reviendrons dans le chapitre sur les branches)
- Il n'y a pour le moment aucun commit (nous y reviendrons très vite)
- Il n'y a actuellement rien à commiter dans notre dépôt
Créons un fichier README.md dans le dépôt :
touch README.md
git status
Ici, le résultat de git status est quelque peu différent
Nous voyons que git a bien reconnu notre nouveau fichier mais il le considère comme "untracked", soit "non suivi"
Afin de pouvoir sauvegarder l'état courant des fichiers d'un projet, il faut donc les traquer (les suivre) et les indexer, c'est à dire les mettre dans le Staging
Il s'agit ni plus ni moins de dire "Ce fichier là, je le veux dans mon prochain commit" : c'est comme un panier d'achat... mais pour les sauvegardes !
Pour traquer un fichier et l'ajouter au Stage, il faut utiliser la commande :
git addgit add peut prendre comme paramètre :
- le chemin du fichier à ajouter
- le chemin d'un dossier à ajouter (les sous-fichiers seront ajoutés aussi)
- un pattern du genre "*.html" (tous les fichiers avec l'extension html
- --all ou . : tous les fichiers
Ainsi, nous pouvons faire :
git add README.md
git status
ATTENTION, git add ne fait qu'indexer (mettre dans le Stage) la version du fichier avant la commande
Pour mieux comprendre, modifier maintenant le fichier README.md, puis :
git status
Cela peut paraître étrange que le fichier soit à la fois indexé et non indexé mais c'est en fait tout à fait normal.
En effet, la commande git add n'indexe qu'une certaine version du fichier (celle juste avant la commande)
Ainsi, si nous "commitions" maintenant, nous ne sauvegarderions que la version précédente du fichier, sans les changements.
Il nous faudra donc indexer de nouveau le fichier README pour que les changements soient pris en compte
Ainsi :
git add README.md
git status
Le fichier est maintenant prêt à être "commité" et donc sa version sauvegardée !
Mais que faire si nous avons indexé un fichier que nous ne souhaitons pas sauvegarder pour le moment ?
Il faut pour cela utiliser la commande :
git reset <nomDuFichier ou dossier>README.md
Un petit aparté pour parler du fichier README.md que nous venons de créer
Il est une très bonne pratique de toujours en placer un à la racine de votre projet
Il s'agit en fait d'un fichier en Markdown dont l'objectif est de spécifier ce que fait votre projet, la manière dont il fonctionne, etc.
C'est une convention partagée par tous les développeurs, ne pas en avoir serait vraiment dommage
.gitignore
Il arrive souvent que certains fichiers du projet ne doivent pas être versionnés pour plusieurs raisons :
- ce sont des fichiers à ne surtout pas divulguer (rappelons que l'objectif de git est aussi d'avoir un dépôt distant)
- ce sont des fichiers temporaires dans votre dépôt mais absolument pas nécessaires au projet
- ce sont des fichiers de configuration de votre IDE (parfois versionnés, parfois non)
.gitignore
Cela arrive si souvent qu'il existe une méthode très facile pour les déclarer
Il faut créer un fichier .gitignore à la racine de votre projet
Il suffit ensuite de déclarer dans ce fichier l'ensemble des chemins/patterns des fichiers ou dossiers que vous ne souhaitez jamais versionner
.gitignore
créer fichier .gitignore
*.temp
toto/*Ne serons plus pris en compte :
- Les fichiers avec l'extension ".temp"
- La totalité du dossier "toto"
Attention à également indexer le fichier .gitignore dans votre projet !
Nous avons donc appris dans ce chapitre :
- la commande git status permet de connaître l'état du dépôt à tout moment et est capitale
- les fichiers doivent être indexés ("staggés" en franglais) pour être pris en compte à la prochaine version
- la mise en Staging se fait via git add <fichier, ...>
- on retire un fichier ou dossier du Stage grâce à git reset <fichier ou dossier>
- le fichier .gitignore nous permet de renseigner les chemins de fichiers à ne jamais versionner

Pour finir, schématisons toute cette histoire de Stage :
Enregistrer des modifications
git commit (-m, -a)
Qu'est-ce qu'un commit ?
Qu'est-ce qu'un commit ?
Dans l'optique de versioner notre code, nous voudrions pouvoir figer une version de notre projet à un moment donné
C'est exactement à ça que sert un commit
Ce n'est ni plus ni moins qu'une image de votre projet à un moment donné
Qu'est-ce qu'un commit ?
Il faut voir votre Stage comme l'ensemble des fichiers dont vous souhaitez valider la version actuelle et donc la marquer d'un commit
Attention, un commit ne peut donc prendre en compte que les fichiers que vous avez préalablement indexé (mis dans le Stage) avec la commande git add
Créer un commit
La commande magique n'est autre que ... :
git commitVotre terminal vous demandera ensuite (via votre éditeur par défaut) de renseigner un message de commit

Créer un commit
Un message de commit n'est pas obligé d'être unique
Il est toutefois plus que souhaitable de donner un nom clair et représentatif des changements effectués par ce commit
Si votre commit consiste au changement d'une couleur de titre dans votre projet et que, par exemple, vous nommez votre commit "babar", ça n'a aucun sens et le versionning perd beaucoup de son utilité
Appelons donc notre commit "Add .gitignore and readme.md"
Le commit devrait ensuite être validé et nous devrions voir quelque chose comme :

Git nous récapitule donc l'ensemble des modifications apportées par le commit et nous donne également son identifiant SHA-1 : 440156b
Utiliser l'éditeur par défaut peut être embêtant et surtout représenter une étape en plus inutile
Il est tout à fait possible de renseigner le message du commit directement dans la commande grâce au flag -m
git commit -m "Add .gitignore and README.md"Après tout ça, votre projet doit être tout propre et sans aucun changement !
Vérifiez ça avec un petit git status
git status
Rien à commit, le projet est clean, tout va bien !
Jouons avec le Stage
Nous l'avons dit, le commit ne valide que les modifications des fichiers indexés
Par exemple, créons maintenant 2 fichiers index.html et test.html
touch index.html
touch test.htmlJouons avec le Stage
git status
Modifier votre fichier "index.html", ajoutez-le au Stage et commitez
Jouons avec le Stage
git add index.html
git status
git commit -m "Add index.html"Jouons avec le Stage
git status
Nous voyons donc que le commit n'a bien validé QUE les fichiers précédemment indexés
Jouons avec le Stage
Cette particularité est extrêmement appréciable car elle permet de maîtriser avec une grande précision ce que l'on commit et donc de faire un travail propre
Toutefois, il est possible (et souvent fait) d'indexer les fichiers en même temps que de faire le commit, d'une pierre deux coups et ceci grâce au flag -a de la commande commit
Jouons avec le Stage
Ajoutons maintenant d'autres fichiers, header.html et footer.html
git status
Jouons avec le Stage
git add --allTraquons tous ces fichiers :
Modifions ensuite footer.html et voyons l'état du dépôt :

Jouons avec le Stage
git commit -a -m "Start of an awesome site"Plutôt que de continuellement devoir re-add les fichiers dans le Stage, le flag -a prend ici tout son sens
Grâce à cette commande, vous venez donc de réaliser un comit prenant en compte l'ensemble des fichiers traqués, même ceux pas dans le Stage à ce moment
Il existe même un raccourcis :
git commit -am "Start of an awesome site"Visualiser l'historique
git log (--oneline, -p), git diff (--cached)
git log
La commande de base pour visualiser l'historique du dépôt est :
git loggit log permet de lister l'ensemble des commit de la branche en cours
Nous y trouvons :
- leur ID (sha-1)
- leur auteur
- leur date
- leur message
Par exemple, git log sur notre dépôt actuel donne :

git log
Nous voyons donc bien tous les commits que nous avions effectué ensemble !
Vous aurez peut-être remarqué le (HEAD -> master)
Nous l'expliquerons plus en détail quand nous parlerons des branches, mais disons que HEAD correspond à votre emplacement dans l'historique et qu'il pointe actuellement vers master, tout est donc normal
git log
Lorsque nous devons visualiser un grand nombre de commits, la simple commande git log est parfois trop verbeuse
Un petit raccourcis sympa à utiliser peut donc être le flag --oneline qui permet de tout aplatir sur une seule ligne par commit

git log --onelinegit log --oneline
Il est également possible de lister l'ensemble des commits qui ont apporté des modifications à un fichier en particulier grâce au flag -p suivi du nom du fichier
Par exemple, si nous voulons analyser tous les commits qui ont modifié le fichier index.html depuis le début du projet :
git log -p index.htmlCette commande existe aussi en version raccourcie
git log --oneline -p index.htmlgit log -p
Résultat de la commande :

La commande nous donne d'ailleurs pas mal d'informations sur les changements en question : super pratique pour déceler l'origine de changements ou de bugs
git log -p
git diff
Cette commande assez intéressante permet de voir l'ensemble des différences entre le projet courant et le dernier commit
Exemple : Effaçons tout le fichier index.html pour écrire "Git c'est vraiment trop bien"
Puis, lançons la commande :
git diff
git diff
Même si ce n'est pas le format le plus lisible du monde, nous reconnaissons tout de même la suppression d'une ligne et l'ajout d'une autre ainsi que leur détail
git diff
Attention : git diff ne fonctionne que pour les fichiers non indexés !
En effet, si vous faites :
git add index.html
git diffVous ne verrez... rien !
En effet, à partir du moment ou un fichier est indexé, il n'apparaît plus dans le git diff
git diff
Pour visualiser les différences entre le Stage et le dernier commit, la commande est :
git diff --cachedFinissez ce chapitre en commitant les modifications sur le fichier index.html
git commit -m "Update index.html"Visualiser l'historique
BONUS : outil graphique
GitKraken
Outil graphique : GitKraken
Plus un projet git devient imposant, plus il devient compliqué de tout visualiser et gérer via sa console
C'est pourquoi il existe de nombreux outils graphiques permettant de grandement se simplifier la tâche
Il en existe des tonnes, sûrement plein que je ne connais d'ailleurs pas, mais les plus "connus" sont : GitKraken et SourceTree
A savoir également que certains IDE intègrent en interne une gestion de git parfois très élaborée comme pour les très bons IDE JetBrains
Outil graphique : GitKraken
Pour la suite de ce cours, j'utiliserai donc parfois l'outil GitKraken comme outil de visualisation de notre dépôt
Il n'est absolument pas nécessaire que vous le téléchargiez de votre côté, c'est juste un "bonus" pour y voir plus clair dans votre dépôt, mais vous pouvez tout faire sans
Pour information, les deux outils sont très intéressants et mon choix ne veut absolument pas dire que gitKraken est mieux que SourceTree
Ce choix étant essentiellement basé sur la présence d'un poulpe lors de l'ouverture du logiciel
Outil graphique : GitKraken
Côté visualisation, rien de plus simple !
Une fois téléchargé puis ouvert, cliquez sur "open a repo"
open a repository pour aller chercher votre repo git
Sélectionner le dossier comprenant votre dossier .git
Observons ensemble l'outil :
C'est bon ! Vous devriez maintenant voir votre super dépôt !
Outil graphique : GitKraken

Sur la gauche de l'écran nous pouvons voir l'ensemble des branches présente sur votre dépôt local mais aussi sur votre dépôt distant
Nous y reviendrons lors de prochains chapitres
Notez que la coche verte indique sur vous êtes actuellement sur la branche master
Outil graphique : GitKraken

Le premier bloc présente l'ensemble des fichiers non indexés du dépôt courant
En cliquant dessus, vous pouvez les add et donc les placer dans le second bloc : l'ensemble des fichiers indexés du dépôt
Enfin, lorsque vous êtes prêt à commit, vous pouvez entrer votre message de commit dans le "summary" puis commit vos changements
Outil graphique : GitKraken

Voici la vue qui nous intéresse le plus !
Il s'agit de la liste de l'ensemble des commits du projet, dans l'ordre chronologique
Voyez cette vue comme un git log bien plus joli !
En cliquant sur chaque commit, vous pouvez voir à droite de l'écran les fichiers qu'il a modifié ainsi que les changements concernés pour chaque fichier !
Outil graphique : GitKraken
Vous l'aurez compris, cet outil est assez incroyable et nous fait gagner un temps précieux
Cependant, l'utiliser dans toute sa puissance doit impérativement passer par une grande connaissance des bases de git en ligne de commande
Ainsi, nous n'utiliserons de cet outil QUE son écran au centre, soit la visualisation des commits
Libre à vous d'étudier le reste de l'outil, mais nous n'en auront pas le temps dans ce cours et nous concentrerons sur les bases en ligne de commande
Se déplacer dans l'historique
(sans le modifier)
git checkout (hash, master, hash + fileName, master + fileName, --)
L'une des grandes forces de git est la capacité que l'on a à se déplacer dans la timeline du projet
Que diriez-vous de pouvoir revenir n'importe quand dans le projet ?
- Voir le code avant la dernière mise à jour qui a fait tout planter ?
- Jeter un coup d'oeil au projet avant que votre collègue fasse sa "fameuse" refacto qui a tout casser ?
- Ou simplement tout effacer et repartir sur de meilleures base à un moment propre du projet ?
git checkout
git checkout
git checkout est une commande qui a la particularité de vous placer sur le commit de votre choix
(Elle permet également de changer de branche, mais c'est pour un peu plus tard, patience)
Vous pourrez ainsi voir la totalité des fichiers dans l'état dans lequel ils étaient au moment du commit !
Pour cela, il s'agit de récupérer le SHA-1 du commit en question, puis de lancer la commande :
git checkout
git checkout ae8dbf57b9735c777f5465ef2b860e436eb9bd80Ce SHA-1 correspond en fait à mon commit précédent la modification de mon fichier index.html !
Voici ce que nous dit git :

git checkout
Pour ceux qui comprenne à peu près l'anglais, je vous invite à lire ce qui est marqué, c'est très bien expliqué !
Pour résumer, ce message nous indique que nous sommes désormais en mode "detached HEAD"
Comme je l'avais dit précédemment, ce fameux HEAD est en fait .. vous ! et vous ne pointez plus actuellement vers master mais sur l'un des commit de master, dans le passé ! D'où le :

git checkout
Faisons un petit coup de :
git log --oneline
Hummmm.. l'un de nos commits semble avoir disparu, celui intitulé "Update index.html"
C'est normal ! Nous venons de faire un bond dans le passé, grâce à git checkout !
Nous ne voyons pas le commit en question, car il n'existait pas à l'époque, c'est tout !
git checkout

Si on regarde le dépôt grâce à notre outil graphique GitKraken, on s'aperçoit bien du mécanisme
Le HEAD pointe bien vers l'avant dernier commit de la branche master !
git checkout
VOUS ETES SPECTATEUR
Attention, on a sorti les gros titres en rouge
Je vous laisse relire le message que git nous proposait après le checkout, mais il dit en gros que nous ne sommes que spectateur sur ce commit et que nous ne devrions rien changer car aucun commit ne pourra être réalisé
En vérité, c'est un chouia plus compliqué que ça, et vous pouvez tout de même notamment tirer une branche dans un état détaché, mais cela relève d'un cours plus avancé que celui-ci et nous ne le verrons pas
git checkout
Bon, alors si je suis juste spectateur, comment je fais pour revenir dans le présent ?
Si vous souhaitez revenir à l'état présent, vous pouvez à tout moment faire un checkout sur votre branche actuelle :
git checkout master
Et voilà ! Nous étions sur le commit et nous avons switcher sur master !
git checkout
Petite précision, il existe une autre manière d'arriver au même résultat, sans avoir besoin du SHA-1 du commit
git checkout HEAD^Chaque ^ signifiant un bond en arrière d'un commit !
Nous ne faisons que bouger le pointeur de commit en commit
git checkout
Il est aussi possible de récupérer une ancienne version d'un fichier grâce à git checkout hash + fileName
Pour cela, il suffit de faire la même commande, avec le SHA-1 de la version spécifique + le nom du fichier en question
git checkout ae8dbf5 index.htmlEn faisant cela, vous êtes au même endroit dans votre historique mais vous avez ramené un fichier du passé !
git checkout master index.html(si vous voulez annuler et reprendre l'état courant du fichier !)
git checkout
Comme nous sommes toujours dans le présent de notre timeline, nous pouvons tout à fait commit notre fichier et donc mettre à jour le projet en revenant à l'ancienne version de ce fichier
git commit -m "Put old version of index.html"
git checkout
Voici une dernière commande intéressante concernant checkout et le retour dans le passé
Que faire si l'on ne souhaite pas conserver les modifications que nous sommes en train d'apporter à un fichier ?
git checkout
Il existe une commande permettant de réinitialiser un fichier à l'état qu'il avait au dernier commit !
git checkout -- fileNameAttention cependant ! En effectuant cette commande vous revenez bien à l'état du dernier commit, mais vous perdez absolument tous les changements !
Modifier l'historique
Un grand pouvoir implique de grandes responsabilités
git revert, git reset (--soft, --mixed, --hard), git commit --amend
ATTENTION
ATTENTION
La plupart des commandes que nous allons apprendre dans ce chapitre sont aussi utiles que dangereuses
La modification d'un historique git ne doit jamais être pris à la légère car il s'agit peut-être du projet le plus important de votre entreprise dont vous modifiez la timeline
Heureusement, la plupart du temps, rien n'est jamais vraiment perdu et les erreurs peuvent être rattrapées
Cependant, ce n'est pas toujours le cas et vous pouvez perdre des données importantes si vous vous y prenez mal, alors prudence
git revert
git revert
Cette commande permet de défaire un commit précédent et d'annuler les changements que celui-ci a mis en place
Cette commande est un peu spéciale car elle ne brise pas vraiment l'historique en "annulant le commit" mais en créant un nouveau commit qui annulera les changements du précédent
Rien de mieux qu'un petit exemple
git revert
Voici les commits de notre dépôt

git revert
Si l'on observe attentivement le premier commit (git log -p 440156b), on s'aperçoit qu'il ne fait que créer le README et le .gitignore

git revert
Tentons de le revert
git revert 440156bIl vous sera demandé un message de commit, laissez celui par défaut et validez
Voici le résultat !

git revert
Nous avons bien un nouveau commit qui vient défaire le précédent commit !
Seulement ... les fichiers étaient en fait bien utiles et ce revert n'était peut-être pas une si bonne idée
Aucun souci, car un revert étant lui-même un commit.. nous pouvons revert un revert !
git revert
git revert 0e72951
Tout est revenu à la normale !
C'est l'astuce avec le revert, il s'agit d'une manière assez sécurisée de revenir sur une décision, car un revert peut lui-même être revert !
git reset
git reset
Vous vous souvenez quand je vous disais de faire attention en modifiant votre historique ?
git reset est justement l'une des commandes à manier avec une grande précaution !
Cette commande, très puissante, permet de revenir à l'état d'un commit mais va littéralement modifier votre historique
git reset
Premier exemple dans les changements courants
Modifions quelques fichiers et faisons les commandes :
git add --all
git status
git reset
Testons maintenant le git reset
git reset
git status
git reset
Nous voyons donc que la commande git reset vient de remettre la totalité du Stage dans l'état dans lequel il était au dernier commit
Il a donc totalement dés-indexé la totalité des fichiers qui l'étaient
Cependant, nous avons pu garder nos modifications, si l'on regarde dans nos fichiers, et ça c'est plutôt rassurant
Sans le savoir, nous venons d'utiliser la commande git reset --mixed (le flag par défaut) qui garde l'ensemble des modifications en mémoire après le reset mais ne les indexe pas
git reset
Seulement.. git reset vient également avec son flag --hard que je vous propose de tester sans plus attendre sur notre dépôt
git reset --hard
git status
git reset
Nous venons d'écraser tous les changements effectués depuis le dernier commit et de revenir à l'état de celui-ci... sans rien garder en mémoire
Or ces changements n'ayant jamais été commité, il nous est impossible de les retrouver via git .. vous comprenez donc qu'il faut utiliser le flag --hard avec une grande prudence
Un 3ème flag existe, le --soft qui permet de revenir en arrière tout en gardant les changements dans l'index (à la différence du --mixed)
git reset sur un commit
git reset sur un commit
La grande force de git reset est qu'il peut s'appliquer directement sur un commit, un peu à la manière d'un git checkout pour revenir dans le passé
La grande différence, et pas des moindres, est que tous les commits précédents seront effacés !
Revenons sur notre dépôt

git reset sur un commit
Ok, imaginons maintenant que je veuille revenir à l'état du commit 0f55c5f
git reset 0f55c5f
git log --oneline
Nous avons bien remonté le temps jusqu'au commit 0f55c5f, effaçant les commits suivants
git reset sur un commit
Cependant, comme nous étions en mode --mixed, nous avons gardé les modifications
git status
git reset sur un commit
Nous pouvons donc les commit
git commit -a -m "Make better index.html message"
git reset sur un commit
Testons maintenant le flag --hard en revenant au commit ae8dbf5
git reset --hard ae8dbf5
Nous sommes bien revenus au niveau du commit, en ayant supprimé toutes les modifications depuis
modifier le dernier commit
modifier le dernier commit
Il peut arriver, pour diverses raisons, que vous ayez besoin de modifier un commit que vous venez de faire
- Peut-être l'avez-vous mal nommé ?
- Peut-être avez vous oublier des changements qui y étaient associés ?
La commande git commit --amend est là pour ça !
git commit --amend
Prenez, par exemple, votre fichier index.html et remplacez tout pour y écrire "Salut tout le monde"
Commitez ensuite ces changements avec un message comme "Add welcoming message"
Vous avez oublié un "!" à la fin de votre phrase dans le index.html... comment faire ?
Créer un nouveau commit juste pour ajouter le "!" semble un peu ridicule, surtout que le message du premier commit était bien, autant les regrouper
git commit --amend
Modifiez votre index.html pour y ajouter le "!"
git add --all
git commit --amendVotre éditeur par défaut va ensuite vous demander de renommer le message de votre commit précédent, si vous le souhaitez
Valider le changement.. et voilà ! Vous n'avez toujours qu'un seul commit, mais avec le "!" en plus

Les branches
git branch (name, -d name), git checkout, git merge (FF, no FF), git rebase (-i)
Les branches
Les branches sont l'une des caractéristiques essentielles de git
Imaginez que vous soyez en train de travailler sur une nouvelle fonctionnalité
Arrivé à la moitié, votre client vous demande de corriger d'urgence un bug en production
Que faire ? Si vous avez tout coder sur master depuis le départ, vous allez pousser la correction du bug + la moitié de votre fonctionnalité ? Donc une fonctionnalité non finie ?
Les branches
Les branches sont justement là pour ça !
Il faut imaginer une branche comme une timeline parallèle à votre branche principale
Vous pouvez ainsi vous déplacer de branche en branche
Développer votre fonctionnalité sur l'une d'elle tout en pouvant revenir sur votre branche principale afin d'y effectuer des corrections urgentes, etc.
Lorsque votre fonctionnalité sera finie, vous n'aurez plus qu'à la fusionner à la branche principale.. et le tour est joué !
Les branches
git branchPour visionner l'ensemble de vos branches, la commande est :

Créons maintenant une nouvelle branche "testing" avec la commande :
git branch testinggit branch

Les branches
Nous venons de créer notre première branche !
Le petit "*" à côté de master signifie que HEAD pointe actuellement dessus
Ainsi, tout nouveau commit sera effectué sur master
Pour changer de branche, il suffit d'utiliser git checkout
git checkout testing

Nous venons de nous déplacer vers testing !
Les branches
Faisons maintenant un commit basique, en modifiant par exemple le index.html
Voilà une représentation de ce que nous venons de faire :

Les branches
GitKraken nous montre le même résultat

- HEAD pointe bien sur la branche testing
- master est bien restée sur le commit précédent
Les branches
Je vous invite d'ailleurs à switcher (checkout) sur master et testing et de faire un coup de git log
Vous remarquerez que testing est bien en avance et que master n'en a aucune idée, chaque branche a sa propre timeline, basée sur sa branche d'origine !
Attention, lorsque vous switchez d'une branche à l'autre, il faut que votre branche courante soit vide de tout changement, sinon git refusera
Pour ce faire, commitez votre travail sur la branche avant de checkout, et c'est bon !
Les branches
(Il existe une technique appelée remisage qui permet d'éviter de commit, en "mettant de côté" notre code, mais nous n'en parlerons qu'en bonus)
Les branches
Lorsque vous créez une branche, pour éviter d'avoir toujours à faire ces deux même commandes :
Infos pratiques
git branch maBranche
git checkout maBrancheVous pouvez directement faire :
git checkout -b maBrancheCette commande va créer la branche et directement vous mettre dessus !
Les branches
BON, ok, c'est cool ..
Mais ça sert à quoi dans la vrai vie ???
Les branches
Cas pratique
Nous allons réaliser un petit cas pratique pour expliquer tout ça et pour voir comment fusionner les branches etc.
Ce chapitre est très important car nous allons aborder les problématiques de Merge, Rebase et de résolutions de conflits, souvent incomprises des débutants
Les branches
Cas pratique
Dans ce cas pratique, nous allons nous baser sur un code "basique" trouvé sur le cours de HTML/CSS d'openclassroom
Vous trouverez les fichiers de code sur votre espace étudiant
Téléchargez les, placez les où vous voulez et initialisez un projet git à la racine
Les branches
Cas pratique
Vous devriez donc avoir une structure de base comme suit :

Vous pouvez ouvrir l'index.html dans votre navigateur et voir le magnifique site qui va nous servir d'exemple !
Les branches
Cas pratique
Qu'allons nous faire ?
Les branches
Cas pratique
Une incroyable refonte graphique a été demandée par le client et est prévue pour dans quelques jours !
Il s'agit de :
- Virer la section "à propos de l'auteur"
- Mettre les onglets en bleu
- Mettre les titres des sections en rouge
La qualité du code n'a aucune importance ! Ce ne sont que des exemples un peu idiots pour nous concentrer sur git !
Les branches
Cas pratique
Commençons par figer la version actuelle sur master pour avoir un bon point de départ
Faites donc un premier commit "Initial commit" avec l'ensemble des fichiers du projet
Une fois que c'est fait, nous pouvons créer une nouvelle branche, pour nous attaquer à la refonte !
Appelons la feature/redesign
git branch feature/redesignLes branches
Cas pratique
Infos pratiques
Il est très bien vu de nommer toutes ses branches de fonctionnalité feature/leNom ainsi que toutes les branches de fix de bug hotfix/leNom
Cela nous vient d'une convention appelée git flow qui décrit d'excellentes pratiques à appliquer dans sa gestion de git
Nous n'aurons cependant pas le temps d'en parler davantage mais je vous invite grandement à vous renseigner dessus !
Les branches
Cas pratique
Première étape de la refonte, virer la section "A propos de l'auteur" !
Niveau code, il suffit de retirer ce bout de code du fichier index.html :

Les branches
Cas pratique
Valider donc ces changements par un petit commit "Remove author section"
git commit -a -m "Remove author section"Notre nouvelle branche est bien en avance sur master avec ce commit

Les branches
Cas pratique
Deuxième étape de notre refonte, mettre les onglets en bleu !
Niveau code, il suffit de remplacer, dans le fichier style.css, ce code :
nav a
{
font-size: 1.3em;
color: #181818;
padding-bottom: 3px;
text-decoration: none;
}Par :
nav a
{
font-size: 1.3em;
color: blue;
padding-bottom: 3px;
text-decoration: none;
}Les branches
Cas pratique
Hop, on valide ce petit changement par un commit "Make navigation tabs blue"
git commit -a -m "Make navigation tabs blue"Les branches
Cas pratique
ALERTE
Avant de réaliser la 3ème étape de la refonte, votre client vous appel, il y a un problème en prod !
En effet, les boutons des réseaux sociaux de l'auteur n'ont jamais été demandé et il veut impérativement que vous les retiriez !

Les branches
Cas pratique
ALERTE
Au cours de la refonte, vous avez retirer la section auteur, mais il s'agit d'une refonte qui ne doit apparaître que dans quelques jours pour le client, il faut donc pour le moment revenir à l'état initial de la prod et simplement retirer les boutons.
Les branches
Cas pratique
Nous allons donc laisser de côté pour le moment notre travail sur la refonte, et revenir sur master
git checkout masterRegarder votre site .. rien qu'avec cette commande, il vient de reprendre exactement l'état qu'il avait au début, l'état de la prod !
Maintenant qu'on a compris que les urgences peuvent subvenir n'importe quand, on va être prudent et créer une branche pour notre correction de bug !
Les branches
Cas pratique
git branch hotfix/remove_buttonsNous pouvons maintenant tranquillement corriger notre bug !
Mais pourquoi avoir créer une nouvelle branche et ne pas avoir corriger directement sur master ?
Imaginons que la correction de ce bug prenne du temps et qu'un autre bug, encore plus critique, arrive en même temps... ça devient compliquer à gérer
Créer une branche par tâche permet de bien séparer le travail et de ne jamais avoir ce genre de souci
Les branches
Cas pratique
Pour la correction du bug, rien de plus simple, il vous suffit de retirer les dernières balises <p> dans la section auteur

Les branches
Cas pratique
Testez que tout fonctionne bien, et si c'est le cas, committez votre modification !
git commit -a -m "Remove social network buttons"Les branches
Cas pratique
Léger rappel sur la situation actuelle de notre dépôt :

- master est bien restée sur le commit initial
- feature/redesign suis sa route en parallèle
- hotfix/remove_buttons est à 1 commit d'avance sur master
Les branches
Cas pratique
Il est temps de rapatrier votre fix sur la prod !
La notion de Merge
Le cas simple : Fast Forward
Les branches
Cas pratique
Voici un moment important dans notre cours sur les branches : le fait de "merger" une branche sur une autre
Merger signifie le fait de fusionner une branche à une autre. Autrement dit, rapatrier le code d'une branche sur une autre afin de n'en faire qu'une
Ici, nous allons rapatrier le code de hotfix/remove_buttons sur master afin de "pousser en prod" le correctif
Les branches
Cas pratique
Lorsque l'on veut faire un merge, il faut toujours se placer sur la branche qui va accueillir l'autre
Plaçons-nous donc sur master
git checkout masterIl ne reste plus ensuite qu'à appliquer la commande git merge en précisant la branche à merger
git merge hotfix/remove_buttonsLes branches
Cas pratique

git merge hotfix/remove_buttonsLes branches
Cas pratique
Que s'est-il passé ?
Etant donné que le commit sur la branche hotfix était directement un descendant du commit sur master, git n'a fait que déplacer le pointeur HEAD d'un cran sur le commit de hotfix
Il s'agit du cas de merge le plus simple qui a pour nom : l'avance rapide ou Fast Forward en anglais
Les branches
Cas pratique

GitKraken nous indique d'ailleurs bien ce simple changement
Désormais, master ET hotfix pointent vers le même commit
Les branches
Cas pratique
Nous pouvons dors et déjà supprimer la branche hotfix
Il est important de toujours avoir un système de branche propre pour mieux s'y retrouver
Si une branche n'est plus utile, on la supprime
Pour supprimer, il suffit de lancer la commande :
git branch -d hotfix/remove_buttonsLes branches
Cas pratique
Notons que -d ne fonctionnera pas si la branche ciblée contient des modifications encore non mergée
Il faudra alors utiliser le flag -D si vous souhaité tout de même forcer sa suppression
git branch -D hotfix/remove_buttonsLes branches
Cas pratique
Désormais, nous pouvons reprendre notre travail que nous avions mis de côté sur la branche feature !
git checkout feature/redesignIl ne nous reste plus qu'à mettre les titres de sections en rouge !
Les branches
Cas pratique
Niveau code, il suffit de remplacer, dans le fichier style.css, ce code :
section h1, footer h1, nav a
{
font-family: Dayrom, serif;
font-weight: normal;
text-transform: uppercase;
}Par :
section h1, footer h1, nav a
{
font-family: Dayrom, serif;
font-weight: normal;
text-transform: uppercase;
}
section h1
{
color: red;
}Les branches
Cas pratique
Y'a plus qu'à commit !
git commit -a -m "Make section titles red"Et voilà ! Notre superbe refonte graphique est finie, et en plus on s'est payé le luxe de réparer un bug en prod durant la refonte !
Les branches
Cas pratique

Voici l'état de notre dépôt actuellement !
Les branches
Cas pratique
Nous remarquons que la branche master a avancé pendant la refonte
C'est un cas très courant et qui soulève une question : comment git va faire pour merger les deux branches ??
Faisons le test, mettons nous sur master et mergons !
git checkout master
git merge feature/redesignLes branches
Cas pratique

Tout ne s'est pas passé comme prévu !
Automatic merge failed nous indique que git n'a pas été capable de gérer la fusion tout seul
En effet, normalement git arrive à gérer les fusions automatiquement, ce qui est très très appréciable
Les branches
Cas pratique
Il arrive pourtant parfois qu'un même bout de code ait été modifié sur les deux branches, ce qui donne lieu à ce qu'on appelle un conflit
Git ne peut alors choisir à votre place quel code prendre en compte, c'est donc à vous de prendre la décision !
Heureusement, git est sympa et vous indique les conflits existants grâce à la commande git status que l'on connaît bien
Les branches
Cas pratique
git status
Les branches
Cas pratique
Cette commande nous donne toutes les infos utiles !
Elle nous indique déjà qu'il n'y a que 2 manières de sortir de conflits :
- Les régler puis faire un commit de résolution
- abandonner la résolution de conflits avec la commande git merge --abort
Les branches
Cas pratique
git status nous indique également que git a parfaitement réussi à fusionner le style.css sur master et celui sur feature, et que cleui-ci est dans le Stage
Enfin, la commande nous indique tous les "Unmerged paths", soit les fichiers causant des conflits : ici uniquement le index.html
Les branches
Cas pratique
Allons donc dans le fichier index.html

Git a l'air de nous avoir mis pleins de caractères bizarres et compliqués, mais ce n'est pas si difficile à comprendre en fait
Les branches
Cas pratique
Lors d'un conflit de merge, git va indiquer dans le fichier les changements apportés par les deux branches et vous serez responsable de ne garder que ce qui vous intéresse

Les changements sont séparés par les symboles "===="
Les branches
Cas pratique
Ici, il faut comprendre que les changements apportés par feature/redesign sont en dessous des "====" (il n'y a en l'occurence rien car feature/design a supprimé cette partie du code)
Les changements apportés par master (HEAD) , eux, sont au dessus des "===="

Les branches
Cas pratique
Il ne reste donc plus qu'à faire votre choix !
Ici, comme nous voulons rapatrier le code de la refonte graphique, nous allons uniquement laisser le code provenant de feature/redesign !
Soit... rien ! Donc vous pouvez tout supprimer :)
Il arrive parfois d'avoir envie de piocher un peu dans les deux, et c'est tout à fait faisable !
Il faut simplement penser à enlever tous les chevrons écris par git et bien laisser le code que vous souhaiter valider !
Les branches
Cas pratique
Cette étape consistant à aller chercher, grâce à git status les différents conflits et les réparer peut paraître un peu compliquée au début mais ça vient vite
Vous verrez vite qu'il est primordial de savoir gérer des conflits lors de travail en équipe car ils sont inévitables !
En effet, en équipe, tout le monde travaille de manière parallèle sur des branches séparées, et les merges génèrent souvent des conflits !
Mais vous l'avez vu, rien d'insurmontable !
Les branches
Cas pratique
Une fois que vous avez pioché le code qu'il vous faut, vous n'avez plus qu'à valider vos changements avec un commit après avoir indexé votre fichier!
git add index.html
git commit -m "Merge redesign into master"Maintenant que nous n'avons plus besoin de la branche feature/redesign, on peut la supprimer
git branch -d feature/redesignLes branches
Cas pratique
Et voilà !

Les branches
Cas pratique
Notons qu'en cas de merge non fast-forward, git garde en mémoire le fait que le code provenait d'une autre branche comme le schéma l'indique
C'est assez intéressant car cela permet de vraiment comprendre tout l'historique du projet !
Les branches
Cas pratique
Il est également possible de forcer l'utilisation d'un commit de merge si l'on souhaite garder un historique complet et empêcher le fast-forward
Pour ce faire, il suffit de rajouter le flag --no-ff à la commande de merge
git merge --no-ff maBrancheQue le Fast-forward soit possible ou non, git ne l'utilisera alors pas et forcera l'utilisation d'un commit de merge
Les branches
Cas pratique
Pour finir sur le merge
Les branches
Cas pratique
Pour finir sur le merge
Il nous reste un tout dernier effort pour comprendre le merge
Nous avons vu qu'un merge fast-forward se contente d'avancer le pointeur de la branche d'acceuil
Nous avons vu que lors d'un merge avec conflit, nous devons les réparer puis créer un commit de merge
Les branches
Cas pratique
Que se passe-t-il lors d'un merge non fast-forward (où la branche d'accueil a avancé parallèlement) mais sans conflits ?
Pour faire le test, créez une branche test, modifiez-y le fichier style.css, commit, puis revenez sur master et faites un changement sur index.html puis commit
git checkout -b test
# Modifiez le fichier css
git commit -a -m "Update css"
git checkout master
# Modifiez le fichier html
git commit -a -m "Update html"
git merge testLes branches
Cas pratique

Git a parfaitement réussi à fusionner les deux branches car il n'y avait aucun conflit !
Il vous demande alors simplement de rentrer votre message de commit (ou garder celui-ci) puis votre merge sera effectué !
Les branches
Cas pratique
git branch -d test
Les branches
(Le cas rebase)
Le cas REBASE
Il existe une manière d'aplatir 2 branches et de réaliser un merge fast-forward même si, à priori, les deux branches ont avancé parallèlement grâce au principe du rebase
Le rebase est une technique dangereuse dans le sens ou vous allez manipuler et modifier l'historique
Toutefois elle a pour avantage de pouvoir rendre l'historique un peu plus joli et digeste
Les branches
(Le cas rebase)
En effet, le merge a pour "défaut" de garder l'historique des branches et de rajouter un commit de merge en plus
Du coup, pour voir les modifications apportées par les différentes branches, il faut suivre l'évolutions de ces branches car les commits y sont restés et ce n'est parfois pas pratique
L'idée derrière le rebase sera donc de rejouer la totalité des commits présents sur la branche pour les mettre sur master et donc aplatir complètement l'historique
Les branches
(Le cas rebase)
Alors comment faire ?
Tout d'abord, créons un petit cas avec une nouvelle branche toto
Faites-y un commit ajoutant un fichier toto.txt
Revenez sur master et faites un commit ajoutant un fichier tata.txt
Retournez sur la branche toto
git rebase master
git checkout master
git merge totoLes branches
(Le cas rebase)
Les branches
(Le cas rebase)
Grâce à cette commande, vous venez de rejouer tous les commits de la branche master sur la branche toto !
Ensuite il a suffit de revenir sur master et de faire un simple merge, qui sera alors fast-forward car toto a été mis à jour aves les commits de master !
Les branches
(Le cas rebase)
Depuis master, supprimer toto et vous verrez que votre historique git a l'air de fonctionner comme s'il n'y avait jamais eu de branche toto !
Cette technique, en supprimant le commit de merge et en rejouant les commits sur la branche ciblée permet un historique plus lisible et joli mais empêche en contrepartie de comprendre l'historique des branches du projet
Les branches
(Le cas rebase)
Un peu comme pour le merge, nous avons vu ici le cas d'un Rebase sans conflits
Nous allons revenir à l'état précédent tous ces changements pour voir un cas un peu plus complexe mais instructif
Faites donc un coup de reset --hard sur le commit précédent ces changements, b1518cd7860864382ff8dc3ab2add5ca14e6cb42 pour moi
Les branches
(Le cas rebase)
Ensuite, nous allons créer de nouveau une branche toto et faire les changements suivants dessus
touch toto.txt
git add --all
git commit -am "Add toto.txt"
// Modifiez ensuite le index.html en
// changeant le premier titre h2
git commit -am "Change title toto"Les branches
(Le cas rebase)
Revenez sur master, modifier le premier titre h2 comme bon vous semble et commitez
git checkout master
// Modifiez le titre h2
git commit -am "Update title"Les branches
(Le cas rebase)
Revenez sur toto, faites un rebase mais cette fois-ci en ajoutant un petit flag -i (pour "interactive")
git rebase -i masterLes branches
(Le cas rebase)

Les branches
(Le cas rebase)
N'ayez pas peur !
La commande rebase est très puissante et nous donne l'occasion de réorganiser nos commits ! En effet, nous allons appliquer nos commits sur master, mais avant tout, on peut y faire un peu de ménage
Si vous ne changez rien dans l'écran qui vous est proposé, les 2 commits seront pris en compte
Notez que les commits vous sont présentés dans le sens inverse du log : Le plus récent est ici en bas de page
Les branches
(Le cas rebase)
Mettons que nous souhaitions fusionner ces commits pour n'en faire qu'un seule (représentatif de tout le travail effectué sur la branche toto)
Il suffit pour cela de remplacer le pick devant le second commit par un squash (ou s uniquement)
Nous indiquons alors à git que nous souhaitons fusionner le seconds commit dans le premier ! Ceci est possible pour un nombre X de commits
Nous pourrions également renommer le premier commit pour un historique plus lisible avec le flag reword
Les branches
(Le cas rebase)
Ce qui nous donne :

Sauvegardez et quittez
Attention, petite coquille ici : ne changez pas le nom du premier commit, ou alors placez un reword ou un r à la place du commit pour préciser que vous voulez le renommer
Les branches
(Le cas rebase)
Nous avons des conflits !
Eh oui, merge et rebase ont de toute manière le même souci lorsqu'une même portion de code est modifiée sur les deux branches, c'est à nous de dire quel code prendre !
Les branches
(Le cas rebase)
Git nous explique dans ce message ce qu'il nous est possible de faire :
- Les résoudre, indexer les fichiers et continuer le rebase avec un git rebase --continue
- Annuler et revenir à l'état avant le rebase avec un git rebase --abort
Corrigeons donc nos conflits !
Les branches
(Le cas rebase)
git status
Le problème semble venir d'index.html
Les branches
(Le cas rebase)

Prenons par exemple les changements provenant de la branche toto et donc du commit daa452a
Les branches
(Le cas rebase)
git add index.html
git rebase --continue
// Choisissez le message de commit qui vous va Nous avons donc normalement maintenant la branche toto qui a bien récupérer les modifications de master et les a incorporé à son historique
Attention, rappelez-vous que nous avions souhaiter modifier le premier message de commit lors du squash. S'il y a des conflits, il faut redonner ici le message que vous souhaitiez donner
Les branches
(Le cas rebase)

Les branches
(Le cas rebase)
Ainsi, nous allons pouvoir retourner sur master et faire un merge fast-forward pour un historique propre
git checkout master
git merge totoEt voilà ! Nous pouvons dorénavant supprimer la branche toto et l'historique, grâce à ce petit merge fast-forward ne fera plus apparaître la branche toto
Les branches
(Le cas rebase)
Pour résumer, le rebase permet donc de rejouer les commits de la branche ciblée sur la branche courante afin de ré-écrire l'historique
Une fois l'historique propre, la brache cible peut donc merger votre branche sans souci et en faisant donc un fast-forward qui rend invisible la branche dans l'historique de git
Les branches
Félicitations !
Si vous avez tenu jusque là et bien compris les différentes notions, c'est vraiment top !
Les notions de merge sont toujours un peu compliquées au début, mais relisez ce cas pratique 2 ou 3 fois et tout devrait être clair :)
Le remote : GitHub
GitHub, git remote (-v, add), git branch -r, git push, git pull (--rebase), git fetch
Le remote : Github
Si vous êtes arrivé à ce chapitre en ayant bien compris les précédents, c'est que vous êtes déjà bien à l'aise avec git en local
Je précise git en local car souvenez-vous du début du cours, nous parlions de git comme d'un système distribué
Jusqu'à présent, vous avez appris tout un tas de choses sur git vous permettant de très bien organiser votre travail de manière locale, sur votre ordinateur
Mais comment travailler en équipe à distance ?
Le remote : Github
Nous l'avons vu, un dépôt git n'est rien d'autre qu'un dossier dans lequel nous avons fait un git init et qui contient donc, au fur et à mesure, tout l'historique de notre projet
Ce que nous appelons un remote n'est en fait rien d'autre qu'un dossier git à distance !
Sauf que ce dossier en question peut être n'importe où ! Il peut s'agit d'un autre dossier sur votre ordinateur, sur une clé USB, sur l'un de vos serveurs à distance, etc.
Le remote : Github
L'intérêt d'un tel procédé est que votre dépôt local et votre dépôt distant pourront communiquer entre eux pour se partager l'historique !
Ainsi, vous pourrez mettre facilement la totalité de votre code source sur un dépôt à distance
Cette particularité est incroyable car, tout en vous permettant de travailler avec l'historique complet sur votre ordinateur, elle vous permet de tout mettre en lieu sûr à distance (en cas de perte de données de votre ordinateur) mais également de partager votre code avec vos collègues ou au monde entier !
Le remote : Github
Le remote correspond donc à ce fameux dossier à distance !
Il est d'ailleurs tout à fait possible d'avoir plusieurs remote pour un même projet, même si c'est plus rare
Mis à part quelques commandes vous permettant d'interagir avec le dépôt distant, vous allez vite comprendre que, ce remote n'étant qu'un dossier git comme un autre, ce que vous avez appris jusqu'à présent correspond à 90% de ce qu'il faut savoir sur git !
Et ce fameux "GitHub" dans tout ça ?
Le remote : Github
Nous l'avons dit, un dépôt distant peut être n'importe où !
Le plus pratique, pour pouvoir travailler en équipe, est d'avoir ce dépôt sur un serveur distant et que chacun y ait accès de chez lui
Seulement gérer un serveur, sa sécurité, etc.. n'est pas toujours simple et sympa
C'est là que Github intervient !
Github permet d'héberger gratuitement vos dépôts distants !
L'outil vient en plus avec une interface graphique et des outils incroyablement utiles et pertinents !
Le remote : Github
Attention, il existe de nombreux autres outils du même genre !
- GitLab
- BitBucket
- ...
Chacun a ses avantages et ses défauts mais ils sont tous identiques sur le principe
Nous prendrons pour ce cours GitHub car il s'agit du plus utilisé à ce jour dans le monde et .. voilà
Je vous invite donc tous à aller sur www.github.com et de vous y créer un compte
Essayez d'utiliser la même adresse mail que celle renseignée dans les configs de votre git local !
Sinon, changez simplement celle de git local, ce n'est pas grave :)
Le remote : Github
- En cliquant en haut à droite, vous pouvez aller dans "your profil"
- Aller dans l'onglet "repositories"
- Cliquer sur le bouton "New"
Nous allons créer notre premier dépôt sur GitHub !
Le remote : Github

Le remote : Github
- Vous devez naturellement donner un nom à votre dépôt
- Vous pouvez ensuite accessoirement lui donner une description
- Si cela vous intéresse, vous pouvez le mettre en privé, auquel cas seul vous pourrez le consulter
Un dépôt public peut en effet être consulter par tout le monde.
Attention cependant, seul vous et les personnes que vous aurez autoriser pourront le modifier
Le remote : Github
Une fois que c'est fini, vous pouvez cliquer sur le bouton "Create repository" !
Vous arriverez ensuite sur l'écran principal de votre dépôt et vous pouvez remarquer que GitHub vous mâche déjà le travail pour la suite des opérations
Mais comme il y a des commandes que vous ne connaissez pas, nous allons d'abord les étudier ensemble avant de continuer
git remote
Le remote : Github
Reprenons le dépôt local où nous l'avions laissé au chapitre précédent
Un dépôt distant n'est constitué, pour git, que de 2 informations importantes :
- Un nom
- Un chemin pour y accéder (dans le cas d'un serveur distant, son URL)
Le remote : Github
Ajouter un dépôt distant à un git local est très simple, il suffit de faire la commande :
git remote add nomDepot urlDepotAttention, le nom du dépôt ne doit pas forcément correspondre au nom que vous avez mis sur GitHub. Il ne s'agit que de son "identifiant" pour le git local (au cas ou vous auriez plusieurs dépôts distants)
La norme veut que le principal dépôt distant d'un projet git se nomme "origin"
Le remote : Github
Créons donc notre dépôt distant !
Pour trouver l'URL associée à votre dépôt GitHub :

git remote add origin https://github.com/ThomasEcalle/cours_git_2019.gitLe remote : Github
La commande git remote -v permet de lister tous nos remotes :
git remote -v
Nous avons donc bien notre remote origin qui a été mis en place et qui pointe vers notre dépôt GitHub !
L'url de fetch est l'url qui va nous permettre de récupérer localement tous les changements fais sur le dépôt distant
Le remote : Github
Il est possible de lister l'ensemble des branches présentes sur le dépôt distant grâce à :
git branch -rLa commande n'affiche rien pour le moment car nous n'avons tout simplement rien sur le dépôt distant
Nous allons donc commencer par "pousser" nos changements sur le remote
Le remote : Github
Pour ce faire, voici la commande :
git push origin masterComprendre "nous poussons l'état actuel du projet (donc la dernière version de la branche master) sur le branche master du dépôt distant origin"
Une fois que c'est fait, mettez à jour votre dépôt github !

Côté dépôt local, je peux voir les changements sur le remote et je peux m'amuser à pousser de nouvelles choses !
Le remote : Github
git branch -r
git branch test
git push origin test
git branch -r

Le remote : Github
Voilà donc comment pousser du contenu sur un dépôt distant !
Maintenant, nous allons voir comment faire pour récupérer du contenu et donc rentrer un peu plus dans le travail en équipe
Tout d'abord créons un dossier parallèle qui représentera le dépôt local de Bob, un développeur de l'équipe
Bien sûr, dans la vraie vie, Bob a son dépôt sur son ordi, mais ça revient exactement au même, deux dépôts git sont complètements indépendants
Le remote : Github
cd ..
Il y a une commande très simple pour commencer un dépôt git à partir d'un déjà existant : git clone
La commande a simplement besoin de l'URL du dépôt et, éventuellement, du nom du dossier dans lequel le mettre si différend du nom du dépôt distant, et tout est bon
git clone https://github.com/ThomasEcalle/cours_git_2019 repo_de_bobLe remote : Github
Bob a maintenant accès en local à la totalité du code présent sur le remote !!
Bob peut donc faire son travail à lui, puis le pousser, etc.
Evidement, pour respecter tout ce qu'on a vu précédemment, Bob devrait faire une petite branche, faire son travail, et ne la merger à master qu'une fois que tout est bon
Pour ce cours sur le remote, disons que Bob va simplement modifier le index.html et pousser ses modifications sur origin master
Le remote : Github
Modifions le premier titre <h2> du index.html en y mettant
<h2>Voici le nouveau titre</h2>
git commit -a -m "Update Home title"C'est bon, Bob a fait tout ce qu'il avait à faire, il peut pousser sur le remote !
git push origin masterLe remote : Github
Le dernier commit de Bob a bien été pris en compte !

Attention, ici GitHub ne fait évidemment pas la différence entre "Bob" et "moi" puisque les configs de mon git local sont généralisées et indiquent l'adresse email correspondant à ce compte Github
C'est donc tout à fait normal, et dans la vrai vie chaque développeur a ses propres configs pour signer différemment ses commits
Le remote : Github
Voyons maintenant, en retournant sur mon premier dépôt, comment je peux récupérer les nouveautés apportées par Bob !
Le remote : Github
La commande pour récupérer les informations d'une branche en remote est très simple
S'il fallait "pousser" pour envoyer les informations, il faut "tirer" pour les récupérer !
git pull origin master
Le remote : Github
Et voilà !
Nous venons de récupérer le commit que Bob a fait et tout va bien dans le meilleur des mondes !
Si vous observez bien le message lors du pull, il indique un "Fast-forward"
Cela devrait vous rappeler le cours sur les branches et les problèmes potentiels de merge !
Il faut comprendre que la branche master à distance n'est qu'une branche comme une autre ! Le pull que vous venez d'effectuer n'est finalement qu'une fusion de 2 branches comme nous en avions l'haitude !
Le remote : Github
En effet, ici, nous avons attendu sagement que Bob fasse son commit avant de pull. Mais dans la vrai vie, il se peut que nous avancions en même temps
Comme toute fusion, il y a des cas comme celui-ci ou la branche cible est juste en avance par rapport à l'actuelle et qui se résume donc en un simple fast-forward
Mais ce n'est pas toujours le cas
Le remote : Github
Faisons un test !
Revenez sur le dépôt de Bob, créez un fichier test.txt puis commitez et poussez le
Revenez sur le dépôt principal, faites de même mais en appelant le fichier test2.txt et sans avoir pull avant
Le remote : Github
// Allez sur le dépôt de Bob
touch test.txt
git add --all
git commit -m "Add test.txt"
git push origin master
// Allez sur le dépôt initial
touch test2.txt
git add --all
git commit -m "Add test2.txt"
git push origin master
Le remote : Github
Une erreur ? Que s'est-il passé ?
Le message de git est assez explicite mais voici la version française et résumée :
Vous souhaitez apporter des changements à la branche master de votre dépôt distant alors déjà que celle-ci est en avance sur votre branche
Il nous faudra donc toujours impérativement tirer les dernières modifications du remote avant de pouvoir le mettre à jour !
Le remote : Github
Ainsi, comme nous l'avons vu :
git pull origin masterVous devez ensuite préciser un nom de commit de merge !
Rappelez vous le cours sur les branches, git n'a pas été capable de faire un Fast-forward mais a tout de même réussi à gérer le merge.
Cependant , il vous demande tout de même de donner un nom à votre commit de merge
Je garde personnellement celui proposé et valide mon commit
Le remote : Github
Finalement, les problèmes de merge sont exactement les même que pour les branches !
Ce pull aurait également pu présenter des conflits, mais je vous laisse relire le cours sur les branches pour la gestion des conflits, finalement il s'agit exactement du même processus
Notons que si git utilise le merge par défaut lors d'un pull, il est tout à fait possible de préciser que vous souhaitez gérer la fusion via un rebase :
git pull --rebase origin masterLe remote : Github
Il est assez fréquent que les gens utilsent davantage le rebase lorsqu'ils tirent les modifications d'une branche en remote
Cela a en effet comme avantage de ne pas se retrouver avec X commits de merge un peu polluants dans l'historique général
Le remote : Github
git fetch
Le remote : Github
Lorsque vous faites un git pull, git va :
- Tirer en local les changements d'origin
- Faire un merge entre votre branche et celle d'origin
Ce qu'il faut comprendre, c'est que les branches remote (origin) sont des branches comme les vôtre
Il est donc possible de simplement les récupérer en local et les voir
Le remote : Github
Pour récupérer en local les branches distantes, vous pouvez faire un coup de git fetch
Vous aurez ensuite accès, en local, aux branches distantes
Pour les différencier, celles-ci sont préfixées par origin/
Le remote : Github
Vous pouvez ensuite vous déplacer tranquillement sur les branches via des checkout et ainsi visionner sur votre local les changements actuels sur le remote
Faites le test en changeant quelque chose uniquement depuis le remote, soit en passant par un autre dépôt, soit en changeant directement sur Github (démo à l'oral)
Faites ensuite un git fetch, puis voyez que les changement sont arrivés !
Parlons sécurité
Parlons sécurité
Votre dépôt git est un espace très critique niveau sécurité pour vous ou votre entreprise
Il s'agit de l'endroit où vous allez héberger l'ensemble du code source de votre ou vos applications, programmes, etc.
Parlons sécurité
- pour une application (site web, app mobile, etc.), il s'agit tout simplement de son code source, de sa valeur ajoutée
- au delà du code source, il y a également des données potentiellement sensibles qui ne doivent pas tomber entre toutes les mains
Il y a donc constamment des risques de vol de données ou de code source
Parlons sécurité
Mais le vol n'est pas le seul problème potentiel
De nos jours, la plupart des systèmes des historiques git des entreprises sont branchés à des intégrations continues qui ont diverses raison d'être, comme la mise en production du code automatique après un changement particulier par exemple
Imaginez alors ce que pourrait faire quelqu'un de mal intentionné qui pourrait, en quelques secondes, mettre du code malveillant sur votre site en production
Parlons sécurité
Enfin, il est fort probable que vous utilisiez dans votre code des clés d'API de certains services comme Google Map, AWS, etc.
Il est très imprudent de versionner ces clés !
Il existe des robots qui fouillent les dépôt Github à leur recherche et les récupère (vous aurez ensuite une surprise lors de votre prochaine facture)
Parlons sécurité
Nous allons donc voir comment sécuriser au mieux son dépôt Github
Supprimer définitivement un fichier
Supprimer un fichier
Imaginons que vous ayez besoin de retirer toute trace d'un fichier dans votre historique
Ce que nous allons apprendre est dangereux, car nous allons réécrire les SHA-1 de tous les commits impactés par ce changement
Supprimer un fichier
Partez toujours du principe qu'une information poussée sur GitHub est considérée comme compromise
Si vous avez poussé un mot de passe : changez-le !
Si c'était une clé SSH : générez-en une nouvelle
Supprimer un fichier
Nous allons utiliser une commande permettant de filtrer la totalité des commits de notre historique et d'en retirer le fichier en question
Attention, nous allons changer le contenu des commits et donc leur SHA-1 !
Supprimer un fichier
Attention, si des Pull Request étaient en cours, le changement des SHA-1 de votre côté risquent de tout casser au moment du Merge
Il faut donc penser à fermer ou merger les Pull Request avant
Supprimer un fichier
Attention, si votre dépôt a été forké... vous ne pouvez rien y faire, la personne a toujours les commits en question !
Je crois qu'il est toujours possible de contacter GitHub et de voir ce qu'il est possible de faire.. mais autant vous dire qu'il faut TOUJOURS partir du principe que votre info a fuité
Supprimer un fichier
filter-branch
Attention, vos modifications "stashées" seront perdues après cette commande ! Le stash est expliqué dans les Bonus pour ceux que ça intéresse
Supprimer un fichier
Pour expliquer un peu tout ça, mettons en place un petit dépôt git et un dépôt GitHub associé
Créer un déoôt
Créer un fichier mdp.txt avec les mots de passes
Commit
Créer un autre fichier genre index.html
Commit
Créer une branche feature/random
Ajouter une info dans l'index
Commit
Créer un depôt Github
Poussez votre branche principale
Poussez votre branche feature/random
On est bonSupprimer un fichier
Faites bien attention aux SHA-1 des commits
Maintenant, nous nous rendons compte que le mdp.txt ne devait pas être versionné.. nous allons le supprimer de l'historique !
git filter-branch --force --index-filter
"git rm --cached --ignore-unmatch mdp.txt"
--prune-empty --tag-name-filter cat -- --allSupprimer un fichier
"Et voilà"
Nous venons de supprimer les références au fichier en question, ainsi que les commits devenus vides à cause de cette suppression !
Nous venons également de changer tous les SHA-1 du coup !
Supprimer un fichier
Pensez maintenant à mettre votre fichier dans le .gitignore !
Pour finir, nous allons pousser ça sur GitHub
git push origin --force --all--force : permet d'écraser l'historique distant par l'historique local
--all : le fait sur toutes les branches d'un coup
Supprimer un fichier
Enfin, voici les 3 commandes à jouer pour effacer les traces dans le Reflog :
git for-each-ref --format="delete %(refname)" refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --prune=nowSupprimer un fichier
Attention, si certains de vos collègues ont d'autres branches de leur côté, dites leur de REBASE vos branche et non pas de les MERGE
Un commit de merge pourrait potentiellement ramener des références que l'on souhaitait effacer
Supprimer un fichier
Ce que nous venons de faire est intéressant mais dangereux et non annulable
De plus, il existe d'autres étapes à ajouter lorsque vous avec des Tags ou des Pull Request
Voici le lien pour ceux qui veulent aller plus loin :
Supprimer un fichier
Nous l'avons vu, supprimer un fichier est compliqué
Ca peut ne pas fonctionner, ou tout du moins entraîner des effets de bords non souhaités
Partez donc toujours du principe que toute information poussée est compromise et qu'il est impératif de surtout faire attention à ce que vous poussez !
Parlons authentification
Parlons authentification
Tout d'abord, voyons comment mettre en place une authentification par SSH avec notre compte GitHub
Vous authentifier auprès de GitHub via SSH est plus sécurisé car :
- vous n'aurez plus jamais à rentrer vos identifiants
- vous pourrez très facilement révoquer une clé qui vous semble compromise
Parlons authentification
Pour ajouter une clé SSH, rien de plus simple :
ssh-keygen -t ed25519 -C "your_email@example.com"Lorsqu'on vous demande un fichier, ne rentrez rien pour choisir celui par défaut
Indiquez ensuite la passphrase de votre choix
Parlons authentification
Vous devriez ensuite pourvoir voir votre nouvelle clé :
ls -la ~/.ssh
SSH est basé sur un système de clé publique, clé privé
clé publique
clé privée
Savez-vous comment ça fonctionne ?
Parlons authentification
Il s'agit ensuite d'aller placer votre clé publique dans vos settings GitHub
Cela se passe dans :
Profile > Settings > SSH and GPG keys

Parlons authentification
A partir de maintenant, il faut que vous utilisiez l'url SSH de vos dépôts pour vous y connecter !
git remote set-url origin url_sshSignons nos commits
Signons nos commits
Nous allons apprendre ici quelque chose de très important, que très peu de développeurs ont en tête
Nous allons voir que ce que nous connaissons actuellement de Git et des commits peut présenter une légère faille :)
Signons nos commits
Petite démonstration en Live !
L'un de vous doit me donner l'url de l'un de ses dépôts, et je m'occupe ensuite de vous faire une petite démonstration de mes talents de "hacker" pas piquée des hannetons
Signons nos commits
J'écris ici ce que j'ai fais en live, pour que vous ayez de quoi réviser !
Vous vous souvenez de la config globale que nous avions modifiée au tout début de notre aventure avec git ?
Nous y avions placé notre name et notre email
Signons nos commits
Ces informations servent à Git pour savoir qui a fait les changements lors d'un commit
Sauf que... il est très facile de se faire passer pour quelqu'un d'autre !
Prenons par exemple Jake Wharton ! (Développeur très très connu de la sphère Android)
Signons nos commits
Je veux me faire passer pour lui sur l'un de mes dépôts
Et pour ça... ce n'est pas très compliqué à vrai dire
Tout d'abord, je vais fouiner dans ses dépôts publics et en prendre un au hasard
Prenons Retrofit par exemple, un des plus connus !
git clone https://github.com/square/retrofit hacked_retrofitSignons nos commits
Ensuite, j'affiche les 3 derniers commits par exemple :
git log -n 3
Signons nos commits
Comme vous pouvez le voir, nous avons accès à ses informations d'auteur Git
name: Jake Wharton
email: github@jakewharton.com
Rien de surprenant, ça représente en effet bien l'auteur du commit
Signons nos commits
Mais... qu'est-ce qui m'empêche de mettre les même informations dans ma config ?

Signons nos commits
Et si je fais maintenant un commit :
touch jake_qui_leak_des_mdp.txt
git add jake_qui_leak_des_mdp.txt
git commit -m "coucou c'est jake !"
git log -n 1Que remarquez-vous ?
Il semble que Jake soit bien l'auteur du commit !
Signons nos commits
Pire encore, faites donc un push !

Evidemment, si vous cliquez sur l'avatar de Jake... vous tombez bien sur son compte GitHub
Signons nos commits
OK.... prenons quelques instant pour mesurer à quel point ce qu'on vient de faire est dangereux
Vous le voyez, il est super facile de falsifier son identité sur Git et de se faire passer pour quelqu'un d'autre
Là, si vous venez sur mon dépôt, il est à priori impossible de savoir que j'ai falsifié l'identité de Jake Wharton
Signons nos commits
Attention, pour autant il y a des limites
Vous ne pouvez pas pour autant pousser des modifications sur un dépôt sur lequel vous n'avez pas les droits GitHub
Si je voulais pousser quelque chose sur Retrofit, GitHub me demanderait les credentials de Jake... et là s'arrêterait ma virée de hacker professionnel !
Signons nos commits
Quels sont les cas d'usage malicieux d'une telle pratique ?
Ils sont très nombreux !
- écrire une pull request pour un projet open source en se faisant passer pour quelqu'un de connu
-
introduire du code malicieux dans le dépôt de sa boîte tout en se faisant passer pour un collègue
- etc.
Signons nos commits
Ok, alors comment son image, et protéger sa boîte de telle pratiques ?
Si vous jetez un coup d'oeil aux derniers commits de notre ami Jake sur le dépôts de Retrofit, vous allez tomber sur ce beau petit cadre VERIFIED

Signons nos commits
Eh oui... en fait Jake s'est quand même un peu protégé !
Il a en fait simplement mis en place un système de signature de commits
Signer ses commits lui permet de s'assurer de 2 choses :
- que le code qu'il a push et celui arrivé sur Github sont bien identiques
- que l'auteur est approuvé et que c'est bien lui qui en est la source
Signons nos commits
Alors vous l'avez vu, signer ses commits n'empêche personne d'usurper son identité !
En fait cela permet seulement aux gens de n'accepter QUE les commits signés et donc vérifiés de Jake, aucun autre
Signons nos commits
Bon, c'est bien joli, mais comment on les signe ces commits ?
Signons nos commits
Nous allons pour cela utiliser une signature cryptographique grâce à l'outil GPG
Avant de parler de GPG, un bref rappel sur les signatures cryptographiques
Il existe 2 types d'algorithmes cryptographiques :
- les symétriques
- les asymétriques
Signons nos commits
Dans le cadre d'un algorithme symétrique :
- vous chiffrez votre message avec un mot de passe
- vous donnez ce mot de passe à votre pote
- lorsque vous vous envoyez des messages, c'est ce mot de passe commun (symétrique) qui vous permet de chiffrer / déchiffrer le message
Signons nos commits
Dans le cadre d'un algorithme asymétrique :
Ici, on se base sur le principe de :
- clé publique
- clé privée
Voyez votre clé publique comme un cadenas et votre clé privée comme la clé de ce cadenas
Signons nos commits
Lorsque que votre pote veut vous envoyer un message, il doit :
- chiffrer le message avec votre clé publique (mettre votre cadenas dessus en gros)
- vous l'envoyer
- vous seul pouvez lire le message puisque vous seul avez la clé du cadenas en question !
Signons nos commits
Il est donc capital, dans ce système, de garder précieusement votre clé privée... privée !
Votre clé publique, elle, on s'en fout ! C'est un bête cadenas, de toute manière personne n'en a la clé
Si vous vouliez répondre à votre pote, il vous suffirait d'avoir sa clé publique à lui (son cadenas), de chiffrer votre message avec puis de lui envoyer, etc.
Signons nos commits
Quel système que nous avons vu dernièrement utilise exactement ce principe de cryptographie asymétrique ?
Signons nos commits
Et nos commits dans tout ça ?
Nous allons donc, comme je le disais, utiliser l'outil GPG
GPG (GNU Privacy Guard) est une implémentation très célèbre et open source du OpenPGP qui est un standard mondial sur la cryptographie et pleins d'autres joyeusetés
Signons nos commits
GPG est accessible sur tous les OS, open source, utilise le principe de cryptographie asymétrique, et fais pleins pleins d'autres choses incroyable dont nous ne parlerons jamais mais que je vous invite à regarder pour les plus curieux
Signons nos commits
Je vous laisse donc télécharger GPG sur votre ordinateur
Pour ceux qui ont brew... c'est pas très compliqué :
brew install gnupgSignons nos commits
Nous allons pouvoir ensuite générer une clé !
Pour cela, rien de plus simple :
gpg --full-generate-key- on choisi la première option RSA and RSA
- pour la taille : 4096
- période de validité, perso je mets 0, à vous de voir
- nom & email
- enfin, un mot de passe sécurisé !
Signons nos commits
Pour visualiser vos clés GPG :
gpg --list-secret-keys --keyid-format LONG [email]Le [email] est optionnel et permet juste de filtrer en fonction de l'email si plusieurs clés GPG
Signons nos commits
Voici ce que ça donne chez moi :

La partie intéressante est le : 649AB0C1D11EF0A43980936F03B9376654058A39
C'est ce qui va permettre à Git de savoir quelle clé utiliser pour signer
Signons nos commits
Vous n'avez ensuite plus qu'à mettre les informations qui vont bien dans votre config, soit en ligne de commande, soit directement dans le fichier ~/.gitconfig
git config --global gpg.program gpg
git config --global user.signingkey [ID_DE_VOTRE_CLE]
git config --global commit.gpgsign true
Signons nos commits
On touche au bout !
Il est possible, surtout sur MacOS que vous ayez besoin de faire une dernière manipulation qui permettra à GPG de vous proposer de rentrer votre mot de passe sur votre terminal :
Dans vos variables d'environnements, préciser ceci :
export GPG_TTY=$(tty)Signons nos commits
Allez-y, faites un commit !
Rentrez votre passphrase et HOP, vous venez de signer votre premier commit !
git log --show-signatureCette commande vous permet d'afficher également les signatures lors des logs des commits
Signons nos commits
Enfin, nous allons lier notre clé GPG avec notre compte GitHub !
Pour cela, on récupère la clé publique de notre GPG :
gpg --armor --export [ID_DE_VOTRE_CLE]Signons nos commits
On récupère tout depuis
-----BEGIN PGP PUBLIC KEY BLOCK-----
jusqu'à
-----END PGP PUBLIC KEY BLOCK-----
(compris)
Signons nos commits
Et on va coller ça dans nos settings GitHub !

Signons nos commits
Allez-y ensuite, faites donc un push !
Vous voilà certifiés par GitHub !
Signons nos commits
Il est ensuite possible d'obliger la signature des commits sur des branches spécifiques de votre dépôt GitHub
Pour cela, aller dans :
mon_depot > settings > branches > Add Rule > ajouter la règle correspondante
Les Hooks
Les Hooks
Les Hooks sont des scripts qu'il est possible d'activer et qui seront lancés à des moments clés du "cycle de vie" de Git
L'objectif d'un Hook est d'automatiser une tâche lors des récurrences d'une tâche en particulier
Les Hooks
N'importe quel dépôt git a des Hooks créés par défauts
ls -la .git/hooks/
Les Hooks
Les étoiles indiques que se sont des exécutables
Par défaut, les hooks sont désactivés, il suffit de retirer le .sample pour qu'ils soient reconnus par Git et donc activés
Leurs noms sont plutôt clairs, mais vous voyez qu'il existe des Hooks pour pleins d'occasions spécifiques
Les Hooks
Au hasard :
- pre-commit
Déclenché au moment d'un commit, avant que celui-ci soit réellement pris en compte
- commit-msg
Déclenché au moment d'un commit, une fois que son message a été récuperé, mais toujours pas validé
- Etc.
Les Hooks
Il est donc possible d'écrire des petits scripts qui seront joués par ces Hooks
En soit, il n'y a pas de règles concernant le langage des scripts en question... le tout étant d'avoir le langage sur votre machine
Ceux par défaut sont écris en shell, mais nous allons nous utiliser du Ruby, un peu plus simple pour faire du script basique
Nous n'allons de toute manière rien faire d'incroyable niveau code, donc on s'en fiche un peu
Les Hooks
Mais d'ailleurs...
On va faire quoi en fait ?
Arrivés à ce moment du cours, vous devriez avoir compris que, comme toujours en sécurité, il vaut mieux prévenir que guérir !
La majorité des problèmes de sécurités sont provoqués parce que nous sommes humains, et qu'une erreur d'innatention peut avoir de grosses répercussions
Les Hooks
Ok, et les Hooks dans tout ça ?
Nous allons nous mettre à la place d'une entreprise qui souhaite faire respecter certaines règles à ses développeurs en terme de sécurité sur Git
Pour être sûrs que tous les développeurs respectent les même règles, nous allons automatiser le respect de ces règles, grâce aux Hooks !
Les Hooks
Par exemple, nous allons tenter de vérifier, lors de chaque commit, que le développeur ne commit aucun console.log()
Laisser ses logs dans son code est en effet souvent une mauvaise pratique car ces logs pourraient être visibles en production et comporter des données sensibles sur le logiciel
Les Hooks
C'est un exemple comme un autre, le tout est de comprendre comment faire, vous pourrez ensuite l'adapter à bien d'autres concepts !
Les Hooks
Commençons par installer Ruby sur votre OS
Normalement, tout est expliqué sur le site et l'installation devrait très bien se passer sur les 3 OS principaux
Les Hooks
OK, on peut commencer !
Remplacez le contenu de votre fichier .git/hooks/pre-commit par ça :
#!/usr/bin/env ruby
puts "SALUT !"Les Hooks
Renommez ensuite le nom du fichier en supprimant le .sample
pre-commit.sample devient donc pre-commit
Tentez ensuite un commit, n'importe quoi, et voilà :

Les Hooks
Nous arrivons donc à communiquer avec le développeur
Le commit sera toujours accepté sauf si le programme se termine avec un code de sortie différent de 0
Par exemple :
#!/usr/bin/env ruby
puts "SALUT, tu peux plus commit, cordialement."
exit 1Les Hooks
Tentez de faire un commit... voilà.
Ok, donc on sait :
- déclencher un script lors du commit
- refuser le commit
Il ne nous reste plus qu'à écrire notre algorithme !
Les Hooks
Comment faire pour récupérer les fichiers qui ont été modifiés dans le commit en cours ?
Pour faire cela, nous allons utiliser la commande git diff !
Vous vous en souvenez ? En l'utilisant avec le --cached ainsi qu'un nouveau flag --name-only, on peut récupérer les noms des fichiers modifiés entre le stage et la dernière version
Les Hooks
Modifiez un ou plusieurs fichiers, ajoutez les au Stage puis lancez :
git diff --cached --name-onlyNous récupérons donc la liste des noms de fichiers prêts à être commit !
Les Hooks
Une fois qu'on a cette lite, on va pouvoir s'en servir pour vérifier le contenu de chaque fichier en Ruby
Si un fichier comporte les mots interdits console.log() alors on refuse le commit... et c'est tout !
Allez-y, tentez donc de faire ce petit algo :)
(Cheat Sheet Ruby)
Les Hooks
(c'est pas bien de regarder la réponse sans même avoir essayé, je vous vois)
Voici un exemple de solution :
#!/usr/bin/env ruby
logRegex = /console.log(.)/
filenames = `git diff --cached --name-only`.split("\n")
logFound = false
filenames.each do |fileName|
file = File.open(fileName)
content = file.read
if logRegex.match(content)
logFound = true
puts "[POLICY] console.log() found in file : #{fileName}"
end
end
if logFound
puts "[POLICY] Commit refused, please remove all your logs"
exit 1
endLes Hooks
Allez-y, tentez maintenant de faire des commits avec des console.log(), vous ne pourrez plus !
L'erreur est humaine, et les erreurs d'innatentions sont légions chez les développeurs, même les plus expérimentés !
Grâce aux Hooks, vous automatisez autant de gardes-fous que vous le souhaitez !
Les Hooks
Il nous reste cependant un souci à régler
Vous avez vu, depuis le début, on modifie le fichier pre-commit mais celui-ci ne semble jamais pris en compte par Git, nous ne pouvons pas le versionner
Sauriez-vous dire pourquoi ?
Les Hooks
Parce que le dossier /hooks est un dossier à l'intérieur de votre propre dossier .git/ !
Et on l'a dit au début du cours : le .git/ est un dossier caché qui est le "moteur" de votre dépôt local
Il est donc tout à fait normal que Git ne s'y intéresse pas, il s'agit de votre "moteur" à vous, il n'est pas fait pour être versionné
Les Hooks
Sauf que ça, c'est problématique
En tant que responsable de la sécurité du logiciel (rien que ça), vous aimeriez que tous les développeurs partagent les même règles de sécurité
Chaque développeur pourrait copier/coller le code, etc.
Mais maintenant que vous êtes expert en Git, vous savez que le mieux est que ces Hooks soient eux-même versionnés et partagés via GitHub par exemple !
Les Hooks
Voilà comment on va faire :
Il est possible de modifier le chemin vers le dossier des Hooks
De cette manière, nous allons pouvoir sortir nos Hooks du dossier .git/ et les mettre dans un dossier à la racine du projet, que nous pourrons versionner comme n'importe quel dossier
Les Hooks
Pour préciser un nouveau chemin à Git concernant les Hooks, ça se passe dans la config, et voici la commande :
git config core.hooksPath <monDossier>Nous allons donc créer un dossier .githooks/ à la racine du projet, et lancer ensuite :
git config core.hooksPath .githooksLes Hooks
Ensuite, il n'y a plus qu'à déplacer nos hooks (seuls ceux qu'on utilise vraiment) dans le nouveau dossier !
mv .git/hooks/pre-commit .githooks/On les rend éxecutables :
chmod u+x .githooks/pre-commitLes Hooks
Et voilà !
Votre hook est toujours pris en compte et il est cette fois présent dans un dossier que vous pouvez versionner !
Mais.... il nous reste un dernier (promis) problème
Tentez de faire un commit, rien d'anormal ?
Les Hooks
Notre fichier pre-commit, contenant lui-même un console.log() dans sa regex nous empêche dons de faire un commit... et c'est quand même un peu con
Pour corriger ce souci, nous allons simplement ajouter un filtre dans notre commande git diff :
git diff --cached --name-only ':(exclude).githooks/pre-commit'Les Hooks
OK ! Là, on est enfin bons !
- le Hook n'est pas compris dans l'analyse
- nous analysons tous les fichiers commités
- si on trouve un console.log(), on interdit le commit
- le hook est partagé dans un dossier versionné
Félicitations, vous venez de réaliser un Hook qui peut éviter de nombreuses erreurs d'innatentions !
Les Hooks
Suis-je obliger d'être développeur pour créer des Hooks ?
Non.
Vous l'imaginez, il y a de nombreux développeurs qui ont eu besoin de créer de nombreux hooks
Il existe donc pleins d'exemples de Hooks déjà faits sur internet pour plein d'utilité différentes, il n'y a qu'à se servir !
Les Hooks
Les limites des Hooks
Les Hooks peuvent tout à fait être ignorés par les développeurs
Pour ce faire, ils peuvent simplement changer leur code, ou encore lancer un commit en mode --no-verify par exemple
Les Hooks
C'est pour cette raison que les Hooks ne doivent être qu'un complément de sécurité
Ils servent à rendre la vie plus facile, à éviter les erreurs d'inattentions, etc. Mais n'empêcherons jamais un développeur mal intentionné de les ignorer
Les Hooks
Sachez qu'il est également possible de mettre en place des Hooks côté serveur, et donc beaucoup plus sécurisés car non accessible aux développeurs à priori
Nous n'en parlerons pas dans ce cours mais, pour les plus curieux, vous pouvez voir un tuto sur le site de Git :
Les Hooks
Envie de vous entraîner ?
Voici un scénario qui arrive souvent dans la vraie vie
Dans la plupart des projets IT, les développeurs se basent sur des systèmes de tickets représentants les tâches qu'ils doivent faire
Ce système permet à la gestion de projet de savoir où ils en sont, le temps passé sur une tâche, qui bosse dessus, etc.
Les Hooks
Le développeur doit donc mettre à jour les tickets selon l'avancée de la tâche (pas commencée, en cours, etc.)
Il est assez commun que les entreprises demandent aux développeurs de renseigner la référence du ticket concerné lors d'un commit
Ca permet de retrouver facilement le ticket concerné par les changements en question mais aussi potentiellement d'automatiser des services !
Les Hooks
On peut imaginer plein de système d'automatisation :
- le ticket est automatiquement fermé/ouvert/etc
- le chef de projet reçoit une notification
- etc.
Côté serveur (GitHub), il s'agit de mettre en place un système d'intégration continue, et nous ne verrons pas ça ensemble
Les Hooks
En revanche, pour vous entraîner, vous pouvez essayer d'écrire un Hook qui, déjà en local, forcera l'utilisateur à renseigner un message de commit avec une référence
Par exemple :
- [ref: 42] Add a.txt serait valide
- Add a.txt [ref: 42] serait valide
- Add a.txt ne serait pas valide
Les Hooks
Pour vous aider, le hook à modifier ici semble être le hook commit-msg
Celui-ci reçoit comme argument le chemin du fichier contenant le nom du commit renseigné
Il suffit donc de récupérer l'argument, lire le fichier (et donc le nom du commit), et de faire votre algorithme !
// récupère le 1er argument, le nom du fichier
// contenant le message de commit
commitFile = ARGV[0]BONUS
Le remisage avec git stash
git stash
Le remisage est une pratique qui va permettre de stocker nos modifications dans le but de les ré-appliquer plus tard
Dans quel cas est-ce utile ?
- Vous souhaitez changer de branche mais ne pas perdre le travail en cours (sans pour autant devoir le commit)
- Vous devez faire un petit commit alors même que vous travailler déjà sur quelque chose
git stash
Pour l'exemple, nous repartirons d'un nouveau projet git avec comme commit initial la mise en place du petit site que nous avons utiliser pour le chapitre sur les branches
Téléchargez donc les sources et mettez les dans un dossier dans lequel vous initialiserez ensuite le projet git et ferez votre premier commit
git stash
Une fois que c'est fait, imaginons que nous souhaitions modifier quelques trucs dans l'index.html en changeant par exemple le titre et d'autres infos (on s'en fiche un peu pour l'exemple)
Mais surtout, ne commitez pas, vous êtes en plein dans votre tâche)
git stash
Imaginez maintenant qu'on vous demande d'urgence de modifier le titre de h2 du site et de commit immédiatement la modification
Le problème est que si vous êtes dans un état instable de votre code, le commit est une mauvaise pratique (chaque commit doit représenter un état stable du code)
Or, vous devez commit la modification du titre.. Alorts que faire ?
- Commiter tout, avec les modifications instables ? (NON)
- Effacer toutes vos modifications pour faire la modif et tout reprendre après ? (du temps de perdu)
git stash
C'est là que git stash intervient !
Voyez le comme un petit panier dans lequel vous allez stocker vos changements (trackés) dans l'idée de les appliquer de nouveau ensuite
Allez, y faites donc la commande :
git stashTous les changements que vous n'avez pas commit ont été mis de côté et vous pouvez faire votre commit avec votre modification de titre !
git stash
Le stockage des changements agit sous forme de pile et nous pouvons voir l'ensemble des stashs du dépôt avec la commande
git stash list
On voit que c'est le stash 0 et que ses changements sont basés à partir du commit aa01bc4 sur master
Modifiez le titre et commitez comme demandé
git stash
Nous allons maintenant pouvoir reprendre où nous en étions notre travail !
git stash applyCette commande permet de rejouer le dernier stash sur le commit courant, nos modifications sont donc revenues !
Une fois que c'est bon, vous pouvez supprimer le dernier stash avec
git stash dropgit stash
Imaginons que nous créons plusieurs stash, il est possible de leur donner des noms plus compréhensible avec :
git stash save Work on header
git stash list
Attention, pour les commandes à venir, le véritable identifiant est le label "stash@{numero}" de votre stash, son nom n'étant pas unique
git stash
Pour voir les changements compris dans un stash de la liste (exemple ici avec le premier, le seul) :
git stash show -p stash@{0}Pour appliquer un stash spécifique
git stash apply stash@{0}Pour supprimer un stash spécifique
git stash drop stash@{0}git stash
Pour apply puis drop en même temps, il existe la commande pop qui fonctionne de la même manière (en indiquant un stash en particulier ou en prenant automatiquement le dernier)
git stash pop
// ou encore
git stash pop stash@{0}Cette commande applique le dernier stash et le supprime automatiquement de la liste
git stash
Attention avec le pop, si vous faites un stash pour changer de branche tranquillement, le fait de l'appliquer ensuite peut potentiellement créer des conflits
Il est toujours rassurant d'avoir le stash encore en réserve tant qu'on a pas complètement corriger tous les conflits !
Je conseillerai donc plutôt de rester sur apply puis drop
git stash
Bien sûr, le stash est beaucoup utilisé pour les changements de branche lorsque git vous interdit de checkout à cause d'un Stage non vide
git stash vous permet alors de mettre de côté les changements, switcher sur votre branche puis appliquer ces changements (ou non, mais en tout cas les changements sont bien stockés de manière à part des branches)
BONUS
git rebase pour réorganiser ses commits
git rebase
Nous avons vu que la commande git rebase permet de modifier l'historique afin de l'aplatir lors de fusion de branches
Il est également possible de faire un Rebase sur un commit de notre branche courante
Nous pourrons alors modifier à notre guise les noms, ordre et fusion des commits suivants celui visé
git rebase
Imaginons que nos commits ressemblent à ça :

Les deux derniers commits pourraient être fusionner pour une meilleure lecture car le dernier est juste un oubli
Nous allons utiliser le git rebase !
git rebase
Il faut toujours se baser sur le commit précédent le dernier que nous voulons modifier
Ici, nous souhaitons modifier jusqu'au commit 6035ae1, nous allons donc faire le rebase sur le commit 69a90e7
git rebase -i 69a90e7
git rebase
On remarque toujours que l'ordre des commits a été inversé ! Le commit le plus récent est en bas de liste
Comme pour les branches, si nous voulons fusionner les deux commits, nous n'avons qu'à écrire squash (ou s) à la place du pick sur la seconde ligne
Cela indique à git que nous souhaitons fusionner le second commit avec le premier

git rebase
Si vous sauvegardez et quitter l'éditeur, la modification sera prise en compte !
git rebase nous permet ainsi de modifier énormément de choses dans notre historique !
Prenons un autre exemple
git rebase

Nous souhaitons ici réordonner les différents commits
git rebase -i 1cc93b4Raccourcis VIM pour déplacer le commit du fichier 3 au dessus de celui du fichier 4 : dd k P
Sauvegardez et quittez, tout est bien en ordre !
git rebase
Enfin, ces 4 commits sont un peu inutiles, fusionnons-les en un commit avec un message plus expressif

(Nous utiliserons reword (ou r) plutôt que pick pour éditer le message d'un commit)
git rebase -i 1cc93b4git rebase


Sauvegardez - quittez
Remettez le bon message (comme nous modifions tous les commits du rebase, même le premier, il demande de valider cela par un nouveau commit qu'il va créer)
git rebase

Effacez tout sauf le bon message, et sauvegardez - quittez ... Et voilà !

Git 3ème année SI
By Ecalle Thomas
Git 3ème année SI
Cours sur les bases de GIT orienté Sécurité Informatique
- 1,691