02

🌿 Git Maîtrisé

Versioning, Branches & Scénarios Réels

"Le code source est la matière première de l'entreprise. Git n'est pas juste un outil de sauvegarde, c'est la machine à voyager dans le temps, l'espace de collaboration mondial et le filet de sécurité absolu du développeur."

🔥 Mise en situation : L'enfer du fichier "Final_v2_v3_OK.docx"
Avant Git, comment travaillait-on à plusieurs sur un code ? On utilisait un dossier partagé sur le réseau de l'entreprise. Alice modifiait le fichier "Index.html". Bob modifiait le même fichier en même temps. En sauvegardant, Bob écrasait le travail d'Alice. Résultat : une perte de données désastreuse.
Pour éviter cela, on créait des copies : "Index_Alice_vendredi.html", "Index_FINAL_FINAL_v3.html". Le projet devenait un dépotoir incompréhensible. Git résout définitivement ce problème archaïque en permettant à des milliers de développeurs de collaborer sur la même ligne de code sans jamais l'écraser sauvagement.

⚠️ Rappel : Versioning "Distribué" VS "Centralisé"

Git est un système de contrôle de version Décentralisé (Distribué).
Dans les anciens systèmes (comme SVN), un unique serveur central stockait tout l'historique du code. Si le serveur crachait ou si vous preniez l'avion (sans WiFi), impossible de voir les anciennes versions ou de valider son travail.
Avec Git, chaque développeur possède un clone intégral (100%) de l'historique et du code source sur son propre ordinateur. Vous pouvez "commiter" dans le TGV sans internet, et le système survit même si le serveur GitLab central explose.

⏳ Analogie : La Machine à Voyager dans le Temps

Imaginez Git comme une sauvegarde temporelle (Save State) de votre jeu vidéo ou de votre projet. Chaque commit est une photo instantanée. Si vous cassez tout la veille d'une livraison, vous pouvez littéralement remonter le temps jusqu'à l'instant précis du vendredi 15h00 pour rétablir votre code tel qu'il était, sans perdre le reste. Les branches sont des univers parallèles où vous pouvez expérimenter des fonctionnalités folles sans empoisonner la dimension principale (le `main`).

📖 Pourquoi Git est le standard absolu ?

Avant Git, les développeurs utilisaient des systèmes centralisés (SVN, Perforce). Si le serveur tombait, tout le monde s'arrêtait de travailler. Git est distribué :

  • Travail Offline : Chaque développeur a l'historique complet sur sa machine.
  • Branches légères : Créer une branche prend 1ms (c'est juste un pointeur).
  • Intégrité totale : Chaque commit est signé par un hash SHA-1 (impossible de modifier l'histoire sans que ça se voie).
  • Agilité : Permet de tester des idées folles sans polluer le code principal.

En DevOps, Git est la Source de Vérité. Si c'est pas dans Git, ça n'existe pas en production.

💡 Le saviez-vous ?

Linus Torvalds (créateur de Linux) a écrit la première version de Git en seulement 2 semaines en 2005. Il était furieux d'avoir perdu l'accès gratuit à BitKeeper et voulait un outil qui soit "tout l'inverse de CVS/SVN".

Aujourd'hui, 94% des développeurs utilisent Git.

main feature/login a1b2c3d v1.0.0 f8e1a12 9b3c4d5 Merge PR HEAD b2c4d6c e3f5a8b

📊 A. Anatomie du Flux Git

📂
Working Dir
Fichiers modifiés
📋
Staging
git add
💾
Local Repo
git commit
☁️
Remote
git push

⌨️ B. Commandes Essentielles

Commande Action Exemple
git clone Copier un repo distant en local git clone git@github.com:user/repo.git
git add Ajouter au staging (préparer le commit) git add . ou git add fichier.js
git commit Sauvegarder dans l'historique local git commit -m "feat: add login"
git push Envoyer les commits vers le remote git push origin main
git pull Récupérer les changements du remote git pull origin main
git branch Lister / Créer des branches git branch feature/login
git checkout Changer de branche / Restaurer fichier git checkout -b feature/api
git merge Fusionner une branche dans l'actuelle git merge feature/login
git rebase Réécrire l'historique (plus propre que merge) git rebase main
git stash Mettre de côté les modifs temporairement git stash puis git stash pop
git log Voir l'historique des commits git log --oneline -10
git reset Annuler des commits (⚠️ Dangereux) git reset --soft HEAD~1

🎬 C. Scénarios Réels (3 Cas)

🧑‍💻 Scénario 1 : Solo Developer

Vous travaillez seul sur un projet perso.

git clone - Récupérer le repo
git checkout -b feature/ma-fonctionnalité - Créer une branche
Coder, tester...
git add . && git commit -m "feat: ..." - Commit
git push origin feature/ma-fonctionnalité - Push
Créer une PR sur GitHub → Merge → Supprimer la branche

👥 Scénario 2 : Équipe (Feature Branch)

Vous développez en parallèle avec d'autres devs.

git pull origin main - Toujours partir d'un main à jour
git checkout -b feature/api-users - Votre branche
Coder la feature (plusieurs commits)
git fetch && git rebase origin/main - Se resynchroniser AVANT la PR
Résoudre les conflits si nécessaire
git push -f origin feature/api-users - Force push après rebase
PR → Code Review → Merge (Squash ou Rebase)
💡 Règle d'or : Rebaser AVANT de push, jamais après (sinon conflits pour les autres).

🚨 Scénario 3 : Hotfix en Production

Bug critique en prod, il faut corriger MAINTENANT.

git checkout main && git pull - Partir de la prod actuelle
git checkout -b hotfix/fix-crash-login - Branche hotfix
Corriger le bug (code minimal)
git commit -m "fix: resolve crash on login"
PR prioritaire → Review express → Merge dans main
Déployer immédiatement (CI/CD)
git cherry-pick <commit-hash> - Reporter le fix sur les autres branches si nécessaire

📊 Merge vs Rebase : Le Grand Débat

🌱 git merge

  • Non-destructif : Préserve l'historique complet et chronologique.
  • Traçabilité : On voit exactement quand les branches ont fusionné.
  • Pollution : Crée beaucoup de "Merge commits" (historique en spaghettis).
  • Conflits : Une seule grosse résolution de conflits à la fin.

🚀 git rebase

  • Historique Linéaire : Pas de commits de merge inutiles. C'est propre !
  • Plus lisible : Plus facile à suivre pour les autres développeurs.
  • Destructif : Réécrit l'histoire (⚠️ Ne jamais faire sur une branche publique partagee).
  • Conflits : On résout les conflits commit par commit (plus granulaire).

📊 Cas d'étude : Résolution de Conflits Explosive

42 Fichiers en conflit
3h Temps de résolution
0 Code perdu

Contexte : Deux équipes ont travaillé sur la même refacto majeure pendant 2 semaines sans se synchroniser. Au moment du merge : l'enfer.

Stratégie de survie :

  1. Isolation : On ne résout pas ça sur le main. On crée une branche de "sync".
  2. Communication : Les deux leads techniques s'asseyent ensemble (Pair Programming).
  3. Outils : Utilisation de git mergetool avec VS Code ou IntelliJ pour visualiser les "3-way merges".
  4. Granularité : Rebase interactif (git rebase -i) pour squasher les petits commits avant de merger.

Résultat : Migration réussie. Leçon Apprise : Synchronisez-vous tous les jours (git pull fréquent) pour éviter les "Merges de la mort".

🔄 À Retenir - Git Mastery

  • Git est distribué : Pas de SPOF (Single Point of Failure).
  • L'Atomicité : Un commit = une seule chose (une feature, un fix).
  • Conventional Commits : Utilisez feat:, fix:, docs: pour un historique clair.
  • Protection de Branche : Interdire de push directement sur main.
  • PR / Code Review : Git est avant tout un outil de collaboration et de qualité.

Git Flow vs Trunk Based

  • Trunk-Based (Moderne) : Une seule branche main. PRs ultra-courtes (< 24h). Nécessite tests solides.
  • Trunk-Based (Legacy) : Branches develop, release, hotfix. Crée des "Merge Hells".

Conventional Commits

Standardiser les messages pour automatiser le Changelog.

feat(auth): add google oauth login
fix(api): resolve timeout on user fetch
chore: update dependencies

🔧 D. Git Under the Hood

Git n'est pas magique. C'est un système de fichiers adressable par le contenu. Tout est stocké dans le dossier .git.

Structure du dossier .git
.git/
├── HEAD         # Pointeur actuel (ref: refs/heads/main)
├── config       # Config locale (remote url, user)
├── index        # La zone de Staging (binaire)
├── refs/        # Pointeurs (branches, tags)
│   ├── heads/   # Branches locales (main contient le hash)
│   └── remotes/ # Branches distantes
└── objects/     # LA BASE DE DONNÉES
    ├── a1/      # Hash SHA-1 (les 2 premiers chars)
    └── ...

Les 3 Objets Git

  • Blob : Le contenu d'un fichier (sans le nom).
  • Tree : Un dossier. Associe des noms de fichiers à des Blobs.
  • Commit : Metadonnées (Auteur, Date, Message) + Pointeur vers un Tree Racine + Pointeur vers le Parent.
SHA-1 : Tout changement (même un espace) change le Hash du Blob, donc du Tree, donc du Commit. L'historique est immuable.

🕵️ E. Advanced Debugging

🔍

Git Bisect

Trouver le commit qui a introduit un bug par dichotomie.
git bisect start
git bisect bad (ici)
git bisect good v1.0
Git vous balade dans l'historique jusqu'au coupable.

🚑

Git Reflog

Vous avez fait un reset --hard et tout perdu ?
NON ! git reflog liste TOUS les mouvements de HEAD (même les annulés).
git reset --hard HEAD@{1} pour revenir.

🧠

Git Rerere

"Reuse Recorded Resolution".
Git se souvient comment vous avez résolu un conflit. S'il se reproduit (ex: rebase interactif), il le résout tout seul.

🛑 Troubleshooting : Oups, j'ai tout cassé !

  • Commit sur la mauvaise branche : git reset --soft HEAD~1 (annule le commit mais garde les modifs), puis git checkout bonne-branche et re-commit.
  • Push de données sensibles (mot de passe) : N'utilisez SURTOUT PAS un simple git rm. Utilisez BFG Repo-Cleaner ou git filter-repo pour réécrire l'historique distant. CHANGER LE MOT DE PASSE IMMEDIATEMENT.
  • Conflits de Merge infinis : git merge --abort ou git rebase --abort pour tout annuler et revenir à l'état sain.

🚅 F. Performance & Large Files

🐘 Git LFS (Large File Storage)

Git est nul pour les gros fichiers binaires (PSD, MP4). Chaque modif re-stocke tout le fichier.

Solution : Git stocke un pointeur texte (2kb), et le fichier réel va dans un stockage à part (LFS Store).

git lfs track "*.psd"

🤏 Partial Clone & Shallow Clone

Le repo fait 10Go ? Pas besoin de tout télécharger.

  • Shallow (--depth 1) : Juste le dernier commit (idéal pour CI).
  • Partial (--filter=blob:none) : Télécharge l'historique mais PAS les fichiers. Les fichiers sont téléchargés à la demande (au checkout).

GitOps = IaC + PRs + Convergence Agent.

Au lieu de faire kubectl apply -f file.yaml (impératif, manuel), vous commitez le fichier yaml dans Git.

ArgoCD (l'agent dans le cluster) voit le changement Git, compare avec l'état réel, et force la synchronisation.

Git (Désiré) == Cluster (Réel)