Logo OFPPT

ISMO - Institut Spécialisé dans les Métiers de l'Offshoring

OFPPT - Office de la Formation Profesionnelle et de la Promotion du Travail

Master Class Git : Architecture, Stratégie et Survie

Dernière mise à jour : Janvier 2026

Parcours d'apprentissage

Partie 1 : Introduction et Fondamentaux

Chapitre 1 : Le problème (Pourquoi Git ?)

1.1 Le cauchemar des fichiers "Final"

On a tous déjà vécu ça. Vous travaillez sur un projet important, vous avez peur de perdre des modifications ou de faire une bêtise, alors vous faites des copies. Et ça finit comme ça :

rapport.docx

rapport_final.docx

rapport_final_v2.docx

rapport_final_vrai_cette_fois.docx

rapport_final_CORRIGE_Oussama.docx

⚠️ Le Problème : C'est ingérable ! On ne sait plus quelle est la bonne version, qui a modifié quoi, et revenir en arrière est un calvaire.

1.2 Travailler en équipe sans s'entretuer

Imaginez maintenant que vous êtes 3 à travailler sur le MÊME fichier en même temps.

  • Comment fusionner les modifications d'Alice avec celles de Bob ?
  • Que se passe-t-il si les deux modifient la ligne 12 en même temps ?
  • Comment savoir qui a cassé le code hier soir ?

Sans outil adapté, c'est le chaos assuré. On s'envoie des fichiers par mail "tiens ma version", on écrase le travail des autres par erreur...

Chapitre 2 : Git, c'est quoi ? (Définitions simples)

2.1 La machine à remonter le temps

Git est un logiciel de gestion de versions (VCS). Pour faire simple, c'est une "machine à remonter le temps" pour vos dossiers.

✅ Ce qu'il permet
  • Sauvegarder l'état exact du projet à un instant T (un "Commit").
  • Revenir à n'importe quelle version précédente instantanément.
  • Voir exactement ce qui a changé (qui, quoi, quand).
  • Travailler à plusieurs sans se marcher sur les pieds.
💡 Analogie Jeu Vidéo

C'est comme un système de Checkpoints dans un jeu vidéo. Avant d'affronter le boss (faire une grosse modif risquée), vous sauvegardez. Si vous mourrez (le code plante), vous rechargez la sauvegarde (commande checkout ou reset).

2.2 "Distribué", ça veut dire quoi ?

Vous entendrez souvent que Git est "décentralisé" ou "distribué". Contrairement à une sauvegarde classique sur un serveur central :

🌍 Tout le monde a TOUT : Quand vous téléchargez un projet Git, vous ne récupérez pas juste les fichiers actuels. Vous téléchargez tout l'historique complet, depuis la création du projet.

Avantage énorme : Vous pouvez travailler dans le train, sans internet. Vous avez votre propre copie complète de la base de données du projet. Vous pouvez faire des commits, créer des branches, regarder l'historique... tout ça hors ligne !

Chapitre 3 : Installation et les Géants (GitHub, GitLab...)

3.1 Installer Git facilement

🪟 Sur Windows

Téléchargez l'installateur sur git-scm.com.

Astuce : Faites "Suivant" à chaque étape, les options par défaut sont très bien pour commencer.

Cela installera aussi "Git Bash", un terminal puissant.

🍎 Sur macOS / Linux

Ouvrez le terminal et tapez :

git --version

S'il n'est pas installé, votre ordinateur vous proposera de le faire automatiquement.

3.2 La première configuration (Indispensable !)

Une fois Git installé, vous devez lui dire qui vous êtes. Ces informations apparaîtront dans l'historique de chaque modification.

# 1. Définir votre nom (Obligatoire)

git config --global user.name "John Doe"

# 2. Définir votre email (Celui de GitHub/GitLab)

git config --global user.email "john@example.com"

# 3. Moderniser la branche par défaut (Recommandé)

git config --global init.defaultBranch main

# 4. Gérer les fins de ligne (Important pour Windows)

git config --global core.autocrlf true

# 5. Vérifier la configuration

git config --list

⚠️ Important : Utilisez le même email que celui de votre compte GitHub/GitLab. Git a besoin de ça pour relier vos contributions (commits) à votre profil en ligne.

3.3 Git vs GitHub (Ne pas confondre !)

C'est la confusion n°1 des débutants.

Git

C'est le LOGICIEL (l'outil).

Comme Word ou Photoshop.
Il s'installe sur votre ordinateur.

GitHub

C'est le SITE WEB (le service).

Comme Google Drive ou Dropbox.
Il héberge vos projets Git sur internet.

3.4 Les plateformes d'hébergement

Où stocker votre code en ligne ? Il y a plusieurs concurrents :

🐱 GitHub

Racheté par Microsoft.

Le plus populaire. C'est le "réseau social" des développeurs. Idéal pour l'open-source et votre portfolio.

🦊 GitLab

Open source core.

Très puissant pour le DevOps (CI/CD intégré). Souvent utilisé en entreprise pour être installé sur leurs propres serveurs.

⚙️ Bitbucket

Par Atlassian (Jira/Trello).

Très utilisé dans les entreprises qui utilisent déjà Jira. Bonne intégration avec les outils Atlassian.

Partie 2 : Initialisation et Fonctionnement

Chapitre 1 : Créer son premier dépôt (git init)

1.1 Démarrer un projet Git

Pour commencer à suivre l'historique d'un projet, il faut dire à Git : "Hé, surveille ce dossier !". C'est le rôle de la commande git init.

# 1. Se placer dans le dossier du projet
$ cd mon-super-projet

# 2. Initialiser Git
$ git init
Initialized empty Git repository in /chemin/mon-super-projet/.git/

🎉 Félicitations ! Vous avez transformé un simple dossier en un dépôt Git. Git est maintenant prêt à enregistrer vos modifications.

1.2 Que s'est-il passé ?

Si vous regardez les fichiers (en affichant les éléments masqués), vous verrez un nouveau dossier caché : .git.

📂

mon-super-projet/

├── index.html

├── style.css

└── .git/ <-- (La magie est ici)

1.3 Erreurs classiques

🚫 Init dans le dossier utilisateur

Ne faites JAMAIS git init directement dans C:\Users\Moi ou sur le Bureau. Cela ralentirait tout votre ordinateur car Git essaierait de suivre tous vos fichiers personnels !

📂 Init imbriqués

Évitez de faire un git init à l'intérieur d'un dossier qui est DÉJÀ dans un projet Git. Cela créerait des conflits bizarres (submodules).

Chapitre 2 : Comment ça marche ? (La boîte noire .git)

2.1 Le dossier .git : Touche pas à ça !

Le dossier .git est le cerveau de votre projet. Il contient tout votre historique, tous vos anciens fichiers, toutes vos branches.

⚠️ Règle d'or : Ne modifiez jamais manuellement les fichiers à l'intérieur de .git/. Laissez la commande git gérer ce dossier pour vous.

Si vous supprimez ce dossier, vous perdez tout l'historique du projet et redevenez un simple dossier de fichiers.

2.2 Analogie : L'album photo

Imaginez Git comme un photographe ultra-rapide pour votre code.

📸
Le Commit

C'est une photo (snapshot) de tout votre projet à un instant T.

🎞️
L'Historique

C'est l'album photo complet, classé par ordre chronologique.

🏷️
Les Branches

Ce sont des étiquettes mobiles collées sur certaines photos pour dire "On travaille ici".

Chapitre 3 : Pourquoi Git ne perd rien (Intégrité)

3.1 Empreintes digitales (Hash)

Git donne à chaque version de fichier et à chaque commit une empreinte digitale unique. C'est une suite de 40 caractères bizarres (lettres et chiffres) que vous verrez souvent.

a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0

On appelle ça un SHA-1 (ou Hash). Ce qu'il faut retenir :

  • Si vous changez une seule virgule dans un fichier, son empreinte change complètement.
  • C'est impossible de corrompre un fichier sans que Git ne s'en aperçoive.
  • C'est grâce à ça que Git est ultra-fiable pour le travail en équipe.

3.2 Une base de données efficace

"Git prend une photo de tout le projet à chaque fois ? Mais ça va prendre une place énorme sur mon disque dur !"

💡 L'astuce géniale de Git

Non ! Git est intelligent. Si vous avez 100 fichiers et que vous n'en modifiez qu'un seul :
- La nouvelle "photo" stocke le nouveau fichier.
- Pour les 99 autres, Git fait juste un lien vers la version précédente (comme un raccourci).

C'est pour ça que les dépôts Git restent légers et rapides, même avec des milliers de versions.

Partie 3 : Les Bases du Travail

Chapitre 1 : Concepts & États

1.1 Le Repository et le Commit

📂 Le Repository (Dépôt)

C'est votre projet complet, avec tout son historique. C'est la base de données qui contient toutes les versions de vos fichiers.

� Le Commit

C'est une photo instantanée (snapshot) de votre projet à un moment précis. Une fois créé, un commit est gravé dans le marbre (ou presque).

1.2 Les 4 États d'un fichier

Git classe chaque fichier de votre dossier dans une de ces 4 catégories. C'est CRUCIAL de bien comprendre la différence.

👻
Untracked

"Non suivi"

Fichier nouveau que Git ne connait pas encore. Il n'est pas dans l'album photo.

📝
Modified

"Modifié"

Fichier connu de Git, que vous avez changé mais pas encore préparé pour la photo.

📦
Staged

"Indexé / Prêt"

Fichier mis dans le carton (Index). Il est prêt à être commité.

🔒
Committed

"Validé"

La version est enregistrée dans la base de données locale. Elle est en sécurité.

Chapitre 2 : Ajouter (Add) et Ignorer (.gitignore)

2.1 La commande git add

git add sert à passer un fichier de l'état Untracked ou Modified à l'état Staged.

# Ajouter un seul fichier
$ git add index.html

# Ajouter plusieurs fichiers spécifiques
$ git add style.css script.js

# Ajouter tout un dossier
$ git add images/

# ⚡ Ajouter TOUT (nouveaux, modifiés, supprimés) - Le plus utilisé
$ git add .

# Ajouter tout (alternative, pareil que .)
$ git add -A

Attention : Si vous modifiez un fichier APRES l'avoir ajouté (staged), vous devez refaire git add pour prendre en compte les dernières modifs !

2.2 Le fichier .gitignore

Certains fichiers ne doivent JAMAIS être committés (mots de passe, fichiers temporaires, dossiers de build, dépendances lourdes...). Pour ça, on crée un fichier texte nommé .gitignore à la racine.

Syntaxe et Exemples :
# Ignorer un fichier spécifique
secret.txt
.env

# Ignorer par extension
*.log
*.tmp
*.psd

# Ignorer un dossier complet
node_modules/
vendor/
build/

# Ignorer tout sauf...
!index.html
Pourquoi c'est important ?
  • Sécurité : Ne pas publier vos clés API.
  • Propreté : Ne pas polluer l'historique avec des fichiers générés.
  • Performance : Git n'a pas besoin de scanner les dossiers géants comme node_modules.

Chapitre 3 : Vérifier (Status) et Valider (Commit)

3.1 git status (Le tableau de bord)

Affiche l'état actuel de votre Working Directory et de votre Staging Area.

$ git status

Untracked files:
  (use "git add ..." to include in what will be committed)
    nouveau_fichier.txt

Changes to be committed:
  (use "git restore --staged ..." to unstage)
    new file:   style.css
    modified:   index.html

3.2 git commit (La validation)

Crée une nouvelle version avec tout ce qui est dans la Staging Area.

1. Commit classique (Recommandé)
$ git commit -m "Message clair et concis"
2. L'option -a (All modified)

Ajoute automatiquement les fichiers déjà suivis (modified) et commit. ⚠️ Ne marche pas pour les fichiers Untracked (nouveaux) !

$ git commit -a -m "Message rapide"
3. Le combo ultime (-am)
$ git commit -am "Ajoute et commit les modifs en une fois"

💪 Exercices Pratiques

  1. Initialisation : Créez un dossier test-git, entrez dedans et tapez git init.
  2. Création : Créez un fichier index.html et tapez git status (Il doit être Untracked/Rouge).
  3. Staging : Tapez git add index.html puis git status (Il doit être Staged/Vert).
  4. Commit : Tapez git commit -m "Premier commit".
  5. Modification : Modifiez le fichier. Tapez git status. Essayez git commit -am "Mise à jour".
  6. Gitignore : Créez un fichier secret.txt. Créez un fichier .gitignore et écrivez secret.txt dedans. Vérifiez avec git status que le fichier secret n'apparait plus !
👁️ Voir la solution
# 1. Initialisation
$ mkdir test-git
$ cd test-git
$ git init

# 2. Création (Sur Windows, utilisez l'explorateur ou echo)
$ echo "Hello" > index.html
$ git status

# 3. Staging
$ git add index.html
$ git status

# 4. Commit
$ git commit -m "Premier commit"

# 5. Modification
$ echo "Modif" >> index.html
$ git status
$ git commit -am "Mise à jour"

# 6. Gitignore
$ echo "Secret" > secret.txt
$ echo "secret.txt" > .gitignore
$ git status
# Le fichier secret.txt ne doit PAS apparaitre

Partie 4 : Exploration et Voyage

Chapitre 1 : Lire l'histoire (git log)

1.1 La base et les variantes d'affichage

La commande git log est votre fenêtre sur le passé. Par défaut, elle est verbeuse, mais on peut la personnaliser à l'infini.

Commande Description
git log Affiche l'historique complet (Hash, Auteur, Date, Message).
git log -n 2 Limite l'affichage aux 2 derniers commits.
git log --oneline Affiche chaque commit sur une seule ligne (Hash court + Message). Idéal pour une vue d'ensemble.
git log --graph Dessine un arbre ASCII sur la gauche pour voir les branches et les fusions.
git log --decorate Affiche les références (HEAD, branches, tags) à côté des commits.

# Le combo ultime ("A DOG" : All, Decorate, Oneline, Graph)

$ git log --all --decorate --oneline --graph

* 3a1b2c (HEAD -> main, origin/main) Fix login bug

| * 8d9e0f (feature/new-ui) Add new buttons

|/

* 1g2h3i Initial commit

1.2 Filtrer la recherche

Dans un projet avec 10 000 commits, vous devez savoir chercher.

📅 Par date
git log --since="2024-01-01"
git log --until="2 weeks ago"
👤 Par auteur
git log --author="Oussama"
🔍 Par message
git log --grep="bugfix"
📄 Par fichier
git log -- index.html

1.3 Voir le contenu (Patchs)

Parfois, le message ne suffit pas, on veut voir CODE.

  • git log -p Affiche le "Patch" (le diff) complet de chaque commit.
  • git log -p index.html Montre l'évolution du code uniquement pour ce fichier.
  • git log --stat Affiche des statistiques résumées (fichiers modifiés, nombre de lignes +/-).

Chapitre 2 : Inspecter les changements (git diff)

2.1 Comprendre ce qu'on compare

git diff ne sert pas juste à voir ce qu'on a fait avant de commiter. C'est un outil de comparaison universel.

1. Working Directory vs Staging (Le défaut)
$ git diff

Ce que j'ai modifié mais PAS ENCORE ajouté (add).

2. Staging vs Dernier Commit
$ git diff --staged

Ce que je m'apprête à commiter (ce qui est ready).

3. Entre deux commits
$ git diff a1b2c..d4e5f

Qu'est-ce qui a changé entre la version A et la version B ?

4. Entre deux branches
$ git diff main..feature

Qu'est-ce que "feature" a de plus que "main" ?

2.2 Options pratiques

  • git diff --name-only : Affiche juste les noms de fichiers, pas le code.
  • git diff -w : Ignore les changements d'espaces (utile si quelqu'un a juste réindenté tout le fichier !).
  • git diff --word-diff : Affiche les changements mot par mot (plutôt que ligne par ligne).

Chapitre 3 : Voyager dans le temps (git checkout)

3.1 La commande aux multiples visages

git checkout fait deux choses très différentes selon le contexte. C'est pour cela que Git moderne a introduit switch et restore (mais checkout reste universel).

✈️ Se déplacer (HEAD)

Change l'état global du projet.

# Aller sur une branche
$ git checkout main

# Créer et aller sur une branche
$ git checkout -b ma-super-branche

# Aller sur un commit précis (Lecture seule)
$ git checkout a1b2c3d
♻️ Restaurer des fichiers

Écrase les modifications locales.

# Annuler les modifs d'un fichier
$ git checkout -- fichier.html

# Tout remettre à zéro (DANGER ☢️)
$ git checkout .

# Récupérer un fichier d'une autre branche
$ git checkout main -- fichier.html

💪 Exercice Avancé : L'enquêteur Temporel

Objectif : Créer un historique complexe et naviguer dedans.

  1. Créez un dépôt et faites 3 commits modifiant data.txt (contenu: "A", puis "A B", puis "A B C").
  2. Utilisez git log --oneline pour voir les Hashs.
  3. Utilisez git log -p data.txt pour voir exactement ce qui a été ajouté à chaque fois.
  4. Faites un git checkout vers le 1er commit. Vérifiez le fichier.
  5. Revenez sur main. Modifiez le fichier ("A B C D") sans commiter.
  6. Faites git diff pour voir la modif.
  7. Oops, c'était une erreur ! Utilisez git checkout -- data.txt pour annuler.
👁️ Voir la solution
# 1. Setup
$ git init exo-log
$ cd exo-log
$ echo "A" > data.txt && git add . && git commit -m "Ajout A"
$ echo "A B" > data.txt && git commit -am "Ajout B"
$ echo "A B C" > data.txt && git commit -am "Ajout C"

# 2. Log avancé
$ git log --oneline
# 3a1b2c (HEAD -> main) Ajout C
# 1f2e3d Ajout B
# 9z8y7x Ajout A

# 3. Voir l'évolution
$ git log -p data.txt

# 4. Voyage
$ git checkout 9z8y7x  (Hash du 1er commit)
$ cat data.txt         # Affiche "A"
$ git checkout main    # Retour au présent

# 5, 6, 7. Manipulation et Annulation
$ echo "A B C D" > data.txt
$ git diff
# Affiche le +D en vert
$ git checkout -- data.txt
$ cat data.txt
# Affiche "A B C" (Modif annulée)

Partie 5 : Annuler et Réparer

Chapitre 1 : Oups ! Petite correction (git commit --amend)

1.1 Corriger le dernier commit

Vous venez de commiter et... vous réalisez que vous avez fait une faute de frappe dans le message ? Ou oublié un fichier ?

Pas besoin de créer un commit "Oups correction" ! Utilisez --amend pour modifier le commit précédent comme si rien ne s'était passé.

# Cas 1 : Changer juste le message
$ git commit --amend -m "Nouveau message corrigé"

# Cas 2 : Ajouter un fichier oublié
$ git add fichier_oublie.css
$ git commit --amend --no-edit
# --no-edit garde l'ancien message

⚠️ Attention : Amend réécrit l'historique (Change le SHA-1). Ne le faites JAMAIS sur un commit déjà pushé !

Chapitre 2 : Annuler proprement (git revert)

2.1 Le concept : "L'Anti-Commit"

Imaginez que vous avez ajouté une fonctionnalité qui fait planter le site en Prod. Vous voulez l'annuler, MAIS vous ne voulez pas effacer l'historique (pour garder une trace de l'erreur).

git revert ne supprime pas de commit. Il crée un Nouveau Commit qui fait exactement l'inverse du commit ciblé.

Commit A
Ajoute bouton
Commit B
Ajoute menu
Commit C
Revert "Commit B"
Supprime menu
# Annuler le dernier commit
$ git revert HEAD

# Annuler un commit spécifique (via son hash)
$ git revert a1b2c3d

✅ Quand l'utiliser ? TOUJOURS si le commit a déjà été partagé (pushé) sur GitHub/GitLab. C'est la méthode sûre.

💪 Exercice : Le bouton maudit

  1. Créez un fichier site.html avec "Version Stable". Commitez.
  2. Ajoutez une ligne "Bouton Maudit" qui casse tout. Commitez.
  3. Vérifiez l'historique avec git log --oneline.
  4. Oups ! Utilisez git revert pour annuler ce bouton sans effacer l'historique.
  5. Vérifiez que le fichier est revenu à la normale ET qu'un nouveau commit "Revert" est apparu.
👁️ Solution Revert
$ echo "

Site Stable

" > site.html $ git add . && git commit -m "Site stable" $ echo "" >> site.html $ git commit -am "Ajout bouton" $ git log --oneline # a1b2c (HEAD) Ajout bouton # d3e4f Site stable $ git revert HEAD # (Git ouvre l'éditeur pour le message, sauvegardez et quittez) $ cat site.html # "

Site Stable

" uniquement $ git log --oneline # z9y8x (HEAD) Revert "Ajout bouton" # a1b2c Ajout bouton # d3e4f Site stable

Chapitre 3 : La chirurgie de l'historique (git reset)

3.1 Le Grand Nettoyage

Contrairement à Revert, git reset efface l'historique. Il déplace le pointeur HEAD vers l'arrière, comme si les commits suivants n'avaient jamais existé.

🚨 DANGER : Ne faites jamais de reset sur des commits déjà pushés ! Vos collègues vous détesteraient.

Les 3 Modes de Reset (Le Trio Infernal)
git reset --soft Le "Gentil"

Déplace HEAD en arrière mais garde les modifs stagées (dans le carton).

Usage : J'ai raté mon dernier commit (message ou oubli), je veux le refaire sans perdre mon travail.

git reset --mixed Le "Par défaut"

Déplace HEAD mais garde les modifs en non-stagées (Working Directory).

Usage : Je veux annuler mes commits et retravailler mes fichiers tranquillement.

git reset --hard Le "Destructeur"

Déplace HEAD et SUPPRIME TOUTES LES MODIFS.

Usage : Je veux tout jeter et revenir exactement comme c'était avant. C'est irréversible* !

*Sauf avec git reflog ;)

💪 Exercice : Crash Test Reset

  1. Faites 3 commits : "V1", "V2", "V3" (avec des fichiers différents pour bien voir).
  2. Test Soft : git reset --soft HEAD~1 (Revient 1 cran avant). Vérifiez git status : les modifs de V3 sont là, prêtes à être commitées.
  3. Recommitez pour revenir en V3.
  4. Test Mixed : git reset --mixed HEAD~1. Vérifiez git status : les modifs de V3 sont là, mais "Untracked/Modified".
  5. Recommitez/Restaurer pour revenir en V3.
  6. Test Hard : git reset --hard HEAD~1. Vérifiez : Tout a disparu. V3 est mort.
👁️ Solution Reset
# Setup
$ touch v1 && git add . && git commit -m "V1"
$ touch v2 && git add . && git commit -m "V2"
$ touch v3 && git add . && git commit -m "V3"

# 1. Soft
$ git reset --soft HEAD~1
$ git status
# On voit "new file: v3" en vert (Staged)
$ git commit -m "Retour V3"

# 2. Mixed
$ git reset --mixed HEAD~1
$ git status
# On voit "v3" en rouge (Untracked)
$ git add . && git commit -m "Retour V3"

# 3. Hard
$ git reset --hard HEAD~1
$ ls
# v3 a disparu définitivement !
$ git log --oneline
# V3 n'est plus dans l'historique

Chapitre 4 : Restaurer sans danger (git restore)

4.1 Le remplaçant moderne de checkout

Comme nous l'avons vu, git checkout fait trop de choses. Git a introduit git restore spécifiquement pour gérer les fichiers, sans risque de changer de branche par erreur.

Annuler les modifications (Working Dir)
$ git restore mon_fichier.txt

Le fichier redevient comme au dernier commit. C'est l'équivalent de "Annuler les changements" dans VS Code.

Enlever du carton (Unstage)
$ git restore --staged mon_fichier.txt

Vous avez fait git add par erreur ? Ceci sort le fichier du carton sans modifier son contenu.

💪 Exercice : Le stagiaire maladroit

  1. Créez un fichier important.config. Commitez.
  2. Modifiez le fichier avec des bêtises.
  3. Faites git add . (Oups, c'est dans le carton !)
  4. Utilisez git restore --staged pour sortir le fichier du carton.
  5. Utilisez git restore pour annuler vos bêtises dans le fichier.
👁️ Solution Restore
$ echo "Config=OK" > important.config
$ git add . && git commit -m "Config Clean"

$ echo "Config=PORTNAWAK" > important.config
$ git add .
$ git status
# Modifié et Staged (Vert)

$ git restore --staged important.config
$ git status
# Modifié mais Unstaged (Rouge)

$ git restore important.config
$ cat important.config
# "Config=OK" -> Ouf !

Partie 6 : Travailler en Parallèle

Chapitre 1 : Comprendre les Branches & Ungit

1.1 Le concept de Branche (Mondes Parallèles)

Une branche est une ligne de développement indépendante. Elle permet de travailler sur une fonctionnalité ou un correctif sans toucher à la version stable (souvent appelée main ou master) du projet.

C'est comme faire une photocopie d'un document pour écrire des notes dessus. Si les notes sont mauvaises, on jette la photocopie. Si elles sont bonnes, on les recopie sur l'original.

1.2 Voir l'Invisible avec Ungit

🛠️ Installation & Utilisation

Pour visualiser ces mondes parallèles, nous utiliserons Ungit.

$ npm install -g ungit

Puis dans votre dossier projet :

$ ungit

Ouvrez http://localhost:8448.

Chapitre 2 : Les Commandes Essentielles

2.1 Créer et Changer (Branch, Checkout, Switch)

La Méthode Classique (Checkout)

Historiquement, checkout sert à tout (fichiers et branches).

# Créer une branche
$ git branch ma-feature

# Aller dessus
$ git checkout ma-feature

# Créer ET Aller dessus (Raccourci)
$ git checkout -b ma-feature
La Méthode Moderne (Switch)

Plus explicite, dédié uniquement aux branches (Git > 2.23).

# Aller sur une branche existante
$ git switch ma-feature

# Créer ET Aller dessus
$ git switch -c ma-feature

2.2 ramener le travail (Merge)

Une fois le travail fini sur la branche, il faut le ramener sur la branche principale.

La Règle d'Or du Merge :

On se place TOUJOURS sur la branche qui REÇOIT (souvent main).

# 1. Je retourne sur le vaisseau mère
$ git switch main

# 2. J'aspire le travail de ma branche
$ git merge ma-feature

Chapitre 3 : 🏆 Projet 'TechStore' (Mise en Pratique)

Scénario

Maintenant que vous connaissez les commandes, vous allez les utiliser pour construire un site E-Commerce. Vous allez rencontrer 3 situations réelles : Le Fast-Forward, Le Merge Classique (No-FF) et le Conflit.

3.1 Initialisation (Main)

Créez le dossier techstore et les fichiers suivants. Commitez le tout sur main.

📂 Afficher le Code Source de départ

index.html

<!DOCTYPE html><html><body><h1>TechStore</h1></body></html>

style.css

body { background: #fff; color: #333; }

index.html

<!DOCTYPE html><html><body><h1>TechStore</h1></body></html>

style.css

body { background: #fff; color: #333; }

# Windows (PowerShell) & Linux/Mac : Tapez les commandes l'une après l'autre

$ git init

$ git add .

$ git commit -m "Init V1"

3.2 Cas 1 : Le Fast-Forward (Design)

Vous travaillez seul. main ne bouge pas. C'est le cas le plus simple.

  1. Créez une branche : git switch -c design-v2
  2. Modifiez style.css (Changez le background en #f4f4f4).
  3. Commitez :

    $ git add .

    $ git commit -m "New Design"

  4. Revenez sur main : git switch main
  5. Fusionnez : git merge design-v2

Observe le résultat : Git a juste avancé l'étiquette main. C'est un Fast-Forward.

3.3 Cas 2 : L'Historique Forcé (Features)

On veut voir clairement la branche "Produits" dans l'historique, même si un FF est possible.

  1. Branche : git switch -c feature-produits
  2. Créez produits.html. Commitez :

    $ git add .

    $ git commit -m "Page produits basic"

  3. Main : git switch main
  4. Fusion : git merge --no-ff feature-produits

Observe Ungit : Une "bulle" s'est créée. On voit le début et la fin de la feature.

3.4 Cas 3 : Le Conflit (Le Choc)

Deux versions différentes du même titre. Qui gagne ?

1. Sur MAIN

Modifiez le H1 : "TechStore 2026"

Commitez.

2. Sur une nouvelle branche "promo"

Modifiez le H1 (Même ligne) : "PROMO HIVER"

Commitez.

3. La Fusion

$ git switch main

$ git merge promo

💥 CONFLIT ! Ouvrez index.html, choisissez la version finale, puis faites git add . et git commit.

Chapitre 4 : La Maîtrise du Stash

4.1 Le "Presse-papiers" de Git

Vous devez changer de branche MAIS votre travail n'est pas fini. Vous ne pouvez pas commiter du code cassé.
Le Stash vous permet de stocker temporairement vos fichiers modifiés.

Action Commande
Sauvegarder (Rapide) git stash
Sauvegarder (Nommé) git stash save "Mon travail en cours"
Récupérer & Supprimer git stash pop
Voir la liste git stash list

Partie 7 : Collaboration Expert & Conflits

Chapitre 1 : Architecture Serveur (Bare & Remotes)

1.1 Qu'est-ce qu'un serveur Git ? (Bare Repo)

Avant de parler de GitHub ou GitLab, comprenez ceci : pour qu'un dépôt serve de "Serveur Central" où tout le monde pousse son code, il ne doit pas avoir de dossier de travail (Working Directory).

Pourquoi ? Si je pousse mon code sur un serveur qui a des fichiers ouverts, je risque de corrompre le travail en cours sur le serveur. C'est pour cela qu'on utilise --bare.

# Créer un dépôt "Nu" (Juste la base de données Git, pas de fichiers visibles)

$ git init --bare mon-projet-serveur.git

Le Secret :

GitHub, GitLab ou Bitbucket ne sont rien d'autres que des collections de dépôts "Bare" avec une interface web par dessus.

Exercice Pratique : Le Serveur Local (Simulation)

Comme nous n'avons pas de "vrai" serveur GitHub sous la main, nous allons en simuler un sur votre propre dossier. C'est idéal pour comprendre la mécanique sans risque.

1. Créer le "Faux GitHub"

# Sortez de votre projet actuel

$ cd ..

# Créez un dossier nu (bare)

$ git init --bare techstore-server.git

2. Connecter votre projet

# Retournez dans votre projet TechStore

$ cd techstore

# Ajoutez l'adresse du serveur (Remote)

$ git remote add origin ../techstore-server.git

# Vérifiez

$ git remote -v

Exercice Pratique : Le Serveur Local (Simulation)

Comme nous n'avons pas de "vrai" serveur GitHub sous la main, nous allons en simuler un sur votre propre dossier. C'est idéal pour comprendre la mécanique sans risque.

1. Créer le "Faux GitHub"

# Sortez de votre projet actuel

$ cd ..

# Créez un dossier nu (bare)

$ git init --bare techstore-server.git

2. Connecter votre projet

# Retournez dans votre projet TechStore

$ cd techstore

# Ajoutez l'adresse du serveur (Remote)

$ git remote add origin ../techstore-server.git

# Vérifiez

$ git remote -v

Chapitre 2 : Synchronisation (Push, Pull & Rebase)

2.1 Envoyer ses modifications (Push)

Une fois vos commits effectués localement, ils ne sont pas encore sur le serveur. Pour les transférer, on utilise push.

# Envoie la branche 'main' locale vers le remote 'origin'

$ git push origin main

Si c'est la première fois, Git vous demandera peut-être de définir la branche amont (upstream) avec -u.

2.2 Récupérer les nouveautés (Pull Standard)

Pour récupérer le travail de vos collègues, la commande standard est pull.

$ git pull origin main

Ce que ça fait vraiment : Git télécharge les nouveautés ET essaie de les fusionner (Merge) avec votre travail actuel.

2.3 Comprendre Fetch vs Pull

Il est crucial de distinguer ces deux concepts :

  • git fetch : Va chercher les infos sur le serveur (met à jour origin/main) mais NE TOUCHE PAS à vos fichiers de travail. C'est du repérage sans danger.
  • git pull : C'est un git fetch suivi immédiatement d'un git merge.
git pull = git fetch + git merge

Exercice : Premier Push & Simulation Collègue (Fetch)

1. Pousser votre travail (Push)

Envoyez votre site TechStore actuel vers le serveur.

$ git push -u origin main

Succès ! Votre code est "dans le nuage" (enfin, dans le dossier d'à côté).

2. Simuler un Collègue (Clone)

Pour tester pull et fetch, il nous faut un deuxième développeur. Créons un clone dans un nouveau dossier.

# Sortez du dossier techstore

$ cd ..

# Clonez le projet en tant que "Collegue"

$ git clone techstore-server.git techstore-collegue

# Entrez chez le collègue

$ cd techstore-collegue

3. Le Collègue travaille (Push)

Le collègue modifie le titre et pousse.

# Dans techstore-collegue

$ echo "<!-- Update -->" >> index.html

$ git commit -am "Update du collegue"

$ git push origin main

4. Vous récupérez (Fetch vs Pull)

# Retournez dans VOTRE dossier

$ cd ../techstore

$ git fetch origin

# Rien ne bouge dans vos fichiers. Tapez 'git status'.

# message : "Your branch is behind... by 1 commit"

$ git pull origin main

# Maintenant vos fichiers sont à jour !

2.4 L'élégance du Pull --rebase

Par défaut, si vous et votre collègue avez travaillé en même temps, git pull va créer un "Commit de Fusion" qui peut polluer l'historique.

L'alternative Pro : Utiliser --rebase. Git va : 1. Mettre vos commits locaux de côté. 2. Mettre à jour avec le code du serveur. 3. Ré-appliquer vos commits à la suite.

# Historique linéaire garanti

$ git pull --rebase origin main

Exercice : Simulation du Rebase

Nous allons créer une divergence pour voir le Rebase en action.

1. Le Collègue avance encore (Côté Serveur)

$ cd ../techstore-collegue

$ echo "Footer: 2026" >> index.html

$ git commit -am "Footer Update"

$ git push origin main

2. Vous travaillez en local (Sans savoir)

$ cd ../techstore

$ echo "Header: New Logo" >> index.html

$ git commit -am "Header Update"

À ce stade, les historiques ont divergé !

3. Le Rebase Salvateur

# On récupère le travail du collègue ET on se place après

$ git pull --rebase origin main

# Git déplace votre commit "Header Update" après "Footer Update"

Chapitre 3 : Gestion de Conflits Expert

3.1 Choisir son Camp (Ours vs Theirs)

Parfois, vous ne voulez pas déchiffrer les chevrons <<< et >>>. Vous savez que vous voulez juste "MA version" ou "LEUR version".

Gardez NOTRE version

J'écrase ce qui vient d'arriver.

$ git checkout --ours fichier.css $ git add fichier.css
Prendre LEUR version

J'accepte leur code à 100%.

$ git checkout --theirs fichier.css $ git add fichier.css

3.2 Git Rerere (Reuse Recorded Resolution)

C'est le super-pouvoir caché de Git. Si vous résolvez un conflit complexe lors d'un gros merge, et que vous devez refaire ce merge plus tard (ex: lors d'un rebase annulé), Rerere s'en souvient.

Il enregistre votre résolution manuelle ("empreinte digitale du conflit") et l'applique automatiquement la prochaine fois qu'il voit exactement le même conflit.

# Activer le super-pouvoir

$ git config --global rerere.enabled true

Désormais, Git vous dira : "Resolved 'index.html' using previous resolution."

Partie 8 : Investigation et Debugging (Niveau Senior)

Chapitre 1 : Git Blame

1.1 Retrouver l'auteur d'une ligne

git blame affiche, pour chaque ligne d'un fichier, qui l'a modifiée en dernier, quand, et dans quel commit.

# Blame un fichier entier
$ git blame src/app.js

# Sortie exemple :
abc1234d (Alice   2024-01-15 10:30:00 +0100  1) const express = require('express');
def5678e (Bob     2024-02-20 14:45:00 +0100  2) const app = express();
abc1234d (Alice   2024-01-15 10:30:00 +0100  3)
ghi9012f (Charlie 2024-03-10 09:15:00 +0100  4) app.use(cors());
# Blame une plage de lignes spécifique
$ git blame -L 10,20 src/app.js

# Ignorer les espaces blancs
$ git blame -w src/app.js

# Format court (juste le hash)
$ git blame -s src/app.js

# Afficher l'email au lieu du nom
$ git blame -e src/app.js

1.2 Ignorer certains commits

Parfois un commit de reformatage pollue le blame. Git permet de l'ignorer.

# Ignorer un commit spécifique
$ git blame --ignore-rev abc1234 src/app.js

# Ignorer une liste de commits (fichier)
$ echo "abc1234" >> .git-blame-ignore-revs
$ echo "def5678" >> .git-blame-ignore-revs
$ git blame --ignore-revs-file .git-blame-ignore-revs src/app.js

# Configurer le fichier globalement pour le projet
$ git config blame.ignoreRevsFile .git-blame-ignore-revs

💡 Bonne pratique : Créez un fichier .git-blame-ignore-revs à la racine du projet et commitez-le. Ajoutez-y les commits de reformatage massif.

1.3 Du blame au contexte complet

# Une fois le commit trouvé, voir les détails
$ git show abc1234

# Voir le diff de ce commit sur ce fichier uniquement
$ git show abc1234 -- src/app.js

# Voir l'historique des modifications de cette ligne
$ git log -p -L 15,15:src/app.js

# Blame sur une ancienne version du fichier
$ git blame abc1234^ -- src/app.js

Chapitre 2 : Git Bisect

2.1 Chasse aux bugs par dichotomie

git bisect utilise une recherche binaire pour trouver le commit exact qui a introduit un bug. Extrêmement efficace sur les longs historiques.

📊 Efficacité : Pour 1000 commits, il suffit de ~10 tests (log₂(1000) ≈ 10) au lieu de potentiellement 1000 !

# 1. Démarrer la session bisect
$ git bisect start

# 2. Marquer le commit actuel comme "mauvais" (bug présent)
$ git bisect bad

# 3. Marquer un ancien commit comme "bon" (bug absent)
$ git bisect good v1.0.0
# ou: git bisect good abc1234

# 4. Git checkout un commit au milieu
# Testez si le bug est présent...

# 5. Marquer selon le résultat
$ git bisect good    # Bug absent
# ou
$ git bisect bad     # Bug présent

# 6. Répéter jusqu'à trouver le commit coupable
# Git affiche: "abc1234 is the first bad commit"

# 7. Terminer et revenir à l'état initial
$ git bisect reset

2.2 Bisect automatisé avec un script

Si vous avez un test automatisé, Git peut exécuter le bisect sans intervention humaine :

# Script de test (doit retourner 0 = good, 1-127 = bad, 125 = skip)
$ cat test-bug.sh
#!/bin/bash
npm test 2>&1 | grep -q "PASS"
# Retourne 0 si "PASS" trouvé, sinon retourne 1

# Lancer le bisect automatique
$ git bisect start
$ git bisect bad HEAD
$ git bisect good v1.0.0
$ git bisect run ./test-bug.sh

# Git teste automatiquement chaque commit et trouve le coupable

💡 Code de retour 125 : Utilisez-le quand un commit ne peut pas être testé (ex: ne compile pas). Git le sautera.

2.3 Commandes utiles pendant bisect

# Voir le log de la session (commits testés)
$ git bisect log

# Visualiser la progression
$ git bisect visualize

# Sauvegarder/restaurer une session
$ git bisect log > bisect.log
$ git bisect replay bisect.log

# Ignorer un commit (ne peut pas être testé)
$ git bisect skip

# Termes alternatifs (pour clarté)
$ git bisect start --term-old=working --term-new=broken
$ git bisect working abc1234
$ git bisect broken HEAD

Chapitre 3 : Git Grep

3.1 Recherche dans le code versionné

git grep est un grep optimisé pour les dépôts Git. Plus rapide que grep classique et ignore automatiquement .git/ et les fichiers ignorés.

# Recherche simple
$ git grep "TODO"

# Ignorer la casse
$ git grep -i "error"

# Afficher les numéros de ligne
$ git grep -n "function"

# Compter les occurrences par fichier
$ git grep -c "import"

# Recherche avec contexte (3 lignes avant/après)
$ git grep -C 3 "bug"

# Limiter à certains fichiers
$ git grep "useState" -- "*.jsx" "*.tsx"

# Expression régulière étendue
$ git grep -E "TODO|FIXME|HACK"

3.2 Recherche dans l'historique

Contrairement à grep classique, git grep peut chercher dans les anciennes versions du code :

# Chercher dans un commit spécifique
$ git grep "oldFunction" abc1234

# Chercher dans un tag
$ git grep "deprecated" v1.0.0

# Chercher dans toutes les branches
$ git grep "API_KEY" $(git branch -r --format='%(refname:short)')

# Chercher quand un pattern a été ajouté/supprimé
$ git log -p -S "function login" --all

# Avec expression régulière
$ git log -p -G "function\s+login\s*\(" --all

💡 Différence -S vs -G :

  • -S "text" : Commits qui changent le NOMBRE d'occurrences de "text"
  • -G "regex" : Commits dont le diff CONTIENT le pattern

3.3 Recherches avancées

# Recherche multi-pattern (AND)
$ git grep -e "import" --and -e "react"

# Recherche dans les noms de fonctions (avec contexte)
$ git grep -p "validate" -- "*.js"

# Afficher le nom de la fonction contenant le match
$ git grep -W "TODO"

# Combiner avec log pour trouver l'auteur
$ git log --all -p -S "buggyCode" --pretty=format:"%h %an %s"
✅ Avantages sur grep
  • Ignore automatiquement .git/
  • Respecte .gitignore
  • Peut chercher dans l'historique
  • Optimisé pour les dépôts Git
🔧 Alternatives modernes
  • ripgrep (rg) : Ultra-rapide
  • ag (Silver Searcher) : Rapide
  • ack : Orienté programmeurs

Partie 9 : Architecture de Projet et Industrialisation

Chapitre 1 : Submodules vs Subtrees

1.1 Git Submodules

Un submodule est un dépôt Git imbriqué dans un autre dépôt. Le parent stocke une référence vers un commit spécifique du submodule.

# Ajouter un submodule
$ git submodule add https://github.com/lib/library.git libs/library

# Cloner un projet avec submodules
$ git clone --recurse-submodules https://github.com/user/project.git
# ou après clone :
$ git submodule update --init --recursive

# Mettre à jour tous les submodules
$ git submodule update --remote

# Voir le statut des submodules
$ git submodule status
✅ Avantages
  • Version exacte de la dépendance
  • Historiques séparés et propres
  • Dépendances légères dans le parent
❌ Inconvénients
  • Complexité extra aux opérations
  • Oubli fréquent de --recurse-submodules
  • Conflits de pointer délicats

1.2 Git Subtrees

Un subtree intègre directement le code d'un autre dépôt. Pas de références externes — tout est dans l'historique.

# Ajouter un subtree
$ git subtree add --prefix=libs/library https://github.com/lib/library.git main --squash

# Mettre à jour depuis l'upstream
$ git subtree pull --prefix=libs/library https://github.com/lib/library.git main --squash

# Pousser des modifications vers l'upstream
$ git subtree push --prefix=libs/library https://github.com/lib/library.git feature-branch
✅ Avantages
  • Pas d'étape supplémentaire au clone
  • Tout l'historique est local
  • Contribuer en retour facile
❌ Inconvénients
  • Historique mélangé (ou squashé)
  • Taille du dépôt augmentée
  • Commandes longues et peu connues

1.3 Quand utiliser quoi ?

Critère Submodule Subtree
Clone simple ❌ --recurse-submodules ✅ Automatique
Modification de la dépendance ⚠️ Process séparé ✅ Dans le même repo
Taille du dépôt ✅ Léger ⚠️ Plus lourd
Version précise ✅ Commit exact ⚠️ Moins visible

Chapitre 2 : Workflows Industriels

2.1 GitFlow

Créé par : Vincent Driessen (2010). Idéal pour les projets avec cycles de release planifiés.

main        ●──────────────────●────────────────●
             ↑                  ↑                ↑
release     ┃    ●─────────────●                ┃
             ┃   ↑              ↓                ┃
develop    ●─●───●──●──────────●───●──●─────────●
            ↑   ↑              ↑      ↑
feature-A  ●───●              ┃      ┃
                               ┃      ┃
feature-B                     ●──────●

Branches principales :

  • main : Code en production
  • develop : Intégration des features

Branches de support :

  • feature/* : Nouvelles fonctionnalités
  • release/* : Préparation d'une release
  • hotfix/* : Correctifs urgents

2.2 GitHub Flow

Philosophie : Simple. Une seule branche main toujours déployable. Tout passe par des Pull Requests.

main      ●────●────●────●────●────●
           ↑    ↑    ↑    ↑
feature   ●────●    ┃    ┃
                    ●────●
  1. Créer une branche depuis main
  2. Commiter et pousser régulièrement
  3. Ouvrir une Pull Request pour review
  4. Discuter et réviser le code
  5. Déployer depuis la branch (optionnel)
  6. Merger dans main et déployer

2.3 Trunk-Based Development

Utilisé par : Google, Facebook. Orienté CI/CD extrême avec feature flags.

main    ●──●──●──●──●──●──●──●──●
         ↑        ↑
short   ●────●    ●
Principe : Commits directs sur main (ou branches très courtes < 1 jour)
Feature Flags : Nouvelles features cachées derrière des flags
CI/CD : Tests automatiques à chaque commit

Chapitre 3 : Mono-repo vs Multi-repo

3.1 Comparaison

📦 Mono-repo

Un seul dépôt pour tous les projets

Utilisé par : Google, Facebook, Microsoft (Windows)

  • ✅ Refactoring atomique cross-projets
  • ✅ Partage de code facile
  • ✅ CI/CD unifiée
  • ❌ Taille énorme (tooling spécial)
  • ❌ Permissions granulaires difficiles
📚 Multi-repo

Un dépôt par projet/service

Approche traditionnelle, microservices

  • ✅ Isolation claire des équipes
  • ✅ Clone rapide
  • ✅ Permissions natives Git
  • ❌ Changements cross-projets = N PRs
  • ❌ Cohérence des dépendances difficile

3.2 Outils pour Mono-repos

🔷 Nx

Mono-repo intelligent avec caching et affected commands.

🟠 Turborepo

Build system incrémental par Vercel.

🔵 Lerna

Gestion de mono-repos JavaScript.

Chapitre 4 : Outils Pro (worktrees, archive, notes)

4.1 Git Worktrees

Permet d'avoir plusieurs branches checkout simultanément dans des dossiers séparés, partageant le même dépôt .git.

# Créer un worktree pour une branche existante
$ git worktree add ../project-hotfix hotfix/urgent-bug

# Créer un worktree avec nouvelle branche
$ git worktree add -b feature/new ../project-feature main

# Lister les worktrees
$ git worktree list
/home/user/project        abc1234 [main]
/home/user/project-hotfix def5678 [hotfix/urgent-bug]

# Supprimer un worktree
$ git worktree remove ../project-hotfix

💡 Cas d'usage : Travailler sur un hotfix urgent sans perdre le contexte de votre feature en cours. Pas besoin de stash ou de commit WIP !

4.2 Git Archive

Exporte une version propre du projet (sans .git) pour distribution ou déploiement.

# Créer une archive ZIP
$ git archive --format=zip --output=release-v1.0.0.zip v1.0.0

# Créer une archive tar.gz
$ git archive --format=tar.gz --output=release.tar.gz HEAD

# Archiver seulement un sous-dossier
$ git archive --format=zip --output=docs.zip HEAD:docs/

# Avec un préfixe de dossier
$ git archive --prefix=myproject-1.0/ -o release.zip v1.0.0

4.3 Git Notes

Ajoute des métadonnées à un commit sans modifier son hash. Utile pour annotations, reviews, ou métadonnées CI.

# Ajouter une note à un commit
$ git notes add -m "Code review : OK" abc1234

# Voir les notes d'un commit
$ git notes show abc1234

# Voir le log avec les notes
$ git log --show-notes

# Éditer une note existante
$ git notes edit abc1234

# Supprimer une note
$ git notes remove abc1234

# Pousser les notes vers le remote
$ git push origin refs/notes/*

⚠️ Note : Les notes ne sont PAS poussées par défaut avec git push. Elles nécessitent une configuration ou commande explicite.

Partie 10 : Cas Réels, Erreurs Classiques et Disaster Recovery

Chapitre 1 : Scénario "Repo en feu"

1.1 Diagnostiquer un dépôt corrompu

# Vérifier l'intégrité du dépôt
$ git fsck --full
error: object abc1234: badTimezone: invalid author/committer line
dangling commit def5678
missing blob ghi9012

# Identifier les problèmes
$ git fsck --lost-found
# Les objets récupérables sont placés dans .git/lost-found/
🚨 Causes courantes de corruption
  • Coupure de courant pendant une opération Git
  • Disque dur défaillant
  • Interruption d'un clone/fetch
  • Manipulation manuelle de .git/

1.2 Récupération d'urgence

# Option 1 : Si le remote est sain, recloner
$ mv projet projet-backup
$ git clone https://github.com/user/projet.git

# Option 2 : Récupérer les refs corrompues depuis le remote
$ git fetch origin
$ git reset --hard origin/main

# Option 3 : Récupérer des objets manquants
$ git fetch --all
$ git fsck --full    # Revérifier

# Option 4 : Si le reflog est intact, revenir à un état sain
$ git reflog
$ git reset --hard HEAD@{5}

1.3 Réparer un historique public cassé

⚠️ Important : Toute réécriture d'historique public nécessite une coordination avec l'équipe. Tout le monde devra re-cloner ou exécuter des commandes spécifiques.

# Après avoir corrigé l'historique localement
$ git push --force-with-lease origin main

# Communication aux collaborateurs :
# "L'historique de main a été réécrit. Exécutez :"
$ git fetch origin
$ git reset --hard origin/main
# Ou pour préserver le travail local :
$ git rebase origin/main

Chapitre 2 : Nettoyage d'historique

2.1 Le problème : Fichier sensible commité

🚨 Scénario cauchemar : Vous avez accidentellement commité un fichier .env avec vos clés API, puis poussé sur GitHub. Le supprimer avec un nouveau commit n'est PAS suffisant — il reste dans l'historique !

Étape 0 : Révoquez immédiatement les secrets exposés (nouvelle clé API, nouveau mot de passe, etc.)

2.2 BFG Repo-Cleaner (Recommandé)

Outil dédié, beaucoup plus rapide et simple que git filter-branch.

# Installation (Java requis)
# Télécharger depuis https://rtyley.github.io/bfg-repo-cleaner/

# Supprimer un fichier de tout l'historique
$ java -jar bfg.jar --delete-files .env repo.git

# Supprimer les fichiers > 100Mo
$ java -jar bfg.jar --strip-blobs-bigger-than 100M repo.git

# Remplacer du texte (mots de passe)
$ echo "PASSWORD" > passwords.txt
$ java -jar bfg.jar --replace-text passwords.txt repo.git

# Après BFG, nettoyer les objets
$ cd repo.git
$ git reflog expire --expire=now --all
$ git gc --prune=now --aggressive

# Force push le résultat
$ git push --force --all
$ git push --force --tags

2.3 git filter-repo (Alternative moderne)

Remplaçant officiel de filter-branch (déprécié). Plus flexible que BFG.

# Installation
$ pip install git-filter-repo

# Supprimer un fichier de tout l'historique
$ git filter-repo --path .env --invert-paths

# Supprimer un dossier
$ git filter-repo --path secrets/ --invert-paths

# Remplacer du texte
$ git filter-repo --replace-text replacements.txt
# Format du fichier: regex:ANCIEN==>NOUVEAU

💡 Après nettoyage : Demandez à GitHub/GitLab de purger leur cache. Les commits supprimés peuvent rester accessibles temporairement via des liens directs.

Chapitre 3 : Automatisation (Hooks)

3.1 Qu'est-ce qu'un Hook Git ?

Les hooks sont des scripts exécutés automatiquement à certains moments du cycle Git. Ils vivent dans .git/hooks/.

Hooks côté client
  • pre-commit : Avant le commit
  • commit-msg : Valide le message
  • pre-push : Avant le push
  • post-checkout : Après un checkout
Hooks côté serveur
  • pre-receive : Avant réception
  • post-receive : Après réception
  • update : Par branche

3.2 Exemple : Hook pre-commit

#!/bin/sh
# .git/hooks/pre-commit

# Linter JavaScript
echo "🔍 Running ESLint..."
npx eslint --fix .
if [ $? -ne 0 ]; then
    echo "❌ ESLint failed. Commit aborted."
    exit 1
fi

# Vérifier qu'aucun fichier sensible n'est stagé
if git diff --cached --name-only | grep -E '\.(env|pem|key)$'; then
    echo "❌ Sensitive file detected! Commit aborted."
    exit 1
fi

echo "✅ Pre-commit checks passed!"
exit 0
# Rendre le hook exécutable
$ chmod +x .git/hooks/pre-commit

# Bypasser un hook (urgence seulement)
$ git commit --no-verify -m "Emergency fix"

3.3 Outils de gestion des hooks

Les hooks ne sont pas versionnés par défaut. Ces outils résolvent ce problème :

🐶 Husky

Pour projets JavaScript

npm install husky --save-dev
npx husky init
🪝 pre-commit

Framework Python multi-langage

pip install pre-commit
pre-commit install
🎣 lefthook

Rapide, multi-langage

brew install lefthook
lefthook install

Chapitre 4 : Signatures GPG

4.1 Pourquoi signer ses commits ?

🔐 Problème : git config user.name peut être modifié par n'importe qui. Un attaquant peut usurper votre identité dans un commit. La signature GPG prouve cryptographiquement que VOUS êtes l'auteur.

✓ Verified Badge affiché sur GitHub/GitLab pour les commits signés

4.2 Configuration de la signature

# 1. Générer une clé GPG (ou utiliser une existante)
$ gpg --full-generate-key
# Choisir RSA 4096, email identique à git config user.email

# 2. Trouver l'ID de votre clé
$ gpg --list-secret-keys --keyid-format LONG
sec   rsa4096/3AA5C34371567BD2 2024-01-01 [SC]
#                ↑ C'est l'ID de la clé

# 3. Configurer Git
$ git config --global user.signingkey 3AA5C34371567BD2
$ git config --global commit.gpgsign true    # Signe tous les commits
$ git config --global tag.gpgsign true       # Signe tous les tags

# 4. Exporter la clé publique (pour GitHub/GitLab)
$ gpg --armor --export 3AA5C34371567BD2

4.3 Utilisation

# Signer un commit (si gpgsign n'est pas activé globalement)
$ git commit -S -m "Signed commit"

# Signer un tag
$ git tag -s v1.0.0 -m "Signed release"

# Vérifier la signature d'un commit
$ git verify-commit abc1234
$ git log --show-signature

# Vérifier la signature d'un tag
$ git verify-tag v1.0.0

4.4 Dépannage GPG

# Erreur "gpg: signing failed: No pinentry"
$ export GPG_TTY=$(tty)
# Ajouter à ~/.bashrc ou ~/.zshrc

# Erreur avec macOS
$ brew install pinentry-mac
$ echo "pinentry-program /usr/local/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf
$ gpgconf --kill gpg-agent

# Tester la signature
$ echo "test" | gpg --clearsign

💡 Alternative moderne : Git 2.34+ supporte la signature avec clés SSH (git config gpg.format ssh). Plus simple si vous avez déjà des clés SSH configurées.

Conclusion & Perspectives

🎓 Ce que vous avez appris

  • La philosophie et architecture interne de Git
  • La gestion avancée des branches et merges
  • Les outils de sauvetage (reset, reflog, stash)
  • La collaboration sécurisée (SSH, secrets, signing)
  • Le debugging avec blame, bisect, grep
  • Les workflows industriels (GitFlow, Trunk-Based)
  • La gestion des mono-repos et dépendances
  • Le disaster recovery et nettoyage d'historique

📚 Pour aller plus loin

📖 Ressources
🔧 Outils GUI
  • GitKraken, Sourcetree
  • VS Code Git Lens
  • GitHub Desktop
🚀 Pratique
  • Contribuer à l'open source
  • Configurer un projet avec CI/CD
  • Mettre en place des hooks

💡 Conseil final

Git est un outil puissant qui peut sembler intimidant. La clé est de pratiquer régulièrement et de ne pas avoir peur d'expérimenter — le reflog est là pour vous sauver. Avec le temps, les commandes avancées deviendront des réflexes.