Devenir efficace avec Git

ℹ️ These slides are also available in English!

👩‍💻 Version autonome (pour lecture en solo)

Git, kézako ?

Un système de contrôle de version (VCS) distribué

Système de contrôle de version

= système permettant de gérer différentes versions d'un ensemble de fichiers

(Beaucoup de versions intermédiaires entre deux releases !)

Souvent utilisé pour travailler à plusieurs sur un projet... entre autres !

Autres VCS

  • Subversion (SVN)
  • Perforce (p4)
  • CVS
  • Mercurial
  • Bazaar

Ce que Git n'est pas

Git ≠ GitHub, GitLab, Gitea, etc.

Git = outil logiciel (en ligne de commande)

GitHub et GitLab = services d'hébergement de dépôts Git

Linux ≠ OVH, par exemple

Pourquoi utiliser Git ?

Bénéfices sur plusieurs niveaux :

  1. Système de backup
  2. Travail par «branches»
  3. Travail collaboratif

Ça vaut le coup !

Faire des backups avec Git

Commençons avec une parenthèse sur le mot «distribué»

Vous avez peut-être entendu dire que Git était un système de contrôle de version distribué.

Qu'est-ce à dire ?

Deux types de VCS

Centralisé
Toute action sur le repo requiert un accès au serveur (Subversion, Perforce, etc.)
Distribué
Aucune copie du repo n'est distincte (Mercurial, Git, etc.)

Intérêts d'un système distribué

  • Chaque développeur possède une copie complète1 du repo, pas juste le serveur.
    ➔ Chouette, des backups pas chers !
  • Les développeurs peuvent travailler même hors ligne !
    (On reviendra plus tard à la résolution de conflits)
1 Pour plus de détails, voir cette présentation de Linus Torvalds à Google.

Concepts de base

Parlons peu mais parlons graphes

❗️ Promis, rien de compliqué ! (il y aura plein d'images)

Git est basé sur un graphe.

Qu'est-ce qu'un commit ?

  • Un message de commit
  • Un auteur (nom + adresse mail)
  • (Quelques autres métadonnées...)
  • Un ensemble de fichiers et leurs contenus
  • Des «flèches» vers son/ses parent(s)

Un commit est identifié de manière unique par son hash.

Un hash ? Ça se mange ?

Toutes les informations d'un commit, y compris le contenu des fichiers, sont passées à une fonction de hachage pour obtenir son hash.

Principe d'une fonction de hachage : on lui passe des données (une suite d'octets), elle retourne un nombre («hash») ; deux entrées identiques ⇔ deux hashs identiques.

(Plus d'infos sur Wikipédia pour les curieux)

Les hashs de commits

Le hash d'un commit est un très grand nombre, présenté en hexadécimal : 6828f7bf493cd4c9c332ea769e6e38fbbe258821.

Les hashs sont souvent raccourcis (par défaut à 7 caractères) : 6828f7b, c'est ce qu'on utilisera dans ce cours.

Des «pointeurs»

Il n'y a pas que les commits qui pointent sur des commits.

f37c942 984b311 v1.7.10 c4fe9cc 700aced master HEAD 150dab6 network-fixes

Il y a aussi des branches, des tags, et quelques autres choses. (On parlera de leurs différences plus tard)

Manipuler le graphe

Créer un commit

f37c942 984b311 c4fe9cc

Pour créer un commit...

... on l'ajoute simplement au graphe.

C'est tout !

Il n'y a pas de piège, on ne fait jamais qu'ajouter des commits au graphe.

Parlons tout de même de ce qui se passe quand on le fait.

HEAD

HEAD désigne le commit qui est actuellement checked out.

C'est-à-dire, il s'agit du commit dont le contenu (les fichiers) est actuellement présent dans le répertoire.

On peut considérer le commit pointé par HEAD comme «là où on se trouve actuellement».

HEAD

Et quand on crée un nouveau commit ?

f37c942 984b311 HEAD c4fe9cc HEAD

HEAD suit le nouveau commit (il est automatiquement checked out).

Branches

Et quand on crée un nouveau commit ?

f37c942 master 984b311 develop crash-fix HEAD c4fe9cc crash-fix HEAD

Une branche suit le commit si et seulement si elle est checked out.

Tags

Un tag est inamovible et ne peut pas être checked out, il ne suit donc jamais un nouveau commit.

(Pour «déplacer» un tag, il faut le supprimer et le re-créer ailleurs.)

➔ Une branche sert à suivre quelque chose (développement d'une fonctionnalité...) ; un tag sert à marquer un commit particulier (version...)

Parlons commandes

Essayez d'éviter les interfaces graphiques si possible.

(Au moins au début.)

Par exemple, leur gestion des erreurs est souvent hasardeuse...

Créer un nouveau dépôt Git

		$ git init

Crée un nouveau dépôt dans le répertoire courant.

Qu'est-ce qui fait un dépôt Git ?

Réponse : le répertoire1 .git.

  • Git ne stocke rien en dehors de ce répertoire.
  • On peut librement déplacer le répertoire parent, Git ne stocke aucun chemin absolu.
  • Git le cherche également dans tous les répertoires parents du répertoire courant.

1 Dans certains cas c'est un fichier.

Créer un commit

Apparemment il y a eu une erreur ?

Créons quelques fichiers.

«Où en suis-je ?»

Parlons staging

Promis c'est le dernier truc

Git permet de choisir quelles modifications vont être enregistrées dans le prochain commit.

On le fait via la commande git add suggérée par le message d'aide plus tôt.

Éditeur interactif

On vient de voir git commit ouvrir un éditeur de texte.

Éditeur de texte utilisé par les commandes Git. Cette valeur est intérprétée par le shell quand elle est utilisée. Exemples : ~/bin/vi, $UNE_VARIABLE_D_ENVIRONNEMENT, "C:\Program Files\Vim\gvim.exe" --nofork. L'ordre de préférence est la variable d'environnement $GIT_EDITOR, puis la configuration core.editor, puis $VISUAL, puis $EDITOR, puis la valeur par défaut choisie à la compilation, qui est habituellement vi.
Source : documentation de GIT_EDITOR dans git-var.

Changer la configuration

L'éditeur utilisé par défaut est vi, qui a une ergonomie... particulière.

Pour le changer pour nano (par exemple) :

			$ git config --global core.editor "nano"
Positionner EDITOR dans son .bashrc/.zshrc fonctionne aussi.
				# ...
				export EDITOR=nano
				# ...

Utiliser un éditeur graphique

Oui c'est possible !

Il faut cependant s'assurer que la commande ne quitte que quand le fichier est fermé :

Sublime Text
$ git config --global core.editor "subl -w"
VS Code
$ git config --global core.editor "code -w"

La collaboration

Git sur sa machine = outil de backup (et plus)

Git sur plusieurs machines = 🤯

Principe

Chaque machine contient un dépôt Git. Répertoire .git, etc.

On peut «pousser» des modifications vers une autre machine, et «tirer» des modifs depuis.

origin 6846ef5 master ac2b311 1234567 master 3d5f4a2 master tsfe01 $ git init $ git commit $ git push $ git pull $ git commit $ git push 6846ef5 master ac2b311 1234567 master 3d5f4a2 master tsfe02 $ git clone $ git commit $ git commit $ git push 6846ef5 master ac2b311 master 1234567 master

Résumé

  • Pour créer un nouveau repo à partir d'un existant: git clone
  • Pour rapatrier les mises à jour depuis un repo distant : git pull
  • Pour publier ses modifications : git push

Un peu plus de terminologie

Git modélise les machines distantes via des remotes. («Remote» en anglais = «distant»)

Une remote = un certain repo sur une certaine machine (grosso modo).

On gère les remotes via git remote !

Remotes & refs

origin ac2b311 master 6846ef5 develop tsfe01 6846ef5 develop 06adada fix-tests tsfe02 ac2b311 develop 24a8c81 lts-fixes develop origin/develop tsfe02/develop

git fetch

Git ne va pas faire des requêtes à chaque commande.

  • Économe en bande passante
  • Permet de travailler hors-ligne

Pour se tenir au jus : git fetch <remote>.

(git pull appelle implicitement git fetch.)

La collaboration (2)

Ça tourne mal

origin 6846ef5 master ac2b311 master tsfe01 $ git commit $ git push ? 6846ef5 master 06adada master tsfe02 $ git commit $ git push 6846ef5 master ac2b311 master

Ça tourne mal...

...mais Git couvre nos arrières.

issotm@sheik-kitty /tmp/test% git push
To example.com:chemin/vers/repo.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'example.com:chemin/vers/repo.git'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and integrate the remote changes
hint: (e.g. 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

... «non-fast-forward» ?

Fast-forwarding

«Fast-forwarder» une branche signifie «la déplacer uniquement vers des commits enfants» :

6846ef5 ac2b311 master 1234567 06adada 3d5f4a2 feedfac master master master master master

Fast-forwarding

«Fast-forwarding» parce que «avance rapide» dans le temps.

Fast-forward = toujours safe (on ne peut «perdre» aucun commit).

...et dans les autres cas ?

  • git merge
  • git rebase

Merge

Principe

6846ef5 ac2b311 1234567 master 06adada add-dark-mode 3d5f4a2 add-dark-mode feedfac

Avantages :

  • Historique préservé

Inconvénients :

  • master non linéaire
  • Les «merge commit» sont artificiels

Commande

git merge <commit>...

Crée un nouveau commit sur la branche actuelle qui «rassemble» la branche actuelle et tous les <commit>s.

On expliquera ce que «rassemblement» signifie quand on parlera de rebase.

Exemple : git merge master

Rebase

Principe

6846ef5 ac2b311 1234567 master 06adada 3d5f4a2 add-dark-mode 14e684a af58e36 add-dark-mode

Commande

git rebase <nouv-base> [<branche>]

Si <branche> est omis, la branche courante est modifiée.

Exemple : git rebase master (ou git rebase master add-dark-mode)

Petit récapitulatif

Créer un nouveau repo

git init

⚠️ Crée un repo dans le répertoire courant !

Créer une copie locale d'un repo

git clone <URL>

Retrouver ses petits

git status

issotm@sheik-kitty /tmp/rgbds% git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

Retrouver ses petits

git status

issotm@sheik-kitty /tmp/rgbds% git status
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   .editorconfig
        deleted:    .checkpatch.conf

no changes added to commit (use "git add" and/or "git commit -a")

Sélectionner les modifs à committer

git add

issotm@sheik-kitty /tmp/rgbds% git add .editorconfig
issotm@sheik-kitty /tmp/rgbds% git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   .editorconfig

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        deleted:    .checkpatch.conf

Goodies

Un visualiseur plus joli pour git diff et git blame : delta

On peut afficher le statut Git dans son prompt de shell (par ex. via powerlevel10k)

Une bonne interface graphique (certes freeware) : Sublime Merge (je recommande car elle liste les commandes exécutées)

Si vous utilisez un IDE, il a peut-être une intégration Git (parfois via extensions), lisez la doc

Merci d'avoir suivi !

Les slides sont disponibles en ligne : https://eldred.fr/slides/git!