GIT - Utilisation de l’outil

Introduction

Tout d’abord, je me confond en excuse pour cet article, parce que ça va être long… Très long…
Je vais vous y détailler toutes les actions « classiques » possible de l’outil. Je ne peux que vous inciter, si vous savez déjà ce que vous chercher, à utiliser le menu ou directement un coup de recherche ;).

Maintenant que le détail quand à ce qu’est GIT ([voir ici)(/articles/outils/git/), nous allons pouvoir nous aventurer un peu plus sur la technique.

L’outil intègre nativement beaucoup de fonctions, et je pense, vous sauvera la mise une fois que vous l’aurez bien en main.
Ne rigolez pas, c’est du vécu !

Actions de base

On va commencer soft, mais surtout avec les actions de base qui permette de commencer l’utilisation de GIT.

À partir de cette étape, nous allons établir un postula de base, très simple, qui me permettra d’étayer plus facilement mes propos.
Le postula étant le suivant, vous disposez déjà d’un dossier contenant des fichiers et d’autres dossier qui vous voulez gérer avec GIT.
Pour l’exemple, on va prendre en compte l’arborescence suivant :

| gitfolder
   |- file1
   |- fold1/file2
   |- fold2/

Pas plus compliqué, et de toute façon, cela ne serait pas pertinent pour simplement vous expliquer les bases de l’outil.

Init

Nous avons donc notre dossier à traiter avec GIT. Mais nous n’avons toujours rien fait pour dire que nous voulons en faire un dépôt local.

C’est donc la première étape. l’initialisation d’un dépôt local.

Pour ce faire, il n’y a rien de vraiment compliqué, et pour le coup, les commandes sont vraiment intuitives. Positionnez vous dans votre dossier folder

git init

À cette étape, vous avez créé un nouveau dépôt local. On va pouvoir commencer à utiliser GIT pour gérer nos fichiers.

Status

Maintenant que nous avons initialisé le dépôt local, on peut « l’interroger » pour savoir ce que GIT voit dans le workspace

git status
On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be commited)

        file1
        fold1/

nothing added to commit but untracked files present (use "git add" to track)

Wow ! Mais pourquoi autant de choses !
Détaillons un peu :
On branch master : Indique le status de votre branche courante, ici master. On reviendra sur la notion de branche un peu plus tard, pour l’instant pas besoin de détailler.
No commits yet : Ici, on vous indique tout simplement qu’il n’y a pas d’historique, du coup, rien de spécial à indiquer. On en reparlera un peu plus juste en dessous dans la partie Commit.
Untracked files : Là, c’est la partie intéressante. Elle va différer selon l’état dans lequel est votre dépôt, on le vera au fur et à mesure des étapes, mais à cet instant, ce qui vous est indiqué, c’est l’ensemble des fichiers et/ou dossier qui ne sont pas pris en compte par GIT.
Vous noterez que l’on ne voit pas la présence de notre dossier fold2. La raison en est simple, GIT à un comportement qui fait qu’il ne traite que le minimum de données possibles. Donc en fait, vu que notre dossier fold2 ne contient pas de fichier, GIT ne s’en préoccupe même pas. Il y a un moyen assez simple pour contourner ça, c’est d’ajouter un simple fichier vide (personnellement, j’aime bien un .gitkeep pour ça), et vous pourrez conserver une arborescence vide dans un dépôt.
Nothing added … (Ouai, c’est long à réécrire) : Là, rien de méchant, on indique simplement que rien n’a été ajouté pour le prochain commit (c’est juste après ;) ).

Add

Bon à ce niveau, on a un dépôt local initialisé, mais nous n’avons encore rien fait.

La toute première chose à faire est de dire à GIT de gérer les fichiers du workspace.
On va ajouter en premier le fichier file1 :

git add file1

Pas plus, pas moins. Et surtout pas de retour ! C’est normal, c’est que tout c’est bien passé.

À ce niveau, vous pouvez relancer un git status pour voir ce que GIT à fait :

git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

  new file:   file1

Untracked files:
  (use "git add <file>..." to include in what will be committed)

  fold1/

Pour le détail, on voit qu’on a toujours les indications de branche, qu’il n’y a pas de commit, et qu’on a toujours des choses non suivis.

Par contre, ce qu’il y a de nouveau, c’est la partie Changes to be committed.
En fait, GIT nous indique que le fichier file1 a été ajouté à l’index, et il est prêt à être poussé dans le dépôt local.

Commit

Nous passons maintenant à l’étape consistant à envoyer les fichiers indexés dans le dépôt local. C’est l’étape de commit.
Nous avons donc à cet instant ajouté file1 à l’index. Pour l’envoyer dans le dépôt local et ainsi créer une « version » du fichier, on va utiliser la commande de commit :

git commit -m "Initial commit of file1"
[master (root-commit) 9c4a07a] Initial commit of file1
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 file1

On notera l’option -m ici qui permet de chaîner directement un message de commit, qui au passage est obligatoire, associé aux modifications que l’on vient de faire.
Ce que vous raconte GIT sur la sortie de la commande c’est la chose suivante : master (root-commit) : sur la branche master, le commit de référence.
9c4a07a : Le hash (l’identifiant unique) du commit, vous verrez ça dans la partie Log un peu plus en détail, cela va permettre d’identifier et naviguer facilement et rapidement dans l’historique. Attention, ce hash sera différent pour vous ! Et il sera différent à chaque commit que vous générerez.
Initial commit of file1 : Bon, là, ça se passe de commentaire. c’est le titre de votre commit.
1 file changes, 0 insertions(+), 0 deletions(-) : C’est assez parlant, 1 fichier modifié, 0 insertion dans les fichiers, 0 suppression dans les fichiers. En fait, si on analyse, c’est simplement qu’on ajoute un nouveau fichier que GIT ne connaissait pas. (Et effectivement, c’est le cas parce que c’est notre premier commit !).
create mode 100644 file1 : Là, c’est juste le détail sur le fichier que l’on vient de pousser dans le dépôt local. On a pas vraiment besoin de s’attarder là, c’est juste informatif.

Il est possible de renseigner de message de façon interactive en lançant simplement :

git commit

En faisant ça, votre éditeur de texte favoris va s’ouvrir. Je vous invite à vérifier votre variable d’environnement $EDITOR avant de lancer la commande, au risque de vous retrouver avec un éditeur que vous ne connaissez pas !
Quand vous aurez validé votre message de commit, vous aurez la même sortie.

Autre chose, et c’est là que le commit en mode interactif est assez sympathique (Et surtout c’est plus pratique que de le faire en commande directe), c’est que l’on peut faire un message de commit un peu plus élaboré.
Qu’est-ce que j’entends par là ?
Dans la commande, j’indique Initial commit of file1, et je vous ai fait passé en douce l’info que c’est le titre du commit. C’est effectivement le cas !

Dans un commit élaboré, on va pouvoir donner foule de détail en plus du titre, qui lui doit être un minimum succinct. Si je vous donne un exemple :

Add first steps of page and reorg themes

- Introduction
- Base action
- First steps of init

Ça, c’est ce que j’ai renseigné dans un commit en mode interactif. Le titre de mon commit est donc « Add first steps of page and reorg themes », et tout ce qui suit et le détail des actions que j’ai réalisé sur les fichiers qui ont été modifiés. Cela va simplement permettre de comprendre facilement les modifications qui ont été faites.


À partir de ce moment, vous en savez globalement assez pour l’utilisation « basique » de GIT. Mais bon, certains seraient capable de me dire « Ça fait vraiment compliqué et c’est lourd pour gérer des versions de fichier. »
Ben… Oui, clairement, je suis entièrement d’accord avec vous ! Mais bon, comme je le disais précédemment, GIT est beaucoup plus élaboré que la simple copie de fichier. Déjà par le système de commit qui permet d’avoir un historique indéfini (Voir §Log), mais aussi parce qu’il permet de « sortir » des copies de votre dépôt ailleurs.

Avec un dépôt distant

Aller, on attaque direct !
Donc les dépôts distants, c’est quoi ? Dans le détail de la chose, je vous renvoi vers le paragraphe correspondant d’un autre article.
En gros, c’est la copie de votre dépôt local sur un serveur différent. L’avantage étant l’accès multiple au même choses par plusieurs personnes.

Tiens, mais c’est pas un aspect collaboratif ça ? Et bien oui exactement. Sans ce bout là de GIT, la collaboration à un projet serait beaucoup plus complexe.
Un dépôt distant étant la référence commune à tout le monde pour le même projet.

Je passerais sur l’initialisation d’un dépôt dans cet article, au besoin j’y reviendrais dans un autre, mais mon conseil reste d’utiliser une forge logicielle qui est, à mon sens le moyen le plus confortable de gérer des dépôts distants.

Mais comment on s’en sert ? Et bien… C’est juste en dessous !

3, 2, 1, …

Remote

La toute première chose à faire pour pouvoir travailler avec un dépôt distant, c’est de créer le dépôt distant.
Pour ce faire, utilisez votre forge logicielle.

Pour l’exemple nous allons créer le dépôt sur la cible http://forge.example.org/user/gitfolder.

Une fois que c’est fait, il faut ajouter le dépôt distant à notre workspace.

git remote add origin http://forge.example.org/user/gitfolder

Rien de bien complexe non ?
Pourquoi origin ? C’est arbitraire en fait. On pourrait nommer le repository n’importe comment.
Seule la convention générale veut que le dépôt distant « général » s’appelle origin.

Typiquement rien ne vous empêche d’ajouter une deuxième cible

git remote add origin http://forge.example.org/user/gitfolder2

Mais bon, pour l’usage « de base », pas vraiment d’intérêt.

Push

Maintenant que vous avez configuré votre dépôt distant, l’étape qui suit et d’envoyer votre dépôt local vers le distant. Logique.

git push origin master

Cette simple commande vous permettra d’envoyer l’ensemble du contenu de votre dépôt local vers le dépôt distant.

Vous devriez avoir ce genre de sortie :

$ git push origin master
Username for 'http://forge.example.org': user
Password for 'http://user@forge.example.org':
Counting objects: 3, done.
Writing objects: 100% (3/3), 225 bytes | 225.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To http://forge.example.org/user/gitfolder.git
 * [new branch]      master -> master

Vous noterez qu’on utilisateur et un mot de passe vous seront demandé. C’est assez logique d’ailleurs si vous utilisez une forge.

Une chose intéressante : * [new branch] master -> master
Là, c’est une information assez importante quand même, GIT vous explicite qu’il crée une nouvelle branche master sur le dépôt distant, depuis votre branch locale master.

Je ne traînes pas sur l’histoire des branche de suite, on en parle juste un peu plus bas.

Pull / Clone

Bon, avoir un dépôt distant c’est bien. Avoir envoyer son dépôt local dessus c’est mieux (Sinon c’est pas vraiment utile). Mais pouvoir récupérer ce qu’il y a dessus, c’est le top ! Surtout dans le cas où on est plusieurs à travailler sur le même dépôt.

Quid entre le pull et le clone ?
Rien de plus simple dans les faits.

Si vous n’avez pas encore de dépôt local, il vous faut cloner le dépôt distant :

git clone http://forge.example.org

Vous avez donc une copie exacte de ce que contient le dépôt distant dans votre dépôt local.
Ça, c’était pour le clone. Initialisation d’un dépôt local depuis un dépôt distant en somme.

Pour l’histoire du pull, cela implique que vous ayez déjà un dépôt local (correspondant bien sur), entier ou non.
C’est dans le cas du dépôt non entier que c’est intéressant.
Si vous souhaitez travailler sur la dernière version de ce que contient votre dépôt distant, on lance la commande suivante dans le dossier contenant notre dépôt :

git pull origin master

On doit voir quelque chose dans le genre :

Username for 'https://git.fricouv.eu': user
Password for 'https://vfricou@git.fricouv.eu':
From https://git.fricouv.eu/user/gitfolder
 * branch            master     -> FETCH_HEAD
Updating 9c4a07a..dcdbade
Fast-forward
 fold1/file2 | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 fold1/file2

Ce que ça nous raconte, outre l’authentification et l’URL de votre dépôt c’est la chose suivante :

  • * branch master -> FETCH_HEAD On récupère le dernier index de la branche master.
  • Updating 9c4a07a..dcdbade On met à jour le commit 9c4a07a (le précédent) avec le nouveau et dernier (dcdbade).
  • fold1/file2 | 0 Le fichier file2 est créé.
  • create mode 100644 fold1/file2 Le fichier file2 est créé avec les droits 100644.
  • 1 file changed, 0 insertions(+), 0 deletions(-) Ça c’est un compte rendu de ce qui est fait dans le dépôt.

Voilà, pas vraiment plus que ça ;).

On se retrouve plus tard avec un petit cas spécial, le Merge.

Notions d’arbres

GIT introduit une notion assez particulière, mais néanmoins vraiment pratique, les branches.
On va voir tout ce qui est associé à ça, parce que ça peut être un minimum touffu (Comme une branche feuillue quoi !).

Branch

La première question qu’il est naturel de se poser c’est la suivante : « Qu’appelle-t-on une branche ? ».
C’est là toute la ressemblance avec un arbre.

Si on fait l’analogie, un arbre est composé d’un tronc, de sève et de branche. (On passera les feuilles, pas d’intérêt ici.)
Si on se ramène à GIT, c’est le même principe.
Le tronc, c’est le code principal, par convention celui qui est sur master. Parce que oui, master est une branche, comme on pourrait dire que le tronc d’un arbre en est la branche principale.

Sur un arbre, les branches prenne naissance sur le tronc, et par connexion, la sève circule dans les branches.
Dans GIT on crée une branche à partir d’une base, pour expliquer le cas, la base sera master, après, ça devient trop complexe.
On va donc retrouver dans la nouvelle branche, la copie identique du contenu de master.

Au fil du temps, le contenu de la branche évolue, change, etc… Comme une branche d’arbre qui se développe.
Mais dans l’idée, même si la branche évolue, on va quand même y retrouver des « bouts » de ce qu’il y a dans la référence (master), même si certains cas font que ça ne sera pas toujours le cas.
Pour en revenir à mon arbre, on va dire que ça s’apparente à la sève, parce que même au bout de la branche aussi longue soit-elle, la sève reste la même que celle qui circule dans le tronc.

Je vous entends de là !
« C’est bien beau ton analogie aux arbres, mais bon, ça ne nous dis pas comment on fait pour utiliser un branche ! »

Et bien il y a deux méthodes, une conventionnelle, et une abrégée :
Forme conventionnelle :

git branch devel

Bon, j’avoue que dans ce cas, GIT est un peu con, parce qu’il ne vous dit strictement rien !
Mais pour voir si c’est fait on fait un simple petit :

git branch
* master
  devel

Oh ! Magie, on a une branche « master » et une autre qui s’appelle « devel » ! Normal, c’est celle que l’on vient de créer !
L’astérisque à côté de « master » que l’on voit est un indicateur pour nous dire sur quelle branche est positionné notre dépôt local.

Pour basculer d’une branche à une autre, il faut voir le paragraphe juste en dessous, le checkout. Je spécifie un paragraphe exprès pour parce que ça fait plusieurs choses !

On a également l’autre forme pour crée une branche, l’abrégée. Pourquoi l’abrégée ? Parce qu’en fait elle fait tout, elle crée la branche et elle bascule dessus.

git checkout -b devel

Tiens un checkout ! Ouai bon, on en cause en dessous ! Juste pour vérifier ce que je vous racontais au dessus, si on affiche les branches on se retrouve avec ça :

git branch
  master
* devel

Aller on y va sans attendre.

Checkout

Donc, nous voilà au cas du checkout.

Rapidement, on reprends la partie que l’on a vue au dessus. Le changement de branche.
Lorsque nous avons créé une branche « devel » plus haut, nous avions vu que l’on ne bascule pas automatiquement d’une branche à un autre.
C’est là que l’on va utiliser le premier cas de « checkout ».

Pour rappel nous sommes dans la configuration de branche suivante :

git branch
* master
  devel

Si on veut se positionner sur la branche devel, il faut donc utiliser git checkout de la façon suivante :

git checkout devel

Et comme souvent, GIT n’est pas bavard… Mais si on regarde on est maintenant sur la branche devel :

git branch
  master
* devel

Annuler des modifications

Un autre avantage de GIT c’est de pouvoir annuler d’un coup les modifications qui ont été faites depuis le dernier commit.
Nous avons notre fichier file1 actuellement vide. Il a été poussé dans le dépôt tel quel.

Maintenant, on va y ajouter du contenu pour voir comment annuler une modification :

echo "Texte que l’on va annuler" > file1

Si on affiche l’état du dépôt, on a la chose suivante :

git status
[…]
  modified:   file1
[…]

On voit bien que le fichier file1 a été modifié (et encore heureux d’ailleurs parce que c’est ce qu’on vient de faire).
Bon, finalement, ce que l’on a ajouté ne va pas du tout ! Il faut donc revenir en arrière. C’est là qu’opère la magie de GIT

On va simplement faire revenir le fichier que l’on vient de modifier au dernier état connu dans le dépôt :

git checkout file1

Maintenant un petit affichage de l’état pour voir que le fichier est revenu à l’état précédent.

git status
[…]
nothing to commit, working tree clean

(Et si vous ne me croyez pas et que je croyez pas GIT non plus, affichez votre fichier ;) )

Et si on a modifié pleins de fichiers dans le dépôt et qu’on veut revenir en arrière sur l’ensemble ?
Ben… C’est prévu aussi !

L’action se fait un niveau le plus haut du dépôt. Et c’est bête si on fait du GNU/Linux depuis longtemps, il faut utiliser le méta dossier « ici » (Le . quoi en fait).

git checkout .

Comme je vous le disais, l’action checkout à encore une autre fonction, mais pour cela, il faut que je vous cause d’abord de l’historique pour vous en parler plus en détail.

Merge

Avoir des branches c’est bien, mais au final, le but est d’alimenter le tronc ! (Et zut il repart dans ses métaphores sur les arbres !)

Ouai, dans l’idée, « master » doit être la branche de référence et c’est elle qui doit comporter l’ensemble se ajout/suppressions/….
Les branches « annexes » ne devraient en théorie pas rester en place après avoir fini les modifications dessus.

L’action de GIT qui vous permettra de ramener le contenu de votre branche vers la branche master c’est « merge ».

En faisant ça, l’ensemble du contenu de votre branche sera ramené dans votre branche « master » en ramenant l’ensemble des commits. Ou une autre option, c’est de ramener l’ensemble des modifications dans un seul commit.

Pour faire les tests, je vous invite à faire les chose suivantes :

git checkout devel
echo "Line 1" >> file1
git commit -am "Add 1 line to file1"
echo "Line 2" >> file1
git commit -am "Add second line to file1"

Ça va juste ajouter deux ligne dans votre fichier « file1 » et faire un commit pour chaque.

Ramener l’ensemble des commits

Pour ramener toute la liste de commit de la branche (ce que je vous préconise, et on vera pourquoi juste après), on va lancer la commande suivante :

git checkout master

git merge devel
Updating dcdbade..529c85c
Fast-forward
 file1 | 2 ++
 1 file changed, 2 insertions(+)

Donc on update le commit « dcdbade » par le commit « 529c85c » (Pensez que les hash ne seront certainement pas les mêmes chez vous).


```1 file changed, 2 insertions(+)``` Ça, c’est un « compte rendu » de ce qu’a fait le merge, 1 fichier modifié et deux insertions.

Si vous faites un ```git status``` vous verrez que vous n’avez aucun fichier en attente de commit.

Maintenant, votre branche master comporte les deux commits que vous aviez fait sur votre branche devel.

#### Ramener l’ensemble des modifications en un seul commit

On va réalimenter la branche devel pour vous monter ça :

```bash
git checkout devel
echo "Line 3" >> file1
git commit -am "Add third line to file1"
echo "Line 4" >> file1
git commit -am "Add fourth line to file1"

Voilà, à ce stade, la branche devel à 2 commit de plus que la branche master. Maintenant, on merge, mais avec une petite option :

git checkout master

git merge --squash devel
Updating 529c85c..f2942cf
Fast-forward
Squash commit -- not updating HEAD
 file1 | 2 ++
 1 file changed, 2 insertions(+)

Grosso modo, on a les mêmes infos qu’avant sauf une ligne Squash commit -- not updating HEAD et c’est bien le not updating HEAD qui nous intéresse.
ce message nous dit que le merge n’a pas mis à jour la branche master.
Effectivement, si on affiche le status du dépôt on va voir ça :

git status
[…]
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  modified:   file1

Ce qui nous dit GIT c’est en effet que le fichier « file1 » a été modifié, et qu’il est prêt à être commité. Si vous affichez son contenu, vous retrouverez les 4 lignes que vous avez ajouté précédemment sur votre branche « devel ».


La navigation dans les versions

Bon, maintenant que vous savez manipuler des fichiers dans un dépôt, les branches, etc… Il est temps de voir la console du « Tardis ».
Déjà, je vais vous blazer un peu, point de console graphique ici, et point de Daleks ou de Cybermen non plus.

Pourquoi je fais allusion à cette série que peu de geek ne connaissent ? Et bien parce que ce que l’on va voir s’apparente de très prêt à du voyage temporel, mais uniquement pour le contenu de votre workspace malheureusement…

Log

En tout premier lieu, il va falloir savoir ce qu’il s’est passé dans dans l’histoire. C’est là ou les commits vont nous aider, et vous allez également comprendre pourquoi je vous disais plus haut pourquoi il est nécessaire d’avoir des messages explicites.

Pour afficher l’historique, on va utiliser l’action « log » :

git log
[…]
commit 529c85ca23b11939ac33810890f7a52b2b76774b
Author: Prénom NOM <adresse@email.tld>
Date:   Sat Jun 2 10:13:38 2018 +0200

    Add second line into file1
[…]

Voilà ce dont ça à l’air. Vous avez donc un message de ce type par commit.
Dans le détail, on retrouve plusieurs choses :

  • commit 529[…] c’est ça le fameux « hash » de commit dont on parle depuis un moment. C’est un identifiant unique lié à votre commit.
  • Author: Comme son nom l’indique, c’est l’auteur du commit. Normalement, pour vous, ça devrait être vous.
  • Date : Bon, ça se passe de commentaires
  • Add second […] Et c’est ça le plus important ! C’est votre message de commit. Et c’est ça qui va vous indiquer ce qui a été fait/modifié/ajouté/supprimé dedans. D’où le besoin d’explicitation.

Plus vous serez clair dans le message de commit, plus il vous sera facile de comprendre ce qui a été fait sans foule de manipulations.
Ah ! Pensez à une chose… C’est multi-lignes, donc vous pouvez y aller ! Si vous voulez mettre beaucoup de détail, je vous conseille fortement de ne pas utiliser l’option -m de l’action commit, ça sera beaucoup plus simple parce que vous travaillerez dans un éditeur.

Checkout

Sauts dans le temps

Maintenant que l’on sait ce qu’il s’est passé dans l’histoire, on va pouvoir regarder ça de plus près.
Je pense que vous avez assez suffisamment vu de film ou lu de livre qui parle des voyages dans le temps avec leurs fameuse règle d’or « Surtout vous ne devez pas modifier quelconque élément dans le passé sous peine de changer drastiquement le présent. ».
Et bien, pour faire cour, c’est pareil.

Naviguer dans le temps avec des checkout, c’est revenir dans le passé, tout en conservant les informations du présent en tête.

L’utilité de ce procédé étant de retrouver l’état à un instant passé d’un fichier, de code, de configuration ou tout autre chose étant stocké dans votre dépôt.

Bon aller, on repart dans le fonctionnel.
Dans notre historique nous avons les choses suivantes :

commit 498048b1ca97c93b2a030995008511782ee7ba28
Author: Prénom NOM <user@domain.tld>
Date:   Thu Jun 7 20:15:57 2018 +0200

    Add lines

commit 529c85ca23b11939ac33810890f7a52b2b76774b
Author: Prénom NOM <user@domain.tld>
Date:   Sat Jun 2 10:13:38 2018 +0200

    Add second line into file1

commit c224fdd4ada8a1b615d53e5b99135e89fafacf48
Author: Prénom NOM <user@domain.tld>
Date:   Sat Jun 2 10:12:37 2018 +0200

    Add text in file1

commit dcdbade64e6c594dfc031ec5d1fd86e580f09e97
Author: Prénom NOM <user@domain.tld>
Date:   Mon May 28 19:04:46 2018 +0200

    Add fold1

commit 9c4a07a4b8a2ac2a9530ac0b2192b816f91a182c
Author: Prénom NOM <user@domain.tld>
Date:   Sun Apr 1 21:24:21 2018 +0200

    Initial commit of file1

Mazette ! Ça en fait des choses ! (Ou pas quand on a l’habitude de travailler avec GIT)

Dans l’idée, on est donc tout en haut « Add lines ». Ouai, je sais le commit message est pourri, mais c’est un dépôt de test pour vous donner les examples pour cet article, donc dans l’idée, il va vire rapidement ;).

Ceci étant, je veux savoir quel était le contenu exact de mon dépôt lors de l’ajout de dossier « fold1 ».
Ben c’est parti ! (et vous allez voir c’est méga simple)

git checkout dcdbade64e6c594dfc031ec5d1fd86e580f09e97

Bon, la vous devez avoir eu un bon petit message vous rappelant que les saut dans le temps c’est dangereux et qu’éventuellement vous pouvez créer une branche à partir de ce commit.
Bref, ce qui est vraiment intéressant c’est ça « You are in ‘detached HEAD’ state » ! « Vous êtes dans un état détaché de HEAD », pour rappel « HEAD » c’est le dernier commit que vous avez fait (Dans le présent).

Un petit coup de git log nous dira effectivement que l’historique s’arrête au commit sur lequel nous sommes revenu. Logique.

Je vous laisse vérifier votre contenu du dépôt, vous allez voir qu’effectivement nous sommes revenu dans le temps.

Bien, c’est pas tout, mais maintenant, on veut pouvoir revenir dans le présent ! « 2.21 GigoWatt tu te rends compte ?! » ! Et zut… J’ai encore glissé une boutade !
Bon, non, vous n’aurez pas besoin de quoi que ce soit, si ce n’est la commande appropriée que voici :

git checkout master

Ça c’est le côté pratique, vous qu’on s’est juste détaché du présent pour voir comment est le passé, on sait toujours où est la référence présente. Notez toutes fois que ici « master » est master parce que c’est la branche sur laquelle nous sommes. Si nous étions sur une autre branche, il faudrait bien sur utiliser le nom de la dite branche.

Correction

Bon, là on est plus dans les sauts dans le temps, on reste dans le présent.

Vous êtes en train d’avancer votre code, mais tout ce que vous avez fait, bah… Marche pô…
Et là, c’est potentiellement le drame si vous n’aviez pas fait de copie originelle de fichier avant modifications.

Bon, je vous arrête de suite, ce fonctionnement de copier l’original, copier la copie, etc… OUBLIEZ ! Vous avez maintenant entre les mains un outil qui fait tout ça pour vous !!!

Bah ouai, ça sert à quoi de mettre tout son taf dans un dépôt qui fait limite le café pour les pauses s’il n’est même pas foutu de faire un truc aussi simple qu’effacer vos dernières modifications qu’ontoutcassé ? Bah ouai, à rien, donc, c’est prévu !

On va juste ajouter une ligne dans notre fichier file1, ou même mieux, on l’a écrasé totalement (Oh la misère).

echo bla > file1

Oups ! Pas de problème, tans que vous n’avez pas commité ce changement, on va pouvoir gérer très facilement !

Alors deux cas ce présentes à nous:

  • Vous n’avez modifié qu’un seul fichier

Rien de compliqué, il suffit de réinitialiser le fichier avec la dernière version connue dans le dépôt :

git checkout HEAD -- file1

Magie, votre fichier « file1 » est revenu à votre dernière version commité dans le dépôt avant que vous ayez fait votre boulette.

  • Vous avez modifié pleins de fichiers et vous avez la flemme de vous les faire un par un (Ouai ça peut être long dans ce cas, mais no problemo, c’est prévu aussi)
git checkout .

Là, en fait on a simplement dit à GIT « Remet moi dans le dernier état que tu connais le dossier courant ».
« Dossier courant » ? Oui oui ! J’ai bien dit dossier courant, ce qui implique que vous ne pouvez remettre en état qu’une partie de votre workspace.

Je crois qu’on va s’arrêter par là pour le cas des checkouts, ça fait déjà beaucoup de choses fort utile pour un premier jet.

Reset

Je ne vais pas trop m’attarder sur la partie reset, ce que vous avez surtout à savoir c’est que c’est ça qui va vous permettre de revenir définitivement dans le passé pour recommencer l’histoire.

Utiliser l’option reset (enfin de la façon dont je vous la présente là), revient à revenir à un commit passé et supprimer définitivement la référence au présent de votre dépôt.

Pour l’historique, je vais garder celui que l’on a vu plus haut.

Mettons que l’on veut revenir au premier ajout de texte dans « file 1 » parce que ce qu’il y a après n’est pas valable et ne le sera jamais.

On va dire à GIT que l’on veut se repositionner sur le dit commit et de supprimer le reste de l’historique jusqu’au présent :

git reset --hard c224fdd4ada8a1b615d53e5b99135e89fafacf48
HEAD is now at c224fdd Add text in file 1

Si tout ce passe bien GIT vous dit que « HEAD » est maintenant positionné sur le commit « c224fdd » avec le commentaire « Add text in file 1 ».

Si vous affichez à nouveau l’intégralité de votre commit log, vous allez voir que tous ceux qui étaient après le c224 n’existent plus :

git log

commit c224fdd4ada8a1b615d53e5b99135e89fafacf48
Author: Prénom NOM <user@domain.tld>
Date:   Sat Jun 2 10:12:37 2018 +0200

    Add text in file1

commit dcdbade64e6c594dfc031ec5d1fd86e580f09e97
Author: Prénom NOM <user@domain.tld>
Date:   Mon May 28 19:04:46 2018 +0200

    Add fold1

commit 9c4a07a4b8a2ac2a9530ac0b2192b816f91a182c
Author: Prénom NOM <user@domain.tld>
Date:   Sun Apr 1 21:24:21 2018 +0200

    Initial commit of file1

Nous sommes donc, du point de vue du dépôt local, revenu dans le temps.

Blame

Une dernière fonction fort intéressante, enfin si vous voulez vous battre avec vos collègues en fait !

Qui n’a jamais rêvé de savoir qui avait écrit/modifié une ligne dans du code ?
Qui n’a jamais rêvé d’aller voir son collègue pour l’engueuler proprement parce qu’il avait fait une connerie ?

Bref…

GIT étant votre amis (et pas celui de votre collègue), il vous permet de savoir qui a écrit/modifié une ligne dans le fichier.
Personnellement je vois le côté pratique, pas le côté remontrances que l’on peut mettre derrière, mais je suis un grand optimiste.

Bref (again) vous allez comprendre pourquoi je fais cette boutade juste en voyant le nom de la fonction !

Comment qu’on fait ça ? Et bien, c’est tout simple, c’est une option de git « blame ».

Et oui… « Blame »… Reprocher, blâmer en bon Français. C’est assez paradoxal non ?

Bon, l’exemple ici ne sera pas super probant vu que nous n’utilisons qu’un seul utilisateur depuis le début.

Si on utilise blame sur un fichier, par exemple « file1 » on va obtenir quelque chose comme ça :

git blame
c224fdd4 (Prénom NOM 2018-06-02 10:12:37 +0200 1) Texte que l’on va annuler

Si on décompose un peu la seule ligne que l’on a, on voit les champs suivant :

  • c224fdd4 : Hash du commit où le texte a été modifié en dernier.
  • Prénom NOM : Ça, ça parle de lui même, c’est l’auteur du commit.
  • 2018-06-02 10:12:37 +0200 : Dans l’ordre, Date, Heure, Timezone (Le +0200 correspondant au fuseau horaire GMT+2)
  • 1 : Le numéro de la ligne
  • Texte ……… : Le contenu de la ligne (En bref si c’est trop long).