# [COURS] EXERCICES GIT & GITHUB - PARTIE 1 (Exercices 1-3)

**10 exercices pratiques ultra-détaillés - De débutant à expert**

---

## [GUIDE] INTRODUCTION

Bienvenue dans cette série complète d'exercices Git et GitHub ! Ce document est la **Partie 1** d'un ensemble de 3 fichiers couvrant 10 exercices progressifs.

**[PACKAGE] Structure du cours :**
- **Partie 1** : Exercices 1-3 (Débutants) <- VOUS ÊTES ICI
- **Partie 2** : Exercices 4-6 (Intermédiaire/Avancé)
- **Partie 3** : Exercices 7-10 (Expert)

---

## [UTILISATEURS] L'ÉQUIPE DE DÉVELOPPEMENT

Vous allez suivre l'histoire de 5 développeurs travaillant sur le projet **TaskMaster** :

1. **Alice Martin** (Tech Lead) - `alice@devteam.com`
2. **Bob Diallo** (Senior Dev) - `bob@devteam.com`  
3. **Charlie Ndiaye** (Dev Backend) - `charlie@devteam.com`
4. **Diana Fall** (Dev Frontend) - `diana@devteam.com`
5. **Emma Sow** (DevOps) - `emma@devteam.com`

---

## [OBJECTIF] CE QUE VOUS APPRENDREZ

### [VERT] Exercice 1 : Premiers pas avec Git
- Installation et configuration
- Repository local et commits
- Les 3 zones de Git
- Historique et modifications

### [VERT] Exercice 2 : Branches et fusion
- Création de branches
- Navigation et merge
- Fast-forward vs 3-way merge
- Git stash

### [JAUNE] Exercice 3 : Collaboration GitHub
- Repository distant
- Push et pull
- Clone et fork
- Branches distantes

**Temps total estimé : 7-10 heures**

---

---

# [VERT] EXERCICE 1 : PREMIERS PAS AVEC GIT

## [LISTE] ÉNONCÉ

### Contexte professionnel

Tu es **Alice Martin**, nouvellement embauchée comme Tech Lead chez **DevTeam Solutions**. Le CTO te demande de créer un nouveau projet : **TaskMaster**, une application web de gestion de tâches.

**Mission :**
1. Initialiser un repository Git
2. Créer la structure du projet
3. Faire tes premiers commits
4. Comprendre l'historique Git

---

## [OBJECTIF] OBJECTIFS PÉDAGOGIQUES

À la fin de cet exercice, tu sauras :

- [OK] Installer et configurer Git
- [OK] Initialiser un repository
- [OK] Comprendre les 3 zones de Git
- [OK] Faire des commits
- [OK] Consulter l'historique
- [OK] Comparer les modifications
- [OK] Annuler des modifications

**Temps estimé : 2 heures**

---

## [DOCS] PRÉREQUIS

- Ordinateur (Linux, macOS ou Windows)
- Terminal / ligne de commande
- Éditeur de texte
- Aucune connaissance Git préalable

---

## [OK] SOLUTION COMPLÈTE

### ÉTAPE 1 : Installer Git

**Sur Ubuntu/Debian :**
```bash
sudo apt update
sudo apt install git -y
```

**Sur macOS :**
```bash
brew install git
```

**Sur Windows :**
Télécharger sur https://git-scm.com/download/win

**Vérifier l'installation :**
```bash
git --version
# Résultat attendu : git version 2.43.0 (ou plus)
```

[OK] **Git installé !**

---

### ÉTAPE 2 : Configurer Git

**Configuration globale :**
```bash
git config --global user.name "Alice Martin"
git config --global user.email "alice@devteam.com"
git config --global init.defaultBranch main
git config --global color.ui auto
```

**Vérifier :**
```bash
git config --list
```

[OK] **Git configuré !**

---

### ÉTAPE 3 : Créer le projet

```bash
mkdir TaskMaster
cd TaskMaster
git init
```

**Résultat :**
```
Initialized empty Git repository in /home/alice/TaskMaster/.git/
```

[OK] **Repository créé !**

---

### ÉTAPE 4 : Les 3 zones de Git

```
┌──────────────────────┐
│ Working Directory    │  Zone 1 : Fichiers que tu édites
│ (Fichiers modifiés)  │
└──────────┬───────────┘
           │ git add
           v
┌──────────────────────┐
│  Staging Area        │  Zone 2 : Préparation du commit
│  (Index)             │
└──────────┬───────────┘
           │ git commit
           v
┌──────────────────────┐
│  Repository          │  Zone 3 : Historique permanent
│  (.git/)             │
└──────────────────────┘
```

**Workflow :**
1. Modifier un fichier (Working Directory)
2. `git add` -> Staging Area
3. `git commit` -> Repository

---

### ÉTAPE 5 : Créer la structure du projet

```bash
# Dossiers
mkdir css js img

# Fichiers
touch index.html css/style.css js/app.js README.md
```

**Vérifier :**
```bash
git status
```

**Résultat :**
```
On branch main
Untracked files:
  README.md
  css/
  index.html
  js/
```

---

### ÉTAPE 6 : Ajouter du contenu

**README.md :**
```markdown
# TaskMaster

Application web de gestion de tâches.

## Fonctionnalités

- Créer des tâches
- Marquer comme terminées
- Supprimer des tâches

## Technologies

- HTML5
- CSS3
- JavaScript (ES6+)

## Auteur

Alice Martin - Tech Lead @ DevTeam Solutions
```

**index.html :**
```html
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>TaskMaster</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <div class="container">
        <h1>[NOTE] TaskMaster</h1>
        <p>Gérez vos tâches efficacement</p>
        
        <div class="task-input">
            <input type="text" id="taskInput" placeholder="Nouvelle tâche...">
            <button onclick="addTask()">Ajouter</button>
        </div>
        
        <ul id="taskList"></ul>
    </div>
    
    <script src="js/app.js"></script>
</body>
</html>
```

**css/style.css :**
```css
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Segoe UI', sans-serif;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
}

.container {
    background: white;
    padding: 2rem;
    border-radius: 10px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.3);
    max-width: 500px;
    width: 90%;
}

h1 {
    color: #667eea;
    margin-bottom: 0.5rem;
}

.task-input {
    display: flex;
    gap: 0.5rem;
    margin: 1rem 0;
}

#taskInput {
    flex: 1;
    padding: 0.8rem;
    border: 2px solid #ddd;
    border-radius: 5px;
}

button {
    padding: 0.8rem 1.5rem;
    background: #667eea;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
}

button:hover {
    background: #764ba2;
}
```

**js/app.js :**
```javascript
// TaskMaster - Version 1.0

let tasks = [];

function addTask() {
    const input = document.getElementById('taskInput');
    const taskText = input.value.trim();
    
    if (taskText === '') {
        alert('Veuillez entrer une tâche');
        return;
    }
    
    const task = {
        id: Date.now(),
        text: taskText,
        completed: false
    };
    
    tasks.push(task);
    input.value = '';
    renderTasks();
}

function renderTasks() {
    const taskList = document.getElementById('taskList');
    taskList.innerHTML = '';
    
    tasks.forEach(task => {
        const li = document.createElement('li');
        li.innerHTML = `
            <span>${task.text}</span>
            <button onclick="deleteTask(${task.id})">Supprimer</button>
        `;
        taskList.appendChild(li);
    });
}

function deleteTask(id) {
    tasks = tasks.filter(task => task.id !== id);
    renderTasks();
}
```

---

### ÉTAPE 7 : Premier commit

```bash
git add .
git status
```

**Résultat :**
```
Changes to be committed:
  new file:   README.md
  new file:   css/style.css
  new file:   index.html
  new file:   js/app.js
```

**Commiter :**
```bash
git commit -m "Initial commit: Structure de base du projet TaskMaster"
```

**Résultat :**
```
[main (root-commit) a1b2c3d] Initial commit: Structure de base du projet TaskMaster
 4 files changed, 150 insertions(+)
```

[OK] **Premier commit créé !**

---

### ÉTAPE 8 : Consulter l'historique

```bash
git log --oneline
```

**Résultat :**
```
a1b2c3d (HEAD -> main) Initial commit: Structure de base du projet TaskMaster
```

**Avec détails :**
```bash
git log
```

**Avec graphique :**
```bash
git log --oneline --graph --all
```

---

### ÉTAPE 9 : Deuxième commit

**Créer .gitignore :**
```bash
cat > .gitignore << EOF
# Système
.DS_Store
Thumbs.db

# Éditeurs
.vscode/
.idea/

# Dependencies
node_modules/

# Environnement
.env

# Logs
*.log
EOF
```

**Modifier README.md (ajouter à la fin) :**
```markdown

## Installation

1. Cloner le repository
2. Ouvrir index.html dans un navigateur
3. C'est tout !

## Licence

MIT
```

**Commiter :**
```bash
git add .
git commit -m "Ajout .gitignore et section Installation"
```

---

### ÉTAPE 10 : Modifier le dernier commit (amend)

**Oubli : Ajouter la version dans README :**
```bash
# Modifier la première ligne du README
sed -i '1s/TaskMaster/TaskMaster v1.0/' README.md

git add README.md
git commit --amend -m "Ajout .gitignore, Installation et version dans README"
```

[ATTENTION] **Ne jamais amend un commit déjà pushé !**

---

### ÉTAPE 11 : Annuler des modifications

**Simuler une erreur :**
```bash
echo "<h2>ERREUR</h2>" >> index.html
git status
```

**Annuler :**
```bash
git restore index.html
# Ou : git checkout -- index.html
```

**Retirer de la staging area :**
```bash
echo "// TODO" >> js/app.js
git add js/app.js
git restore --staged js/app.js
```

---

## [OK] TESTS DE VALIDATION

**1. Configuration Git**
```bash
git config user.name   # -> Alice Martin
git config user.email  # -> alice@devteam.com
```

**2. Repository initialisé**
```bash
ls -la .git/  # -> Dossier existe
```

**3. Commits créés**
```bash
git log --oneline  # -> Au moins 2 commits
```

**4. Working tree propre**
```bash
git status  # -> "working tree clean"
```

---

## [ROUGE] ERREURS COURANTES

### Erreur 1 : "Please tell me who you are"

**Solution :**
```bash
git config --global user.name "Votre Nom"
git config --global user.email "votre@email.com"
```

### Erreur 2 : "fatal: not a git repository"

**Solution :**
```bash
git init
```

### Erreur 3 : Annuler le dernier commit

**Garder les modifications :**
```bash
git reset --soft HEAD~1
```

**Supprimer les modifications (DANGER !) :**
```bash
git reset --hard HEAD~1
```

---

## [IMPORTANT] POINTS CLÉS À RETENIR

1. **Les 3 zones** : Working Directory -> Staging Area -> Repository
2. **Workflow** : Modifier -> `git add` -> `git commit`
3. **Commandes essentielles** :
   - `git init` : Initialiser
   - `git add` : Ajouter à staging
   - `git commit -m` : Créer commit
   - `git status` : État actuel
   - `git log` : Historique

4. **Messages de commit** :
   - Impératif présent : "Ajout" (pas "Ajouté")
   - < 50 caractères
   - Descriptif et concis

---

## [RAPIDE] POUR ALLER PLUS LOIN

**Alias Git :**
```bash
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
```

**git reflog** (récupérer commits perdus) :
```bash
git reflog
git reset --hard abc1234
```

---

## [COURS] CONCLUSION EXERCICE 1

[OK] **Félicitations ! Tu maîtrises les bases de Git !**

**Compétences acquises :**
- [OK] Installation et configuration
- [OK] Workflow git add/commit
- [OK] Historique et modifications
- [OK] Annulation de changements

**Prochaine étape :** Exercice 2 - Branches et fusion ! [HERB]

---

---

# [VERT] EXERCICE 2 : BRANCHES ET FUSION

## [LISTE] ÉNONCÉ

### Contexte professionnel

**Bob Diallo** (Senior Dev) rejoint le projet. Il va développer un **système de catégories** pour les tâches. Pendant ce temps, **Alice** améliore le design CSS.

**Problème :** Comment travailler en parallèle sans s'interférer ?

**Solution :** Les branches Git !

---

## [OBJECTIF] OBJECTIFS PÉDAGOGIQUES

À la fin de cet exercice, tu sauras :

- [OK] Créer et naviguer entre branches
- [OK] Faire des commits sur une branche
- [OK] Fusionner des branches (merge)
- [OK] Comprendre fast-forward vs 3-way merge
- [OK] Supprimer des branches
- [OK] Utiliser git stash

**Temps estimé : 2-3 heures**

---

## [OK] SOLUTION COMPLÈTE

### ÉTAPE 1 : Comprendre les branches

**Une branche = Une ligne de développement parallèle**

```
      main
        │
        [WHITE_CIRCLE] Commit 1
        │
        [WHITE_CIRCLE] Commit 2
       ╱│╲
      ╱ │ ╲
    f1  │  f2     (branches feature-1 et feature-2)
    │   │   │
    [WHITE_CIRCLE]   [WHITE_CIRCLE]   [WHITE_CIRCLE]     (commits sur les branches)
    │   │   │
     ╲  │  ╱
      ╲ │ ╱
        [WHITE_CIRCLE]         (merge)
        │
      main
```

**Voir les branches :**
```bash
git branch
# Résultat : * main
```

---

### ÉTAPE 2 : Bob crée une branche

**Simuler Bob :**
```bash
git config user.name "Bob Diallo"
git config user.email "bob@devteam.com"
```

**Créer et basculer sur la branche :**
```bash
git checkout -b feature/categories
# Ou : git switch -c feature/categories
```

**Vérifier :**
```bash
git branch
# Résultat :
#   * feature/categories
#     main
```

---

### ÉTAPE 3 : Bob développe les catégories

**Modifier index.html (ajouter sélecteur) :**
```html
<div class="task-input">
    <input type="text" id="taskInput" placeholder="Nouvelle tâche...">
    <select id="categorySelect">
        <option value="personnel">[LIVRE] Personnel</option>
        <option value="travail">[PRO] Travail</option>
        <option value="urgent">[ALERTE] Urgent</option>
    </select>
    <button onclick="addTask()">Ajouter</button>
</div>
```

**Modifier js/app.js (gérer catégories) :**
```javascript
function addTask() {
    const input = document.getElementById('taskInput');
    const categorySelect = document.getElementById('categorySelect');
    const taskText = input.value.trim();
    const category = categorySelect.value;
    
    if (taskText === '') {
        alert('Veuillez entrer une tâche');
        return;
    }
    
    const task = {
        id: Date.now(),
        text: taskText,
        category: category,
        completed: false
    };
    
    tasks.push(task);
    input.value = '';
    renderTasks();
}

function renderTasks() {
    const taskList = document.getElementById('taskList');
    taskList.innerHTML = '';
    
    tasks.forEach(task => {
        const li = document.createElement('li');
        li.className = `task-item category-${task.category}`;
        li.innerHTML = `
            <span>${task.text}</span>
            <span class="category-badge">${getCategoryLabel(task.category)}</span>
            <button onclick="deleteTask(${task.id})">Supprimer</button>
        `;
        taskList.appendChild(li);
    });
}

function getCategoryLabel(category) {
    const labels = {
        'personnel': '[LIVRE] Personnel',
        'travail': '[PRO] Travail',
        'urgent': '[ALERTE] Urgent'
    };
    return labels[category] || category;
}
```

**Ajouter styles CSS :**
```css
#categorySelect {
    padding: 0.8rem;
    border: 2px solid #ddd;
    border-radius: 5px;
}

.category-badge {
    padding: 0.3rem 0.8rem;
    border-radius: 15px;
    font-size: 0.85rem;
    font-weight: bold;
}

.category-personnel {
    border-left: 4px solid #4A90E2;
}

.category-travail {
    border-left: 4px solid #F5A623;
}

.category-urgent {
    border-left: 4px solid #D0021B;
}
```

**Commiter :**
```bash
git add .
git commit -m "Ajout système de catégories pour les tâches"
```

---

### ÉTAPE 4 : Alice améliore le design

**Retourner sur main :**
```bash
git checkout main
git config user.name "Alice Martin"
git config user.email "alice@devteam.com"
```

**Vérifier :**
```bash
cat index.html | grep categorySelect
# -> Aucun résultat ! Les modifs de Bob ne sont PAS sur main
```

**Créer branche design :**
```bash
git checkout -b feature/design-improvement
```

**Ajouter animations CSS :**
```css
body {
    animation: gradientShift 15s ease infinite;
}

@keyframes gradientShift {
    0%, 100% { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }
    50% { background: linear-gradient(135deg, #764ba2 0%, #667eea 100%); }
}

.container {
    animation: fadeIn 0.5s ease;
}

@keyframes fadeIn {
    from { opacity: 0; transform: translateY(20px); }
    to { opacity: 1; transform: translateY(0); }
}

#taskList li {
    transition: all 0.3s ease;
}

#taskList li:hover {
    transform: translateX(5px);
    box-shadow: 0 5px 15px rgba(0,0,0,0.2);
}
```

**Commiter :**
```bash
git add css/style.css
git commit -m "Amélioration design : animations et responsive"
```

---

### ÉTAPE 5 : Visualiser les branches

```bash
git log --oneline --all --graph
```

**Résultat :**
```
* e5f6g7h (HEAD -> feature/design-improvement) Amélioration design
| * d4e5f6g (feature/categories) Ajout catégories
|/
* c3d4e5f (main) Ajout .gitignore
* a1b2c3d Initial commit
```

**Les deux branches ont divergé !**

---

### ÉTAPE 6 : Merger la branche de Bob (fast-forward)

```bash
git checkout main
git merge feature/categories
```

**Résultat :**
```
Updating c3d4e5f..d4e5f6g
Fast-forward
 css/style.css | 20 ++++++++++++++
 index.html    | 5 +++-
 js/app.js     | 30 +++++++++++++++++---
```

**Fast-forward = Git avance simplement main vers le commit de la branche**

```
AVANT :
  main -> [WHITE_CIRCLE] c3d4e5f
          │
          [WHITE_CIRCLE] d4e5f6g (feature/categories)

APRÈS :
  main, feature/categories -> [WHITE_CIRCLE] d4e5f6g
```

---

### ÉTAPE 7 : Merger la branche design (3-way merge)

```bash
git merge feature/design-improvement
```

**Git ouvre l'éditeur pour le message de merge. Sauvegarder.**

**Résultat :**
```
Merge made by the 'ort' strategy.
 css/style.css | 35 ++++++++++++++++++++++++++
```

**3-way merge = Crée un commit de merge avec 2 parents**

```
         main
           │
           [WHITE_CIRCLE] f6g7h8i (commit de merge)
          ╱│╲
         ╱ │ ╲
        [WHITE_CIRCLE]  │  [WHITE_CIRCLE]
       d4e5f6g  e5f6g7h
```

---

### ÉTAPE 8 : Supprimer les branches mergées

```bash
git branch -d feature/categories
git branch -d feature/design-improvement
```

**`-d` = Supprime seulement si mergée (sécurité)**
**`-D` = Force la suppression (DANGER)**

---

### ÉTAPE 9 : Git stash (sauvegarder temporairement)

**Situation : Tu commences une feature mais dois basculer sur main**

```bash
git checkout -b feature/filters
echo "<!-- Filtres -->" >> index.html
git status  # -> Modifications non commitées
```

**Sauvegarder avec stash :**
```bash
git stash push -m "WIP: Filtres"
git status  # -> Working tree clean !
```

**Basculer sur main :**
```bash
git checkout main
# ... faire correction urgente ...
git checkout feature/filters
```

**Récupérer le stash :**
```bash
git stash pop
```

**Commandes stash :**
- `git stash` : Sauvegarder
- `git stash list` : Voir le stash
- `git stash pop` : Appliquer + supprimer
- `git stash apply` : Appliquer (garder)
- `git stash drop` : Supprimer

---

## [OK] TESTS DE VALIDATION

**1. Branches créées et mergées**
```bash
git log --oneline --graph
# -> Voir les merges
```

**2. Fast-forward vs 3-way**
- [ ] Comprendre la différence
- [ ] Identifier dans l'historique

**3. Stash fonctionnel**
```bash
git stash list  # -> Vide si tout appliqué
```

---

## [ROUGE] ERREURS COURANTES

### Erreur 1 : "Please commit or stash before switching"

**Solution :**
```bash
git stash
git checkout autre_branche
# Plus tard :
git stash pop
```

### Erreur 2 : Suppression branche non mergée

```
error: The branch 'feature/xyz' is not fully merged.
```

**Solution :**
```bash
git branch -D feature/xyz  # Si vraiment sûr
# Ou merger d'abord
```

---

## [IMPORTANT] POINTS CLÉS À RETENIR

1. **Branches** = Développement parallèle
2. **Merge types** :
   - Fast-forward : Historique linéaire
   - 3-way : Commit de merge avec 2 parents
3. **Commandes** :
   - `git branch nom` : Créer
   - `git checkout -b nom` : Créer + basculer
   - `git merge branche` : Fusionner
   - `git branch -d nom` : Supprimer
4. **Stash** : Sauvegarder temporairement

---

## [COURS] CONCLUSION EXERCICE 2

[OK] **Félicitations ! Tu maîtrises les branches !**

**Compétences acquises :**
- [OK] Création et navigation de branches
- [OK] Merge (fast-forward et 3-way)
- [OK] Git stash
- [OK] Visualisation avec --graph

**Prochaine étape :** Exercice 3 - Collaboration GitHub ! [WEB]

---

---

# [JAUNE] EXERCICE 3 : COLLABORATION AVEC GITHUB

## [LISTE] ÉNONCÉ

### Contexte professionnel

Le CTO demande maintenant :
1. Héberger le code sur **GitHub**
2. **Charlie Ndiaye** rejoint l'équipe
3. Workflow de collaboration

**Objectifs :**
- Repository GitHub
- Push/Pull
- Clone
- Collaboration à plusieurs

---

## [OBJECTIF] OBJECTIFS PÉDAGOGIQUES

À la fin de cet exercice, tu sauras :

- [OK] Créer un repository GitHub
- [OK] Configurer SSH
- [OK] Push et pull
- [OK] Cloner un repository
- [OK] Gérer les branches distantes
- [OK] Collaborer à plusieurs

**Temps estimé : 2-3 heures**

---

## [OK] SOLUTION COMPLÈTE

### ÉTAPE 1 : Créer un compte GitHub

**Aller sur : https://github.com**

1. Cliquer "Sign up"
2. Email, mot de passe, username
3. Vérifier l'email

[OK] **Compte créé !**

---

### ÉTAPE 2 : Configurer SSH

**Vérifier si clé existe :**
```bash
ls -la ~/.ssh/id_*.pub
```

**Générer une clé :**
```bash
ssh-keygen -t ed25519 -C "alice@devteam.com"
```

**Afficher la clé publique :**
```bash
cat ~/.ssh/id_ed25519.pub
```

**Sur GitHub :**
1. Settings -> SSH and GPG keys
2. New SSH key
3. Coller la clé publique
4. Add SSH key

**Tester :**
```bash
ssh -T git@github.com
# -> Hi AliceMartin! You've successfully authenticated...
```

[OK] **SSH configuré !**

---

### ÉTAPE 3 : Créer repository GitHub

**Sur GitHub :**
1. Click "+" -> New repository
2. Name: `TaskMaster`
3. Public
4. **NE PAS** cocher "Initialize with README"
5. Create repository

---

### ÉTAPE 4 : Lier local -> GitHub

```bash
git remote add origin git@github.com:AliceMartin/TaskMaster.git
# [ATTENTION] Remplacer AliceMartin par ton username !
```

**Vérifier :**
```bash
git remote -v
# Résultat :
# origin  git@github.com:AliceMartin/TaskMaster.git (fetch)
# origin  git@github.com:AliceMartin/TaskMaster.git (push)
```

---

### ÉTAPE 5 : Push vers GitHub

```bash
git push -u origin main
```

**Résultat :**
```
Enumerating objects: 15, done.
Counting objects: 100% (15/15), done.
Writing objects: 100% (15/15), 3.45 KiB, done.
To github.com:AliceMartin/TaskMaster.git
 * [new branch]      main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.
```

**`-u` = Configure le tracking (après, juste `git push` suffit)**

[OK] **Code sur GitHub !**

---

### ÉTAPE 6 : Charlie clone le repository

**Simuler Charlie :**
```bash
cd ..
mkdir charlie-workspace
cd charlie-workspace
```

**Cloner :**
```bash
git clone git@github.com:AliceMartin/TaskMaster.git
cd TaskMaster
```

**Configurer identité :**
```bash
git config user.name "Charlie Ndiaye"
git config user.email "charlie@devteam.com"
```

[OK] **Repository cloné !**

---

### ÉTAPE 7 : Charlie fait des modifications

**Créer branche :**
```bash
git checkout -b feature/task-counter
```

**Modifier index.html (ajouter compteur) :**
```html
<p id="taskCounter">Nombre de tâches : 0</p>
```

**Modifier js/app.js (mettre à jour compteur) :**
```javascript
function renderTasks() {
    // ... code existant ...
    
    // Mettre à jour le compteur
    const counter = document.getElementById('taskCounter');
    counter.textContent = `Nombre de tâches : ${tasks.length}`;
}
```

**Commiter et pusher :**
```bash
git add .
git commit -m "Ajout compteur de tâches"
git push -u origin feature/task-counter
```

[OK] **Branche poussée sur GitHub !**

---

### ÉTAPE 8 : Alice récupère les modifications

**Retourner workspace Alice :**
```bash
cd ../../TaskMaster
```

**Récupérer les infos du remote :**
```bash
git fetch origin
```

**Résultat :**
```
From github.com:AliceMartin/TaskMaster
 * [new branch]      feature/task-counter -> origin/feature/task-counter
```

**Voir branches distantes :**
```bash
git branch -r
# Résultat :
#   origin/main
#   origin/feature/task-counter
```

**Créer branche locale qui suit la distante :**
```bash
git checkout feature/task-counter
# Git crée automatiquement et configure le tracking
```

**Merger dans main :**
```bash
git checkout main
git merge feature/task-counter
git push
```

[OK] **Collaboration fonctionnelle !**

---

### ÉTAPE 9 : git fetch vs git pull

**`git fetch origin`** :
- Récupère les infos du remote
- NE modifie PAS le working directory
- Opération SAFE

**`git pull origin main`** :
- = `git fetch` + `git merge`
- Récupère ET merge automatiquement
- Peut créer des conflits

**Recommandation : Utiliser `fetch` puis `merge` manuellement**

---

### ÉTAPE 10 : Comprendre origin

**`origin` = Nom par défaut du remote principal**

**Voir tous les remotes :**
```bash
git remote -v
```

**Ajouter un autre remote :**
```bash
git remote add upstream https://github.com/original/repo.git
```

**Renommer origin :**
```bash
git remote rename origin github
```

**Supprimer un remote :**
```bash
git remote remove upstream
```

---

## [OK] TESTS DE VALIDATION

**1. Repository GitHub créé**
- [ ] Visible sur github.com

**2. Push fonctionnel**
```bash
git push  # -> Pas d'erreur
```

**3. Clone et collaboration**
- [ ] Charlie peut cloner
- [ ] Push de Charlie visible par Alice

**4. Fetch vs Pull**
- [ ] Comprendre la différence

---

## [ROUGE] ERREURS COURANTES

### Erreur 1 : Permission denied (publickey)

**Solution :**
```bash
# Vérifier SSH
ssh -T git@github.com
# Si erreur, régénérer clé et l'ajouter sur GitHub
```

### Erreur 2 : ! [rejected] (non-fast-forward)

**Cause : Quelqu'un a pushé entre temps**

**Solution :**
```bash
git pull --rebase
git push
```

### Erreur 3 : fatal: 'origin' does not appear to be a git repository

**Solution :**
```bash
git remote add origin git@github.com:username/repo.git
```

---

## [IMPORTANT] POINTS CLÉS À RETENIR

1. **GitHub = Hébergement Git distant**
2. **SSH** recommandé (pas HTTPS)
3. **Workflow** :
   - `git clone` : Première fois
   - `git fetch` : Récupérer infos
   - `git pull` : fetch + merge
   - `git push` : Envoyer commits
4. **origin** = Remote principal
5. **Branches distantes** : `origin/nom`

---

## [RAPIDE] POUR ALLER PLUS LOIN

**Fork :**
- Copie d'un repo sur ton compte
- Pour contribuer à des projets open source

**Pull Request (on verra dans l'exercice 5)**

**GitHub CLI :**
```bash
gh repo create
gh pr create
```

---

## [COURS] CONCLUSION EXERCICE 3

[OK] **Félicitations ! Tu sais collaborer avec GitHub !**

**Compétences acquises :**
- [OK] Repository GitHub
- [OK] SSH
- [OK] Push/Pull/Clone
- [OK] Branches distantes
- [OK] Collaboration

---

## [BRAVO] CONCLUSION DE LA PARTIE 1

**Félicitations ! Tu as terminé les 3 premiers exercices !**

**Récapitulatif :**

[OK] **Exercice 1** : Bases de Git (commits, historique)
[OK] **Exercice 2** : Branches et fusion
[OK] **Exercice 3** : Collaboration GitHub

**Compétences totales acquises :**
- [OK] Workflow Git complet
- [OK] Gestion de branches
- [OK] Collaboration avec GitHub

**Temps total Partie 1 : 7-10 heures**

**Continue avec la Partie 2 pour les exercices 4-6 (Intermédiaire/Avancé) !** [RAPIDE]

---

**FIN DE LA PARTIE 1**

# [COURS] EXERCICES GIT & GITHUB - PARTIE 2 (Exercices 4-6)

**Suite de la Partie 1 - Exercices Intermédiaires et Avancés**

---

# [JAUNE] EXERCICE 4 : GESTION DES CONFLITS

## [LISTE] ÉNONCÉ

### Contexte professionnel

Alice et Charlie travaillent en parallèle sur TaskMaster. Alice améliore le CSS pendant que Charlie modifie aussi le CSS pour un thème sombre. Quand ils essaient de merger, Git détecte un **CONFLIT** !

### Mission

Apprendre à résoudre les conflits Git professionnellement.

---

## [OBJECTIF] OBJECTIFS PÉDAGOGIQUES

- [OK] Comprendre les causes des conflits
- [OK] Identifier et résoudre les conflits manuellement
- [OK] Utiliser git mergetool
- [OK] Prévenir les conflits
- [OK] Gérer les conflits dans les PRs

---

## [OK] SOLUTION COMPLÈTE

### ÉTAPE 1 : Créer un conflit volontairement

**Alice modifie le CSS :**

```bash
cd ~/TaskMaster
git checkout -b feature/improve-colors

# Modifier css/style.css
nano css/style.css
# Changer background: en rouge-bleu
```

**Commiter et merger dans main :**

```bash
git add css/style.css
git commit -m "Amélioration couleurs: rouge-bleu"
git checkout main
git merge feature/improve-colors
git push
```

---

**Charlie modifie le même CSS (sans pull) :**

```bash
cd ~/charlie-workspace/TaskMaster
git checkout -b feature/dark-theme

# Modifier css/style.css - même lignes
nano css/style.css
# Changer background: en gris-noir

git add css/style.css
git commit -m "Ajout thème sombre"
```

---

### ÉTAPE 2 : Tenter le merge -> CONFLIT

```bash
git checkout main
git pull  # Récupère les changements d'Alice
git merge feature/dark-theme
```

**[IMPACT] CONFLIT ! [IMPACT]**

```
CONFLICT (content): Merge conflict in css/style.css
Automatic merge failed; fix conflicts and then commit the result.
```

---

### ÉTAPE 3 : Examiner le conflit

```bash
nano css/style.css
```

**Marqueurs de conflit :**

```css
<<<<<<< HEAD
background: linear-gradient(135deg, #FF6B6B 0%, #4ECDC4 100%);
=======
background: linear-gradient(135deg, #2C3E50 0%, #34495E 100%);
>>>>>>> feature/dark-theme
```

**Explication :**
- `<<<<<<< HEAD` : Version actuelle (main)
- `=======` : Séparateur
- `>>>>>>> feature/dark-theme` : Version de la branche

---

### ÉTAPE 4 : Résoudre le conflit

**Stratégie : Combiner les deux (thème switcher)**

```css
/* Variables CSS pour thèmes */
:root {
    --bg-start: #FF6B6B;
    --bg-end: #4ECDC4;
}

body.dark-theme {
    --bg-start: #2C3E50;
    --bg-end: #34495E;
}

body {
    background: linear-gradient(135deg, var(--bg-start) 0%, var(--bg-end) 100%);
}
```

**Ajouter bouton de switch dans index.html :**

```html
<button onclick="document.body.classList.toggle('dark-theme')">
    [CRESCENT_MOON] Toggle Theme
</button>
```

---

### ÉTAPE 5 : Finaliser le merge

```bash
git add css/style.css index.html
git commit -m "Merge: Combine themes with switcher

Résolution conflit en créant un système de thème
- Thème clair (Alice)
- Thème sombre (Charlie)
- Bouton toggle"
```

**[OK] Conflit résolu !**

---

### ÉTAPE 6 : Utiliser git mergetool

**Installer meld (Linux) :**

```bash
sudo apt install meld -y
git config --global merge.tool meld
```

**Lors d'un conflit :**

```bash
git mergetool
```

**Meld ouvre avec 3 panneaux :**
- LOCAL (votre version)
- BASE (ancêtre commun)
- REMOTE (leur version)
- MERGED (résultat)

**Sélectionner les changements à garder visuellement.**

---

## [ROUGE] ERREURS COURANTES

### Erreur 1 : Oubli de supprimer les marqueurs

**Symptôme : Code cassé avec `<<<<<<<` visible**

**Solution : Hook pre-commit**

```bash
nano .git/hooks/pre-commit
```

```bash
#!/bin/bash
if git diff --cached | grep -E '^(\+<<<<<<<|^\+=======|^\+>>>>>>>)'; then
    echo "[X] Marqueurs de conflit détectés !"
    exit 1
fi
```

```bash
chmod +x .git/hooks/pre-commit
```

---

### Erreur 2 : Mauvaise version choisie

**Solution : Annuler le merge**

```bash
git merge --abort  # Si pas encore commité
git reset --hard HEAD~1  # Si déjà commité
```

---

## [IMPORTANT] POINTS CLÉS

1. **Conflits = normaux** lors de travail collaboratif
2. **Anatomie** : `<<<<<<<`, `=======`, `>>>>>>>`
3. **Résolution** : Éditer -> `git add` -> `git commit`
4. **Prévention** : Communication + pull fréquent
5. **Outils** : mergetool pour conflits complexes

---

## [RAPIDE] POUR ALLER PLUS LOIN

**Diff3 (voir l'ancêtre commun) :**

```bash
git config --global merge.conflictstyle diff3
```

**Résultat :**

```
<<<<<<< HEAD
Version actuelle
||||||| merged common ancestors
Version originale
=======
Autre version
>>>>>>>
```

**rerere (Reuse Recorded Resolution) :**

```bash
git config --global rerere.enabled true
```

Git se souvient de vos résolutions !

---

**Temps moyen : 2h**

**Prochaine étape : Exercice 5 - Pull Requests et Code Review ! [RECHERCHE]**

---

---

# [JAUNE] EXERCICE 5 : PULL REQUESTS ET CODE REVIEW

## [LISTE] ÉNONCÉ

### Contexte professionnel

Le CTO impose des règles strictes :
- [X] Interdit de pusher sur main
- [OK] Obligatoire : Pull Requests avec 2 reviews minimum

Diana va créer un système de filtres via une PR complète.

---

## [OBJECTIF] OBJECTIFS PÉDAGOGIQUES

- [OK] Créer une Pull Request
- [OK] Reviewer du code
- [OK] Répondre aux commentaires
- [OK] Merger une PR (squash/merge/rebase)
- [OK] Protéger les branches
- [OK] Templates de PR

---

## [OK] SOLUTION COMPLÈTE

### ÉTAPE 1 : Protéger la branche main

**Sur GitHub :**

1. Settings -> Branches -> Add rule
2. Branch name pattern : `main`
3. Cocher :
   - [OK] Require pull request before merging
   - [OK] Require approvals: 2
   - [OK] Dismiss stale approvals
   - [OK] Require conversation resolution

**[OK] main protégée !**

**Tester :**

```bash
echo "test" >> README.md
git add README.md
git commit -m "Test push direct"
git push
```

**Résultat :**

```
remote: error: GH006: Protected branch update failed
error: failed to push
```

**[X] Rejeté ! On DOIT passer par une PR.**

---

### ÉTAPE 2 : Diana crée une feature

```bash
cd ~/diana-workspace/TaskMaster
git checkout -b feature/task-filters

# Ajouter filtres dans index.html
nano index.html
```

**Ajouter :**

```html
<div class="filters">
    <button class="filter-btn active" data-filter="all">Toutes</button>
    <button class="filter-btn" data-filter="personnel">[LIVRE] Personnel</button>
    <button class="filter-btn" data-filter="travail">[PRO] Travail</button>
    <button class="filter-btn" data-filter="urgent">[ALERTE] Urgent</button>
</div>
```

**Ajouter JavaScript dans js/app.js :**

```javascript
// Filtrage
document.querySelectorAll('.filter-btn').forEach(btn => {
    btn.addEventListener('click', (e) => {
        document.querySelectorAll('.filter-btn').forEach(b => 
            b.classList.remove('active')
        );
        e.target.classList.add('active');
        
        const filter = e.target.dataset.filter;
        document.querySelectorAll('.task-item').forEach(task => {
            if (filter === 'all' || task.dataset.category === filter) {
                task.classList.remove('hidden');
            } else {
                task.classList.add('hidden');
            }
        });
    });
});
```

**CSS dans css/style.css :**

```css
.filters {
    display: flex;
    gap: 0.5rem;
    margin: 1rem 0;
}

.filter-btn {
    padding: 0.5rem 1rem;
    background: white;
    color: #667eea;
    border: 2px solid #667eea;
    border-radius: 20px;
    cursor: pointer;
}

.filter-btn.active {
    background: #667eea;
    color: white;
}

.task-item.hidden {
    display: none;
}
```

---

**Commiter :**

```bash
git add .
git commit -m "feat: Add task filtering system

- Filter buttons (All, Personal, Work, Urgent)
- JavaScript filtering logic
- CSS styles for active state
- Hide/show tasks based on category"
```

**Pousser :**

```bash
git push -u origin feature/task-filters
```

---

### ÉTAPE 3 : Ouvrir une Pull Request

**Sur GitHub :**

1. Après le push, cliquer sur "Compare & pull request"
2. Ou : Pull requests -> New pull request

**Remplir :**

**Title :**
```
feat: Add task filtering system
```

**Description :**

```markdown
## [OBJECTIF] Objectif

Ajouter filtres pour tâches par catégorie

## [OK] Changements

- 4 boutons de filtre
- Logique JavaScript
- Styles CSS
- Utilisation de data-category

## [OK] Checklist

- [x] Code testé localement
- [x] Pas de console.log
- [x] Responsive
```

**Assignees :** Diana  
**Reviewers :** Alice, Bob  
**Labels :** `enhancement`, `frontend`

**Create pull request**

---

### ÉTAPE 4 : Alice et Bob reviewent

**Alice ouvre la PR -> Files changed**

**Commentaire sur une ligne :**

```
[IDEE] Suggestion : Au lieu de addEventListener en JS,
envisager d'utiliser la délégation d'événements
pour meilleures performances.
```

**Alice : Request changes**

```
Bon travail ! Quelques suggestions mineures.
Une fois corrigé, j'approuverai ! [BIEN]
```

---

**Bob review :**

```
LGTM! [RAPIDE] (Looks Good To Me)

Code propre et fonctionnalité utile.
```

**Bob : Approve [OK]**

---

**Statut PR :**

```
[OK] Bob approved
[ATTENTION] Alice requested changes
```

**Impossible de merger sans l'approbation d'Alice.**

---

### ÉTAPE 5 : Diana corrige

```bash
cd ~/diana-workspace/TaskMaster
git checkout feature/task-filters

# Refactoring avec délégation d'événements
nano js/app.js
```

**Modifier :**

```javascript
// Délégation d'événements (meilleure performance)
document.querySelector('.filters').addEventListener('click', (e) => {
    if (!e.target.classList.contains('filter-btn')) return;
    
    document.querySelectorAll('.filter-btn').forEach(b => 
        b.classList.remove('active')
    );
    e.target.classList.add('active');
    
    const filter = e.target.dataset.filter;
    document.querySelectorAll('.task-item').forEach(task => {
        task.classList.toggle('hidden', 
            filter !== 'all' && task.dataset.category !== filter
        );
    });
});
```

**Commiter et pousser :**

```bash
git add js/app.js
git commit -m "refactor: Use event delegation for filters

- Better performance
- Single event listener
- Cleaner code"
git push
```

**La PR est automatiquement mise à jour ! [BRAVO]**

---

**Diana répond au commentaire :**

```
@AliceMartin Excellente suggestion !
J'ai refactorisé avec délégation d'événements.
Prêt pour une nouvelle review ! [BIEN]
```

---

### ÉTAPE 6 : Alice approuve

**Alice revoit les changements :**

```
Perfect! [BRAVO]
Approved! [OK]
```

**Statut PR :**

```
[OK] Alice approved
[OK] Bob approved
All checks passed [OK]
```

**[OK] Prête à merger !**

---

### ÉTAPE 7 : Merger la PR

**Trois options :**

**1. Merge commit** (conserve tous les commits)

```
* Merge pull request #5
|\
| * refactor: Use event delegation
| * feat: Add task filtering
|/
```

**2. Squash and merge** * (1 PR = 1 commit)

```
* feat: Add task filtering (#5)
```

**3. Rebase and merge** (linéaire)

```
* refactor: Use event delegation
* feat: Add task filtering
```

---

**Diana choisit : Squash and merge**

**Message final :**

```
feat: Add task filtering system (#5)

- Filter buttons (All, Personal, Work, Urgent)
- JavaScript filtering with event delegation
- CSS styles
- Responsive design
```

**Confirm squash and merge**

**[OK] PR mergée ! [BRAVO]**

**Supprimer la branche : Delete branch**

---

### ÉTAPE 8 : Mettre à jour les repos locaux

**Tous les membres :**

```bash
git checkout main
git pull
```

**Diana nettoie localement :**

```bash
git branch -d feature/task-filters
git fetch --prune
```

---

### ÉTAPE 9 : Template de PR

**Créer `.github/pull_request_template.md` :**

```markdown
## [OBJECTIF] Description

<!-- Décrivez les changements -->

## [LIEN] Issue liée

<!-- Closes #123 -->

## [OK] Type de changement

- [ ] [BUG] Bug fix
- [ ] * New feature
- [ ] [OUTIL] Refactoring
- [ ] [NOTE] Documentation

## [OK] Checklist

- [ ] Code testé
- [ ] Tests passent
- [ ] Pas de console.log
- [ ] Documentation mise à jour

## [NOTE] Notes

<!-- Infos supplémentaires pour reviewers -->
```

**Commiter :**

```bash
git add .github/pull_request_template.md
git commit -m "chore: Add PR template"
git push
```

**Maintenant, chaque nouvelle PR aura ce template ! [OK]**

---

## [ROUGE] ERREURS COURANTES

### Erreur 1 : Conflit dans une PR

**Solution :**

```bash
git checkout ma-branche
git merge main  # Ou git rebase main
# Résoudre conflits
git add .
git commit
git push
```

**La PR se met à jour automatiquement.**

---

### Erreur 2 : Mauvaise branche de base

**Sur GitHub, dans la PR :**

Cliquer "Edit" à côté de "base: develop"  
Changer pour "base: main"

---

## [IMPORTANT] POINTS CLÉS

1. **PR = Proposition de changement** (pas push direct)
2. **Code Review obligatoire** (qualité + partage de connaissance)
3. **Workflow** : Branch -> PR -> Review -> Corrections -> Merge
4. **Protection** : Empêche les erreurs
5. **Squash** : Historique propre (1 PR = 1 commit)

---

## [RAPIDE] POUR ALLER PLUS LOIN

**CODEOWNERS (auto-assign reviewers) :**

```
# .github/CODEOWNERS
*.html @DianaFall
*.css @DianaFall
/js/ @DianaFall
*.py @CharlieNdiaye
```

**GitHub CLI :**

```bash
gh pr create --title "feat: X" --body "Description"
gh pr list
gh pr view 5
gh pr merge 5 --squash
gh pr checkout 5
```

---

**Temps moyen : 2-3h**

**Prochaine étape : Exercice 6 - Git Flow ! [HERB]**

---

---

# [ROUGE] EXERCICE 6 : GIT FLOW ET STRATÉGIES DE BRANCHES

## [LISTE] ÉNONCÉ

### Contexte professionnel

TaskMaster a 1000+ utilisateurs. Le CTO veut professionnaliser le workflow :
- Releases planifiées (v1.1, v1.2)
- Hotfixes urgents
- Features en parallèle

**Solution : Git Flow**

---

## [OBJECTIF] OBJECTIFS PÉDAGOGIQUES

- [OK] Comprendre Git Flow
- [OK] Implémenter develop/main/feature/release/hotfix
- [OK] Gérer des releases avec tags
- [OK] Faire des hotfixes
- [OK] Comparer les stratégies (Git Flow, GitHub Flow, GitLab Flow)
- [OK] Utiliser git-flow CLI

---

## [OK] SOLUTION COMPLÈTE

### ÉTAPE 1 : Architecture Git Flow

**Branches principales (permanentes) :**

```
main (production)
  │
develop (intégration)
```

**Branches de support (temporaires) :**

```
feature/* -> develop
release/* -> main + develop
hotfix/* -> main + develop
```

---

**Workflow visuel :**

```
main:     [BLACK_CIRCLE]─────[BLACK_CIRCLE]───────[BLACK_CIRCLE]
          v1.0  │       v1.1
                │        ^
release:        └──[BLACK_CIRCLE]──[BLACK_CIRCLE]──┘
                      │
develop:  [BLACK_CIRCLE]───[BLACK_CIRCLE]───[BLACK_CIRCLE]───[BLACK_CIRCLE]───[BLACK_CIRCLE]
          │   │   │
feature:  [BLACK_CIRCLE]───┘   [BLACK_CIRCLE]───────┘
```

---

### ÉTAPE 2 : Initialiser Git Flow

**Créer develop :**

```bash
cd ~/TaskMaster
git checkout main
git pull
git checkout -b develop
git push -u origin develop
```

**Protéger develop sur GitHub :**

Settings -> Branches -> Add rule -> `develop`  
(Mêmes protections que main)

---

### ÉTAPE 3 : Feature branch

**Emma crée une feature :**

```bash
git checkout develop
git pull
git checkout -b feature/export-json

# Développer l'export JSON
nano js/app.js
```

**Ajouter :**

```javascript
function exportTasks() {
    const dataStr = JSON.stringify(tasks, null, 2);
    const blob = new Blob([dataStr], {type: 'application/json'});
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = 'tasks.json';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(url);
}
```

**Commiter :**

```bash
git add js/app.js
git commit -m "feat: Add JSON export functionality"
git push -u origin feature/export-json
```

**PR vers develop (PAS main) :**

base: `develop` <- compare: `feature/export-json`

**Après review, merger dans develop.**

---

### ÉTAPE 4 : Préparer une release

**Alice gère la release :**

```bash
git checkout develop
git pull
git checkout -b release/1.1.0
```

**Mise à jour version :**

```bash
nano README.md
# Première ligne : # TaskMaster v1.1.0

nano CHANGELOG.md
```

**CHANGELOG.md :**

```markdown
# Changelog

## [1.1.0] - 2026-01-05

### Ajouté
- Système de filtres
- Thème sombre
- Compteur de tâches
- Export JSON

### Modifié
- Amélioration design avec animations

### Corrigé
- (Aucune correction)
```

**Commiter :**

```bash
git add README.md CHANGELOG.md
git commit -m "chore: Prepare release 1.1.0"
```

**Tests finaux :**

```bash
# Simuler tests
echo "[OK] Tests passed!"
```

**Pousser :**

```bash
git push -u origin release/1.1.0
```

---

**PR vers main :**

base: `main` <- compare: `release/1.1.0`

Title: `Release 1.1.0`

**Description :**

```markdown
# Release 1.1.0

## Nouvelles fonctionnalités
- Filtres par catégorie
- Thème sombre
- Export JSON

## Checklist
- [x] Tests passés
- [x] CHANGELOG à jour
- [x] Version bump
```

**Après approvals : Create a merge commit** (pas squash pour release)

---

**Merger aussi dans develop :**

```bash
git checkout develop
git pull
git merge release/1.1.0
git push
```

**Supprimer la release branch :**

```bash
git branch -d release/1.1.0
git push origin --delete release/1.1.0
```

---

### ÉTAPE 5 : Créer un tag

```bash
git checkout main
git pull

git tag -a v1.1.0 -m "Release 1.1.0

Features:
- Filters
- Dark theme
- JSON export"

git push origin v1.1.0
```

**Sur GitHub -> Releases -> Draft a new release**

- Tag: `v1.1.0`
- Title: `TaskMaster v1.1.0`
- Description: Copier depuis CHANGELOG

**Publish release**

**[OK] Release officielle ! [BRAVO]**

---

### ÉTAPE 6 : Hotfix en production

**Bug critique : Export ne marche pas sur Safari !**

```bash
git checkout main
git pull
git checkout -b hotfix/safari-export
```

**Corriger :**

```javascript
function exportTasks() {
    // ... code ...
    
    // FIX: Ajouter au DOM pour Safari
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    
    // ... reste du code ...
}
```

**Commiter :**

```bash
git add js/app.js
git commit -m "fix: Export JSON not working on Safari

Add link to DOM before click() for Safari compatibility

Fixes #42"
```

**PR vers main (urgente) :**

Title: `[ALERTE] HOTFIX: Export JSON Safari`  
Labels: `hotfix`, `critical`

**Après merge rapide :**

```bash
git checkout main
git pull
git tag -a v1.1.1 -m "Hotfix 1.1.1: Safari export fix"
git push origin v1.1.1
```

**[ATTENTION] IMPORTANT : Merger aussi dans develop !**

```bash
git checkout develop
git pull
git merge hotfix/safari-export
git push
```

**Supprimer la hotfix branch :**

```bash
git branch -d hotfix/safari-export
git push origin --delete hotfix/safari-export
```

---

### ÉTAPE 7 : git-flow CLI (automatisation)

**Installer :**

```bash
sudo apt install git-flow -y
```

**Initialiser :**

```bash
git flow init
# Accepter defaults, sauf version tag prefix: v
```

---

**Créer une feature :**

```bash
git flow feature start import-json
# Développer...
git add .
git commit -m "feat: Add JSON import"
git flow feature finish import-json
```

**Équivalent manuel :**

```bash
git checkout develop
git checkout -b feature/import-json
# Développer...
git checkout develop
git merge feature/import-json
git branch -d feature/import-json
```

**Mais en 2 commandes ! [RAPIDE]**

---

**Créer une release :**

```bash
git flow release start 1.2.0
# Préparer (bump version, CHANGELOG)
git add .
git commit -m "chore: Prepare 1.2.0"
git flow release finish 1.2.0
# Message pour le tag dans l'éditeur
```

**git-flow fait automatiquement :**
1. Merge dans main
2. Tag v1.2.0
3. Merge dans develop
4. Supprime la branche

**Pousser :**

```bash
git push origin main develop --tags
```

---

**Créer un hotfix :**

```bash
git flow hotfix start 1.2.1
# Corriger bug...
git add .
git commit -m "fix: Critical bug"
git flow hotfix finish 1.2.1
```

**Automatique : Merge main + develop, tag, suppression.**

---

### ÉTAPE 8 : Comparer les stratégies

**1. Git Flow** (ce qu'on vient de faire)

[OK] Releases planifiées  
[OK] Hotfixes isolés  
[OK] Historique clair  
[X] Complexe  
[X] Beaucoup de merges

**Quand : Produits avec releases (desktop, mobile)**

---

**2. GitHub Flow**

```
main (toujours déployable)
  ├─ feature/A -> PR -> merge -> DEPLOY
  └─ hotfix/X -> PR -> merge -> DEPLOY
```

[OK] Simple  
[OK] Déploiement continu  
[X] Pas de releases planifiées

**Quand : Applications web (SaaS)**

---

**3. GitLab Flow**

```
main -> staging -> production
```

[OK] Branches par environnement  
[OK] Contrôle des déploiements

**Quand : Plusieurs environnements**

---

**4. Trunk-Based Development**

```
main (trunk) - commits fréquents
Feature flags pour cacher features incomplètes
```

[OK] Très simple  
[OK] Intégration continue maximale  
[X] Nécessite discipline

**Quand : Équipes matures (Google, Facebook)**

---

---

### [OK] TESTS DE VALIDATION (EXERCICE 6)

**1. Branches Git Flow créées**

- [ ] Branche `develop` existe et est protégée
- [ ] Branche `main` existe et est protégée
- [ ] Feature branches créées depuis `develop`
- [ ] Release branch créée depuis `develop`
- [ ] Hotfix branch créée depuis `main`

---

**2. Workflow feature complet**

- [ ] Feature développée sur branche dédiée
- [ ] PR créée vers `develop`
- [ ] Code reviewé et approuvé
- [ ] Mergé dans `develop`
- [ ] Feature branch supprimée

---

**3. Workflow release complet**

- [ ] Release branch créée depuis `develop`
- [ ] Version bumpée dans package.json
- [ ] CHANGELOG généré
- [ ] Tests passent
- [ ] Mergé dans `main` et `develop`
- [ ] Tag créé et poussé
- [ ] GitHub Release créée
- [ ] Release branch supprimée

---

**4. Workflow hotfix complet**

- [ ] Hotfix créé depuis `main`
- [ ] Bug corrigé
- [ ] Mergé dans `main` ET `develop`
- [ ] Tag créé
- [ ] Hotfix branch supprimée

---

**5. git-flow CLI fonctionnel**

- [ ] `git flow init` configuré
- [ ] `git flow feature start/finish` fonctionne
- [ ] `git flow release start/finish` fonctionne
- [ ] `git flow hotfix start/finish` fonctionne

---

### [ROUGE] ERREURS COURANTES ET SOLUTIONS

#### Erreur 1 : Oubli de merger hotfix dans develop

**Symptôme :**

Le hotfix est sur main, mais pas sur develop. À la prochaine release, le bug revient ! [!]

**Solution :**

```bash
git checkout develop
git merge hotfix/nom-du-hotfix
git push
```

**Prévention : Toujours merger dans LES DEUX branches !**

---

#### Erreur 2 : Tag sur le mauvais commit

**Symptôme :**

Tu as taggé trop tôt, avant le dernier commit de la release.

**Solution :**

```bash
# Supprimer le tag (localement)
git tag -d v1.1.0

# Supprimer le tag (sur GitHub)
git push origin :refs/tags/v1.1.0

# Recréer au bon endroit
git tag -a v1.1.0 <commit-hash> -m "Message"
git push origin v1.1.0
```

---

#### Erreur 3 : Confusion entre branches main et develop

**Symptôme :**

Tu développes sur main au lieu de develop.

**Solution :**

```bash
# Créer une branche pour sauver le travail
git checkout -b feature/sauvegarde

# Retourner sur develop
git checkout develop

# Merger le travail
git merge feature/sauvegarde
```

---

#### Erreur 4 : Release branch créée depuis main au lieu de develop

**Symptôme :**

La release ne contient pas les dernières features !

**Solution :**

```bash
# Supprimer la mauvaise release branch
git branch -D release/1.2.0

# Recréer depuis develop
git checkout develop
git checkout -b release/1.2.0
```

---

#### Erreur 5 : Conflit lors du merge release -> main

**Symptôme :**

```
CONFLICT (content): Merge conflict in README.md
```

**Cause : main a avancé pendant la release (hotfix par exemple)**

**Solution :**

```bash
# Résoudre les conflits comme d'habitude
nano fichier-en-conflit.txt
git add fichier-en-conflit.txt
git commit
```

---

### [IMPORTANT] POINTS CLÉS À RETENIR

**1. Git Flow = Stratégie avec 5 types de branches**
- **main** : Production, toujours stable
- **develop** : Intégration, peut être instable
- **feature/*** : Nouvelles fonctionnalités
- **release/*** : Préparation de releases
- **hotfix/*** : Corrections urgentes en production

**2. Workflow feature**
```
develop -> feature/nom -> develop (via PR)
```

**3. Workflow release**
```
develop -> release/x.y.z -> tests -> main + develop -> tag vx.y.z
```

**4. Workflow hotfix**
```
main -> hotfix/x.y.z -> fix -> main + develop -> tag vx.y.z
```

**5. Tags = Marqueurs de versions**
- Tags annotés pour releases : `git tag -a v1.0.0 -m "Message"`
- Semantic versioning : MAJOR.MINOR.PATCH
- Toujours pousser les tags : `git push --tags`

**6. git-flow CLI automatise tout**
- `git flow init` : Initialiser
- `git flow feature start/finish nom` : Features
- `git flow release start/finish x.y.z` : Releases
- `git flow hotfix start/finish x.y.z` : Hotfixes

**7. Bonnes pratiques**
- Une branche = une fonctionnalité/fix
- Toujours partir de la bonne branche (feature depuis develop, hotfix depuis main)
- Merger hotfix dans MAIN ET DEVELOP
- Tagger chaque release
- CHANGELOG à jour

**8. Comparaison des stratégies**

| Projet | Stratégie recommandée |
|--------|----------------------|
| App web (SaaS) avec déploiement continu | GitHub Flow |
| Logiciel avec releases planifiées | Git Flow |
| Plusieurs environnements distincts | GitLab Flow |
| Équipe très mature, déploiements multiples/jour | Trunk-Based |

---

### [RAPIDE] POUR ALLER PLUS LOIN

**1. Support branches (Git Flow étendu)**

**Support branches = Maintenance de versions anciennes**

**Exemple : Supporter v1.x pendant que v2.x est développé**

```bash
# Créer une support branch depuis le tag
git checkout -b support/1.x v1.2.0

# Faire des hotfixes sur cette branche
git checkout -b hotfix/1.2.1 support/1.x
# Fix...
git checkout support/1.x
git merge hotfix/1.2.1
git tag -a v1.2.1 -m "Hotfix 1.2.1"
git push origin support/1.x --tags
```

---

**2. Pre-release versions**

**Versions candidates, bêtas, alphas**

**Convention :**
- v1.0.0-alpha.1
- v1.0.0-beta.1
- v1.0.0-rc.1 (release candidate)
- v1.0.0 (stable)

```bash
git tag -a v2.0.0-beta.1 -m "Beta 1 pour v2.0.0"
```

---

**3. Automatiser avec Semantic Release**

**Semantic Versioning automatique selon les commits :**

```bash
# Installation
npm install --save-dev semantic-release

# Configuration .releaserc.json
{
  "branches": ["main"],
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    "@semantic-release/changelog",
    "@semantic-release/npm",
    "@semantic-release/github",
    "@semantic-release/git"
  ]
}
```

**Avec Conventional Commits :**
```
feat: Nouvelle feature -> MINOR bump (0.X.0)
fix: Bug fix -> PATCH bump (0.0.X)
feat!: Breaking change -> MAJOR bump (X.0.0)
```

---

**4. Visualiser Git Flow**

**Outils graphiques qui comprennent Git Flow :**

**GitKraken :**
- Interface visuelle pour Git Flow
- Boutons pour start/finish feature/release/hotfix

**Sourcetree :**
- Support natif de Git Flow
- Vue graphique de l'historique

**VS Code avec extensions :**
- GitLens
- Git Graph
- Git Flow (extension)

---

**5. Git Flow pour monorepos**

**Adapter Git Flow aux monorepos :**

```
main
  │
develop
  │
  ├── feature/frontend-login
  ├── feature/backend-api
  └── feature/mobile-ui
```

**Tags par package :**
- `frontend-v1.0.0`
- `backend-v2.1.0`
- `mobile-v1.5.0`

**Ou releases globales :**
- `v1.0.0` pour tout le monorepo

---

**6. Checklist complète avant chaque type de merge**

**Avant de merger une feature dans develop :**
- [ ] Code testé localement
- [ ] Tests unitaires passent
- [ ] Pas de console.log oubliés
- [ ] Code reviewé (PR)
- [ ] Approuvé par 2+ personnes
- [ ] Pas de conflits

**Avant de créer une release :**
- [ ] Toutes les features mergées dans develop
- [ ] Tests passent sur develop
- [ ] CHANGELOG prêt
- [ ] Version bumpée
- [ ] Documentation à jour

**Avant de merger release dans main :**
- [ ] Tests finaux passent
- [ ] Tests de régression OK
- [ ] Performance vérifiée
- [ ] Approuvé par Tech Lead
- [ ] Plan de déploiement prêt

**Après le merge en production :**
- [ ] Tag créé et poussé
- [ ] Release GitHub créée
- [ ] Mergé aussi dans develop
- [ ] Release branch supprimée
- [ ] Équipe notifiée
- [ ] Monitoring activé

---

## [COURS] CONCLUSION DE L'EXERCICE 6

**[OK] Félicitations ! Tu maîtrises Git Flow et les stratégies de branching !**

**Ce que tu as appris :**
- Architecture complète de Git Flow
- Workflow feature, release, et hotfix
- Gestion de releases avec tags sémantiques
- Hotfixes en production sans perturber le développement
- Comparaison Git Flow vs GitHub Flow vs GitLab Flow vs Trunk-Based
- Utilisation de git-flow CLI pour automatiser
- Semantic Versioning
- CHANGELOG et documentation de releases

**Compétences acquises :**
- [OK] Git Flow complet (5 types de branches)
- [OK] Releases et tags professionnels
- [OK] Hotfixes en production
- [OK] git-flow CLI (automatisation)
- [OK] Stratégies de branching (comparaison et choix)
- [OK] Semantic Versioning
- [OK] CHANGELOG automatique

**Cas d'usage maîtrisés :**
- [OK] Développement d'une nouvelle fonctionnalité
- [OK] Préparation d'une release planifiée
- [OK] Correction urgente en production
- [OK] Maintenance de plusieurs versions
- [OK] Collaboration en équipe avec branches

**Temps moyen de réalisation :** 3-4 heures

**Prochaine étape :** Exercice 7 - Rebase, Cherry-pick et Stash avancé dans la Partie 3 ! [SYNC]

---

**[NOTE] Notes importantes :**

**Git Flow n'est pas toujours la meilleure solution !**

- [OK] Parfait pour : Logiciels avec releases planifiées (desktop, mobile apps)
- [X] Overkill pour : Applications web avec déploiement continu

**Choisis la stratégie selon ton contexte :**
- **Releases planifiées + tests longs** -> Git Flow
- **Déploiement continu + petite équipe** -> GitHub Flow
- **Plusieurs environnements** -> GitLab Flow
- **Équipe mature + CI/CD solide** -> Trunk-Based Development

**L'important n'est pas d'utiliser Git Flow, mais d'avoir UNE stratégie claire et partagée par toute l'équipe !**

---

## [BRAVO] CONCLUSION DE LA PARTIE 2

**Félicitations ! Tu as terminé les exercices 4, 5 et 6 !**

**Récapitulatif de la Partie 2 :**

[OK] **Exercice 4 : Gestion des conflits**
- Comprendre l'anatomie des conflits
- Résolution manuelle et avec outils
- Prévention des conflits
- rerere et diff3

[OK] **Exercice 5 : Pull Requests et Code Review**
- Création de PR professionnelles
- Processus de code review
- Request changes et approbations
- Protection de branches
- CODEOWNERS et templates

[OK] **Exercice 6 : Git Flow et stratégies de branching**
- Architecture Git Flow complète
- Workflows feature/release/hotfix
- Tags et semantic versioning
- Comparaison des stratégies
- git-flow CLI

**Compétences totales acquises dans la Partie 2 :**
- [OK] Résolution de conflits avancée
- [OK] Collaboration GitHub professionnelle
- [OK] Workflows d'équipe structurés
- [OK] Gestion de releases
- [OK] Maintenance de versions en production

**Temps total Partie 2 : 8-10 heures**

**Continue maintenant avec la Partie 3 pour les exercices experts (7-10) !** [RAPIDE]

---

**FIN DE LA PARTIE 2**

# [COURS] EXERCICES GIT & GITHUB - PARTIE 3 FINALE (Exercices 7-10)

**Suite et fin du document - Exercices avancés et experts**

---

### [ROUGE] ERREURS COURANTES (SUITE EXERCICE 6)

#### Erreur 1 : Oubli de merger hotfix dans develop

**Symptôme :**

Le hotfix est sur main, mais pas sur develop. À la prochaine release, le bug revient ! [!]

**Solution :**

```bash
git checkout develop
git merge hotfix/nom-du-hotfix
git push
```

**Prévention : Toujours merger dans LES DEUX branches !**

---

#### Erreur 2 : Tag sur le mauvais commit

**Symptôme :**

Tu as taggé trop tôt, avant le dernier commit de la release.

**Solution :**

```bash
# Supprimer le tag (localement)
git tag -d v1.1.0

# Supprimer le tag (sur GitHub)
git push origin :refs/tags/v1.1.0

# Recréer au bon endroit
git tag -a v1.1.0 <commit-hash> -m "Message"
git push origin v1.1.0
```

---

### [IMPORTANT] POINTS CLÉS À RETENIR (EXERCICE 6)

**1. Git Flow = Stratégie avec 5 types de branches**
- main (production)
- develop (intégration)
- feature/* (nouvelles features)
- release/* (préparation release)
- hotfix/* (corrections urgentes)

**2. Workflow release**
```
develop -> release/x.y.z -> tests -> main + develop -> tag
```

**3. Workflow hotfix**
```
main -> hotfix/x.y.z -> fix -> main + develop -> tag
```

**4. Tags = Marqueurs de versions**
- Tags annotés pour releases
- Semantic versioning (X.Y.Z)

**5. git-flow CLI automatise tout**
- `git flow feature start/finish`
- `git flow release start/finish`
- `git flow hotfix start/finish`

---

## [COURS] CONCLUSION DE L'EXERCICE 6

**[OK] Félicitations ! Tu maîtrises Git Flow et les stratégies de branching !**

**Ce que tu as appris :**
- Architecture Git Flow complète
- Gestion de releases avec tags
- Hotfixes en production
- Comparaison des stratégies (Git Flow, GitHub Flow, GitLab Flow)
- Utilisation de git-flow CLI
- Semantic Versioning

**Compétences acquises :**
- [OK] Git Flow complet
- [OK] Releases et tags
- [OK] Hotfixes
- [OK] git-flow CLI
- [OK] Stratégies de branching

**Temps moyen de réalisation :** 3-4 heures

**Prochaine étape :** Exercice 7 - Rebase, Cherry-pick et Stash avancé ! [SYNC]

---

---

# [ROUGE] EXERCICE 7 : REBASE, CHERRY-PICK ET STASH AVANCÉ

## [LISTE] ÉNONCÉ

### Contexte professionnel

**Le projet TaskMaster a un historique Git qui devient "sale" :**

- Commits "WIP", "fix typo", "oops forgot this"
- Branches avec 50 commits pour une petite feature
- Historique difficile à lire

**Le CTO demande :** "On nettoie tout ça ! Je veux un historique PROPRE et LINÉAIRE."

**Mission :**
1. Apprendre à utiliser `git rebase` (interactif et normal)
2. Nettoyer l'historique avec squash, reword, fixup
3. Utiliser `git cherry-pick` pour copier des commits spécifiques
4. Maîtriser `git stash` avancé (branch, apply index)

---

## [OBJECTIF] OBJECTIFS PÉDAGOGIQUES

À la fin de cet exercice, tu sauras :

- [OK] Comprendre rebase vs merge
- [OK] Faire un rebase simple
- [OK] Rebase interactif (squash, reword, edit, drop)
- [OK] Gérer les conflits lors d'un rebase
- [OK] Cherry-pick un ou plusieurs commits
- [OK] Utiliser stash avancé (list, apply, pop, branch, drop)
- [OK] Reflog pour récupérer des commits perdus
- [OK] Bonnes pratiques de rebase

---

## [DOCS] PRÉREQUIS

- Exercices 1 à 6 terminés
- Compréhension solide de l'historique Git
- [ATTENTION] **ATTENTION** : Rebase réécrit l'historique !

---

## [OK] SOLUTION COMPLÈTE

### ÉTAPE 1 : Comprendre rebase vs merge

**Merge = Combine deux branches AVEC un commit de merge**

```
main:     [WHITE_CIRCLE]───[WHITE_CIRCLE]───[WHITE_CIRCLE]───[BLACK_CIRCLE]
                     / \
feature:  [WHITE_CIRCLE]───[WHITE_CIRCLE]───[WHITE_CIRCLE]   \
                       \
                        [BLACK_CIRCLE] (commit de merge)
```

**Historique :**
```
* Merge branch 'feature' into main
|\
| * Commit feature C
| * Commit feature B
| * Commit feature A
|/
* Commit on main
```

---

**Rebase = "Rejoue" les commits d'une branche sur une autre**

```
AVANT rebase:
main:     [WHITE_CIRCLE]───[WHITE_CIRCLE]───[WHITE_CIRCLE]
               \
feature:        [WHITE_CIRCLE]───[WHITE_CIRCLE]───[WHITE_CIRCLE]

APRÈS rebase:
main:     [WHITE_CIRCLE]───[WHITE_CIRCLE]───[WHITE_CIRCLE]───[WHITE_CIRCLE]───[WHITE_CIRCLE]───[WHITE_CIRCLE]
                    └───feature rejoué
```

**Historique :**
```
* Commit feature C
* Commit feature B
* Commit feature A
* Commit on main (plus récent)
* Commit on main (ancien)
```

**Historique LINÉAIRE ! Pas de commit de merge.**

---

**Avantages du rebase :**

[OK] Historique linéaire (plus facile à lire)
[OK] Pas de commits de merge "inutiles"
[OK] Bisect plus facile (recherche de bugs)
[OK] Historique "comme si" tu avais développé après les derniers commits

**Inconvénients :**

[X] Réécrit l'historique (change les hashes)
[X] Dangereux si déjà pushé (conflits pour les autres)
[X] Peut être complexe avec beaucoup de commits

---

**[ATTENTION] RÈGLE D'OR DU REBASE :**

**NE JAMAIS rebase des commits déjà pushés sur une branche partagée !**

**OK pour rebase :**
- Branche feature locale (pas encore pushée)
- Ta propre branche feature (avant PR)

**PAS OK pour rebase :**
- main ou develop (branches partagées)
- Après un push et que d'autres ont tiré

---

### ÉTAPE 2 : Rebase simple (non-interactif)

**Situation :** Tu as une branche feature, mais main a avancé.

**Créer une situation :**

```bash
cd ~/TaskMaster
git checkout main
git pull

# Alice ajoute une fonctionnalité sur main (simuler)
echo "<!-- Footer -->" >> index.html
git add index.html
git commit -m "Ajout placeholder footer"
git push
```

---

**Bob crée une branche (depuis l'ancien main) :**

```bash
# Sur la machine de Bob
cd ~/bob-workspace/TaskMaster
git checkout main
# Bob ne fait PAS git pull (il est sur l'ancien main)

git checkout -b feature/notification
echo "// Notifications" >> js/app.js
git add js/app.js
git commit -m "Ajout système de notifications"
```

**Maintenant :**

```
main (remote):  [WHITE_CIRCLE]───[WHITE_CIRCLE]───[BLACK_CIRCLE]  (footer par Alice)
                     \
feature (Bob):        [WHITE_CIRCLE]  (notifications)
```

**Bob est "en retard" sur main.**

---

**Bob veut mettre sa branche à jour avec main :**

**Option 1 : Merge (crée un commit de merge)**

```bash
git merge main
```

**Option 2 : Rebase (historique linéaire) ***

```bash
git rebase main
```

**Résultat :**

```
Applying: Ajout système de notifications
```

**[OK] Le commit de Bob est "rejoué" sur le nouveau main !**

---

**Vérifier l'historique :**

```bash
git log --oneline --graph
```

**Résultat :**

```
* abc1234 (HEAD -> feature/notification) Ajout système de notifications
* def5678 (main) Ajout placeholder footer
* ...
```

**Historique linéaire ! Pas de commit de merge.**

---

**Pousser la branche :**

**Si c'est la première fois :**

```bash
git push -u origin feature/notification
```

**Si déjà pushée (AVANT le rebase), il faut forcer :**

```bash
git push --force-with-lease
```

**`--force-with-lease`** = Force push SÉCURISÉ
- Push seulement si personne d'autre n'a pushé entre temps
- Protège contre l'écrasement du travail des autres

**[ATTENTION] NE JAMAIS `git push --force` sur main ou develop !**

---

### ÉTAPE 3 : Rebase interactif (nettoyer l'historique)

**Situation : Charlie a fait une feature avec plein de petits commits "sales" :**

**Créer des commits "sales" (simuler) :**

```bash
cd ~/charlie-workspace/TaskMaster
git checkout -b feature/search

echo "// Search init" >> js/app.js
git add js/app.js
git commit -m "WIP search"

echo "// Search function" >> js/app.js
git add js/app.js
git commit -m "add search function"

echo "// Fix typo" >> js/app.js
git add js/app.js
git commit -m "fix typo"

echo "// Search UI" >> index.html
git add index.html
git commit -m "oops forgot UI"

echo "// Final search" >> js/app.js
git add js/app.js
git commit -m "search complete"
```

**5 commits pour une petite feature ! [!]**

---

**Voir l'historique :**

```bash
git log --oneline
```

**Résultat :**

```
e5f6g7h (HEAD -> feature/search) search complete
d4e5f6g oops forgot UI
c3d4e5f fix typo
b2c3d4e add search function
a1b2c3d WIP search
...
```

**Messages peu clairs, commits atomiques cassés.**

---

**Nettoyer avec rebase interactif :**

```bash
git rebase -i HEAD~5
```

**`-i`** = Interactif
**`HEAD~5`** = Les 5 derniers commits

---

**Git ouvre l'éditeur avec :**

```
pick a1b2c3d WIP search
pick b2c3d4e add search function
pick c3d4e5f fix typo
pick d4e5f6g oops forgot UI
pick e5f6g7h search complete

# Rebase ... onto ...
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
```

---

**Explication des commandes principales :**

**`pick`** (par défaut)
- Garder le commit tel quel

**`reword`** (ou `r`)
- Garder le commit, mais changer le message

**`edit`** (ou `e`)
- Garder le commit, mais s'arrêter pour modifier (amend)

**`squash`** (ou `s`)
- Fusionner avec le commit PRÉCÉDENT
- Combine les messages de commit

**`fixup`** (ou `f`)
- Fusionner avec le commit PRÉCÉDENT
- **Jette le message** de ce commit

**`drop`** (ou `d`)
- Supprimer complètement le commit

**`exec`** (ou `x`)
- Exécuter une commande shell (tests, lint, etc.)

---

**Notre plan : Combiner tous les commits en UN seul**

**Modifier ainsi :**

```
pick a1b2c3d WIP search
squash b2c3d4e add search function
squash c3d4e5f fix typo
squash d4e5f6g oops forgot UI
squash e5f6g7h search complete
```

**Ou utiliser `fixup` pour jeter les messages intermédiaires :**

```
pick a1b2c3d WIP search
fixup b2c3d4e add search function
fixup c3d4e5f fix typo
fixup d4e5f6g oops forgot UI
fixup e5f6g7h search complete
```

**Avec `fixup`, seul le message du premier commit sera gardé.**

**On va plutôt utiliser `squash` pour réécrire un message propre.**

---

**Sauvegarder et quitter l'éditeur.**

**Git ouvre un nouvel éditeur pour le message du commit combiné :**

```
# This is a combination of 5 commits.
# This is the 1st commit message:

WIP search

# This is the commit message #2:

add search function

# This is the commit message #3:

fix typo

# This is the commit message #4:

oops forgot UI

# This is the commit message #5:

search complete
```

---

**Remplacer TOUT par un message propre :**

```
feat: Ajout système de recherche de tâches

- Fonction de recherche dans le titre et contenu
- Interface utilisateur avec champ de recherche
- Filtrage en temps réel
- Highlighting des résultats
```

**Sauvegarder et quitter.**

---

**Résultat :**

```
[detached HEAD f6g7h8i] feat: Ajout système de recherche de tâches
 Date: Thu Jan 7 10:00:00 2026 +0000
 2 files changed, 50 insertions(+)
Successfully rebased and updated refs/heads/feature/search.
```

**[OK] 5 commits -> 1 commit propre ! [BRAVO]**

---

**Vérifier l'historique :**

```bash
git log --oneline
```

**Résultat :**

```
f6g7h8i (HEAD -> feature/search) feat: Ajout système de recherche de tâches
...
```

**Un seul commit avec un message clair ! [OK]**

---

**[ATTENTION] ATTENTION : Les hashes ont changé !**

**AVANT rebase :** `a1b2c3d`, `b2c3d4e`, `c3d4e5f`, etc.
**APRÈS rebase :** `f6g7h8i`

**C'est un NOUVEAU commit (historique réécrit).**

---

**Si la branche était déjà pushée :**

```bash
git push --force-with-lease
```

**Les autres devront faire :**

```bash
git fetch
git reset --hard origin/feature/search
```

**C'est pour ça qu'on ne rebase PAS les branches partagées !**

---

### ÉTAPE 4 : Rebase interactif avancé (reword, edit, drop)

**Simuler un historique avec différents problèmes :**

```bash
git checkout -b feature/refactor

git commit -m "refactor: Clean code" --allow-empty
git commit -m "Add coment" --allow-empty  # Typo volontaire
git commit -m "TODO: Finish this" --allow-empty
git commit -m "feat: Add feature X" --allow-empty
git commit -m "Debug code (remove later)" --allow-empty
```

**5 commits avec problèmes :**
1. OK
2. Typo dans le message
3. Commit incomplet (TODO)
4. OK
5. Code de debug à supprimer

---

**Rebase interactif :**

```bash
git rebase -i HEAD~5
```

**Plan d'action :**

```
pick abc1234 refactor: Clean code
reword def5678 Add coment
edit ghi9012 TODO: Finish this
pick jkl3456 feat: Add feature X
drop mno7890 Debug code (remove later)
```

---

**1. `pick` : Pas de changement**

---

**2. `reword` : Corriger le message**

**Git ouvre l'éditeur :**

```
Add coment
```

**Corriger en :**

```
refactor: Add comments for better code documentation
```

**Sauvegarder et quitter.**

---

**3. `edit` : S'arrêter pour modifier**

**Git s'arrête à ce commit :**

```
Stopped at ghi9012...  TODO: Finish this
You can amend the commit now, with

  git commit --amend

Once you are satisfied with your changes, run

  git rebase --continue
```

**Tu peux maintenant :**
- Modifier des fichiers
- Ajouter à la staging area
- Amend le commit

**Simuler une modification :**

```bash
echo "// Feature completed" >> js/app.js
git add js/app.js
git commit --amend -m "feat: Complete feature implementation"
```

**Continuer le rebase :**

```bash
git rebase --continue
```

---

**4. `pick` : Pas de changement**

---

**5. `drop` : Supprimé ! [X]**

---

**Résultat final :**

```bash
git log --oneline
```

```
* pqr4567 feat: Add feature X
* stu8901 feat: Complete feature implementation
* vwx2345 refactor: Add comments for better code documentation
* yz01234 refactor: Clean code
```

**4 commits propres au lieu de 5 ! [OK]**

---

### ÉTAPE 5 : Gérer les conflits lors d'un rebase

**Situation : Rebase avec conflit**

**Simuler :**

```bash
git checkout main
echo "Version 1" > file.txt
git add file.txt
git commit -m "Add file version 1"

git checkout -b feature/edit-file
echo "Version 2 from feature" > file.txt
git add file.txt
git commit -m "Edit file in feature"

git checkout main
echo "Version 2 from main" > file.txt
git add file.txt
git commit -m "Edit file in main"
```

**Maintenant :**
- main a "Version 2 from main"
- feature a "Version 2 from feature"

---

**Rebase feature sur main :**

```bash
git checkout feature/edit-file
git rebase main
```

**[IMPACT] CONFLIT ! [IMPACT]**

```
Auto-merging file.txt
CONFLICT (content): Merge conflict in file.txt
error: could not apply abc1234... Edit file in feature
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply abc1234... Edit file in feature
```

---

**Voir les fichiers en conflit :**

```bash
git status
```

```
rebase in progress; onto def5678
You are currently rebasing branch 'feature/edit-file' on 'def5678'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
	both modified:   file.txt
```

---

**Ouvrir le fichier :**

```bash
cat file.txt
```

```
<<<<<<< HEAD
Version 2 from main
=======
Version 2 from feature
>>>>>>> abc1234 (Edit file in feature)
```

---

**Résoudre (garder les deux) :**

```bash
nano file.txt
```

**Remplacer par :**

```
Version 2 from main (updated in feature)
```

**Sauvegarde.**

---

**Marquer comme résolu :**

```bash
git add file.txt
```

---

**Continuer le rebase :**

```bash
git rebase --continue
```

**[OK] Rebase terminé !**

---

**Options si le conflit est complexe :**

**Abandonner le rebase :**

```bash
git rebase --abort
```

**Revenir à l'état avant le rebase.**

---

**Sauter le commit en conflit :**

```bash
git rebase --skip
```

**[ATTENTION] Attention : Le commit est PERDU !**

---

### ÉTAPE 6 : git cherry-pick (copier des commits)

**Situation :** Tu veux copier UN commit d'une branche vers une autre.

**Exemple : Un bug fix a été fait sur `develop`, mais tu veux l'appliquer sur `main` rapidement.**

---

**Simuler :**

```bash
git checkout develop
echo "// Bug fix" >> js/app.js
git add js/app.js
git commit -m "fix: Correction bug d'affichage"
```

**Note le hash du commit :**

```bash
git log --oneline -1
```

```
ghi9012 (HEAD -> develop) fix: Correction bug d'affichage
```

**Hash : `ghi9012`**

---

**Appliquer ce commit sur main :**

```bash
git checkout main
git cherry-pick ghi9012
```

**Résultat :**

```
[main jkl3456] fix: Correction bug d'affichage
 Date: Thu Jan 7 11:00:00 2026 +0000
 1 file changed, 1 insertion(+)
```

**[OK] Le commit a été copié sur main !**

---

**Vérifier :**

```bash
git log --oneline -1
```

```
jkl3456 (HEAD -> main) fix: Correction bug d'affichage
```

**[ATTENTION] Nouveau hash (`jkl3456`, pas `ghi9012`) !**

**C'est un NOUVEAU commit (même contenu, différent hash).**

---

**Cherry-pick plusieurs commits :**

```bash
git cherry-pick abc1234 def5678 ghi9012
```

**Ou une plage :**

```bash
git cherry-pick abc1234..ghi9012
```

**Applique tous les commits entre abc1234 et ghi9012 (excluant abc1234).**

---

**Cherry-pick avec conflit :**

**Même processus que rebase :**

```bash
git cherry-pick xyz7890
# Conflit !
# Résoudre le conflit
git add .
git cherry-pick --continue
```

---

**Annuler un cherry-pick :**

```bash
git cherry-pick --abort
```

---

**Cas d'usage courants :**

1. **Hotfix urgent :** Appliquer un fix de develop vers main rapidement
2. **Backport :** Appliquer un fix de v2.0 vers v1.0
3. **Feature partielle :** Copier seulement certains commits d'une grosse feature

---

### ÉTAPE 7 : git stash avancé

**On a vu `git stash` dans l'exercice 2. Allons plus loin !**

---

**Stash avec message :**

```bash
git stash push -m "WIP: Feature X - UI not finished"
```

**Plus clair que juste "WIP on branch".**

---

**Stash seulement certains fichiers :**

```bash
git stash push -m "Stash only CSS" css/style.css
```

---

**Stash incluant les fichiers non-trackés :**

```bash
git stash --include-untracked
```

**Ou :**

```bash
git stash -u
```

**Par défaut, stash ignore les fichiers non-trackés.**

---

**Stash incluant les fichiers ignorés (.gitignore) :**

```bash
git stash --all
```

**Stash TOUT, même les fichiers ignorés !**

---

**Voir le contenu d'un stash :**

```bash
git stash show stash@{0}
```

**Ou avec diff complet :**

```bash
git stash show -p stash@{0}
```

**`-p`** = Patch (diff complet)

---

**Appliquer un stash sans le supprimer :**

```bash
git stash apply stash@{0}
```

**Différence avec `pop` :**
- `pop` = Applique + supprime du stash
- `apply` = Applique mais GARDE dans le stash

---

**Supprimer un stash spécifique :**

```bash
git stash drop stash@{0}
```

---

**Créer une branche depuis un stash :**

```bash
git stash branch nouvelle-branche stash@{0}
```

**Crée une nouvelle branche, applique le stash, et supprime le stash.**

**Super pratique si tu stashes sur la mauvaise branche !**

---

**Stash interactif (choisir ce qu'on stash) :**

```bash
git stash push -p
```

**Git demande pour chaque modification :**

```
Stash this hunk [y,n,q,a,d,e,?]?
```

- `y` = Yes (stash)
- `n` = No (ne pas stash)
- `q` = Quit (arrêter)
- `a` = All (stash tout le reste)
- `d` = Don't (ne stash rien du reste)
- `e` = Edit (éditer manuellement)
- `?` = Aide

---

### ÉTAPE 8 : git reflog (récupérer l'impossible)

**Le reflog = Journal de TOUS les mouvements de HEAD**

**Même les commits "perdus" (supprimés, rebase, reset, etc.) sont récupérables !**

---

**Voir le reflog :**

```bash
git reflog
```

**Résultat :**

```
abc1234 (HEAD -> main) HEAD@{0}: commit: Latest commit
def5678 HEAD@{1}: rebase finished: returning to refs/heads/main
ghi9012 HEAD@{2}: rebase: Commit message
jkl3456 HEAD@{3}: commit: Another commit
mno7890 HEAD@{4}: reset: moving to HEAD~1
pqr4567 HEAD@{5}: commit: Lost commit
...
```

**Chaque ligne = Un mouvement de HEAD**

---

**Récupérer un commit "perdu" :**

**Exemple : Tu as fait un `git reset --hard HEAD~1` par erreur.**

```bash
git reset --hard HEAD~1
# Oops ! J'ai supprimé un commit important !
```

**Le commit est "perdu" de l'historique, mais PAS du reflog !**

```bash
git reflog
```

```
abc1234 HEAD@{0}: reset: moving to HEAD~1
def5678 HEAD@{1}: commit: Important commit  <- Celui qu'on veut récupérer !
```

**Revenir à ce commit :**

```bash
git reset --hard def5678
```

**Ou :**

```bash
git reset --hard HEAD@{1}
```

**[OK] Commit récupéré ! [BRAVO]**

---

**Récupérer une branche supprimée :**

```bash
git branch -D feature-supprimee
# Oops ! Je voulais pas la supprimer !

git reflog
```

```
abc1234 HEAD@{0}: checkout: moving from feature-supprimee to main
def5678 HEAD@{1}: commit: Last commit on feature-supprimee
```

**Recréer la branche :**

```bash
git checkout -b feature-supprimee def5678
```

**[OK] Branche récupérée !**

---

**Le reflog garde l'historique pendant 90 jours par défaut.**

**Après ça, les commits sont vraiment perdus (garbage collection).**

---

### [OK] TESTS DE VALIDATION

**1. Rebase simple**

- [ ] Rebase d'une branche sur main
- [ ] Historique linéaire
- [ ] Pas de commit de merge

---

**2. Rebase interactif**

- [ ] Squash de plusieurs commits en un
- [ ] Reword d'un message
- [ ] Drop d'un commit
- [ ] Historique propre

---

**3. Cherry-pick**

- [ ] Copie d'un commit d'une branche à une autre
- [ ] Nouveau hash créé
- [ ] Contenu identique

---

**4. Stash avancé**

- [ ] Stash avec message
- [ ] Stash de fichiers spécifiques
- [ ] Création de branche depuis stash

---

**5. Reflog**

- [ ] Récupération d'un commit "perdu"
- [ ] Récupération d'une branche supprimée

---

### [ROUGE] ERREURS COURANTES ET SOLUTIONS

#### Erreur 1 : "Cannot rebase: You have unstaged changes"

**Symptôme :**

```
error: cannot rebase: You have unstaged changes.
error: Please commit or stash them.
```

**Cause : Modifications non commitées**

**Solution :**

```bash
# Option 1 : Stash
git stash
git rebase main
git stash pop

# Option 2 : Commiter
git add .
git commit -m "WIP"
git rebase main
```

---

#### Erreur 2 : Rebase foireux, historique cassé

**Symptôme :**

Tu as fait n'importe quoi pendant le rebase, tout est mélangé.

**Solution : Annuler le rebase**

```bash
git rebase --abort
```

**Ou revenir en arrière avec reflog :**

```bash
git reflog
# Trouver le HEAD avant le rebase
git reset --hard HEAD@{5}
```

---

#### Erreur 3 : Force push qui écrase le travail des autres

**Symptôme :**

Tu as fait `git push --force`, quelqu'un d'autre avait pushé entre temps -> Son travail est perdu !

**Prévention : TOUJOURS utiliser `--force-with-lease`**

```bash
git push --force-with-lease
```

**Si quelqu'un a pushé, ça échoue :**

```
error: failed to push some refs to 'origin'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
```

**-> Tu sais qu'il faut pull avant de pousser.**

---

#### Erreur 4 : Cherry-pick du mauvais commit

**Solution : Annuler le cherry-pick**

```bash
git reset --hard HEAD~1
```

**Ou avec revert :**

```bash
git revert HEAD
```

---

### [IMPORTANT] POINTS CLÉS À RETENIR

**1. Rebase vs Merge**
- Merge = Historique préservé + commit de merge
- Rebase = Historique linéaire, réécrit l'historique

**2. [ATTENTION] Règle d'or du rebase**
- **NE JAMAIS rebase des commits pushés sur branche partagée**
- OK pour branches locales ou propres branches feature

**3. Rebase interactif**
- `squash` = Fusionner commits
- `reword` = Changer message
- `edit` = Modifier commit
- `drop` = Supprimer commit

**4. Cherry-pick**
- Copier un commit d'une branche à une autre
- Crée un nouveau commit (nouveau hash)

**5. Stash avancé**
- `git stash push -m "message"`
- `git stash apply` vs `pop`
- `git stash branch` pour créer une branche

**6. Reflog = Filet de sécurité**
- Tous les mouvements de HEAD enregistrés
- Récupération de commits "perdus"
- Garde 90 jours par défaut

---

### [RAPIDE] POUR ALLER PLUS LOIN

**1. Rebase avec autosquash**

**Utiliser `fixup!` et `squash!` dans les messages :**

```bash
git commit -m "feat: Add feature"
# Plus tard, correction
git commit -m "fixup! feat: Add feature"

# Rebase avec autosquash
git rebase -i --autosquash main
```

**Git met automatiquement `fixup` à côté du bon commit !**

---

**2. Rebase avec exec (tests automatiques)**

```bash
git rebase -i main
```

**Dans l'éditeur :**

```
pick abc1234 Commit 1
exec npm test
pick def5678 Commit 2
exec npm test
```

**Git exécute les tests après chaque commit !**

**Si un test échoue, le rebase s'arrête.**

---

**3. git bisect (trouver le commit qui a introduit un bug)**

**Workflow :**

```bash
git bisect start
git bisect bad  # Le commit actuel est buggé
git bisect good abc1234  # Ce commit était OK

# Git fait une recherche binaire
# À chaque étape, teste et marque :
git bisect good  # ou git bisect bad

# Git trouve automatiquement le commit fautif !
git bisect reset  # Terminer
```

---

**4. Interactive rebase avec --exec pour reformater**

```bash
git rebase -i --exec "npm run format" main
```

**Reformate le code après chaque commit du rebase.**

---

## [COURS] CONCLUSION DE L'EXERCICE 7

**[OK] Félicitations ! Tu maîtrises rebase, cherry-pick et stash !**

**Ce que tu as appris :**
- Différence rebase vs merge
- Rebase simple et interactif
- Squash, reword, edit, drop
- Cherry-pick de commits
- Stash avancé
- Reflog pour récupérer des commits

**Compétences acquises :**
- [OK] git rebase (simple et interactif)
- [OK] git cherry-pick
- [OK] git stash (avancé)
- [OK] git reflog
- [OK] Nettoyage d'historique

**Temps moyen de réalisation :** 3-4 heures

**Prochaine étape :** Exercice 8 - Git Hooks et automatisation ! [HOOK]

---

---

# [ROUGE] EXERCICE 8 : GIT HOOKS ET AUTOMATISATION

## [LISTE] ÉNONCÉ

### Contexte professionnel

**Le CTO de TaskMaster en a marre des problèmes récurrents :**

[X] Commits avec des `console.log()` oubliés
[X] Code non formaté (espaces, indentation)
[X] Tests non lancés avant commit
[X] Messages de commit non conventionnels

**Solution : Automatiser avec Git Hooks !**

**Mission :**
1. Créer des hooks pour valider le code avant commit
2. Automatiser le formatage
3. Empêcher les commits mal formés
4. Lancer les tests automatiquement

---

## [OBJECTIF] OBJECTIFS PÉDAGOGIQUES

À la fin de cet exercice, tu sauras :

- [OK] Comprendre les Git Hooks
- [OK] Créer des hooks côté client (pre-commit, commit-msg, pre-push)
- [OK] Créer des hooks côté serveur (pre-receive, post-receive)
- [OK] Utiliser Husky (outil pour gérer les hooks)
- [OK] Intégrer lint-staged
- [OK] Automatiser le formatage avec Prettier
- [OK] Valider les messages de commit (commitlint)
- [OK] Partager les hooks avec l'équipe

---

## [DOCS] PRÉREQUIS

- Exercices 1 à 7 terminés
- Node.js installé (pour Husky)
- Compréhension du scripting bash de base

---

## [OK] SOLUTION COMPLÈTE

### ÉTAPE 1 : Comprendre les Git Hooks

**Git Hooks = Scripts exécutés automatiquement à certains moments**

**Emplacement : `.git/hooks/`**

```bash
ls -la .git/hooks/
```

**Résultat :**

```
applypatch-msg.sample
commit-msg.sample
pre-commit.sample
pre-push.sample
pre-rebase.sample
...
```

**Fichiers `.sample` = Exemples (désactivés)**

**Pour activer un hook : Retirer `.sample` et rendre exécutable**

---

**Types de hooks (côté client) :**

| Hook | Quand | Usage |
|------|-------|-------|
| **pre-commit** | Avant un commit | Linter, tests, formatage |
| **prepare-commit-msg** | Avant l'éditeur de message | Template de message |
| **commit-msg** | Après le message | Valider format du message |
| **post-commit** | Après un commit | Notifications, backup |
| **pre-push** | Avant un push | Tests lourds, build |
| **post-checkout** | Après checkout | npm install, clean |
| **post-merge** | Après un merge | npm install, migrations |

---

**Types de hooks (côté serveur) :**

| Hook | Quand | Usage |
|------|-------|-------|
| **pre-receive** | Avant réception push | Valider commits, permissions |
| **update** | Pour chaque branche | Valider par branche |
| **post-receive** | Après réception push | Déploiement, notifications |

---

**[ATTENTION] Problème avec les hooks dans `.git/hooks/` :**

[X] Pas versionné (`.git/` n'est pas dans le repo)
[X] Chaque dev doit installer manuellement
[X] Pas partagé avec l'équipe

**Solution : Husky (on verra plus bas)**

---

### ÉTAPE 2 : Créer un hook pre-commit manuel

**Hook pre-commit = Exécuté AVANT chaque commit**

**Créer le hook :**

```bash
cd ~/TaskMaster
nano .git/hooks/pre-commit
```

**Contenu :**

```bash
#!/bin/bash

echo "[RECHERCHE] Pre-commit hook : Vérification du code..."

# Vérifier s'il y a des console.log
if git diff --cached --name-only | grep '\.js$' > /dev/null; then
    for file in $(git diff --cached --name-only | grep '\.js$'); do
        if grep -n 'console\.log' "$file"; then
            echo "[X] ERREUR : console.log détecté dans $file"
            echo "   Supprimez les console.log avant de commiter."
            exit 1
        fi
    done
fi

# Vérifier s'il y a des TODO
if git diff --cached | grep -i 'TODO'; then
    echo "[ATTENTION]  AVERTISSEMENT : TODO détecté dans le code"
    echo "   Pensez à les résoudre avant la release."
fi

echo "[OK] Vérifications passées !"
exit 0
```

**Sauvegarde.**

---

**Rendre exécutable :**

```bash
chmod +x .git/hooks/pre-commit
```

---

**Explication du script :**

**`#!/bin/bash`**
- Shebang : indique que c'est un script bash

**`git diff --cached --name-only`**
- Affiche les noms des fichiers en staging area
- `--cached` = staging area (pas working directory)

**`grep '\.js$'`**
- Filtre seulement les fichiers .js
- `\.` = Point littéral (échappé)
- `$` = Fin de ligne (fichiers se terminant par .js)

**`grep -n 'console\.log' "$file"`**
- Cherche "console.log" dans le fichier
- `-n` = Affiche le numéro de ligne
- Si trouvé, grep retourne 0 (succès)

**`exit 1`**
- Code de sortie 1 = ERREUR
- Bloque le commit

**`exit 0`**
- Code de sortie 0 = SUCCÈS
- Autorise le commit

---

**Tester le hook :**

```bash
# Ajouter un console.log
echo "console.log('debug');" >> js/app.js

# Essayer de commiter
git add js/app.js
git commit -m "Test commit"
```

**Résultat :**

```
[RECHERCHE] Pre-commit hook : Vérification du code...
js/app.js:50:console.log('debug');
[X] ERREUR : console.log détecté dans js/app.js
   Supprimez les console.log avant de commiter.
```

**[X] Commit bloqué ! [OK]**

---

**Retirer le console.log :**

```bash
# Enlever la ligne ajoutée
sed -i '$d' js/app.js

git add js/app.js
git commit -m "Test commit"
```

**Résultat :**

```
[RECHERCHE] Pre-commit hook : Vérification du code...
[OK] Vérifications passées !
[main abc1234] Test commit
```

**[OK] Commit autorisé !**

---

### ÉTAPE 3 : Hook commit-msg (valider le format)

**Hook commit-msg = Valide le message APRÈS que tu l'as écrit**

**Créer le hook :**

```bash
nano .git/hooks/commit-msg
```

**Contenu (validation Conventional Commits) :**

```bash
#!/bin/bash

# Lire le message de commit
commit_msg=$(cat "$1")

# Regex Conventional Commits
# Format: type(scope): description
# Exemples:
# - feat: Add feature
# - fix(ui): Correct button
# - docs: Update README
regex='^(feat|fix|docs|style|refactor|test|chore|perf)(\(.+\))?: .{1,50}'

if ! echo "$commit_msg" | grep -qE "$regex"; then
    echo "[X] ERREUR : Message de commit invalide !"
    echo ""
    echo "Format attendu : type(scope): description"
    echo ""
    echo "Types valides :"
    echo "  - feat: Nouvelle fonctionnalité"
    echo "  - fix: Correction de bug"
    echo "  - docs: Documentation"
    echo "  - style: Formatage"
    echo "  - refactor: Refactoring"
    echo "  - test: Tests"
    echo "  - chore: Tâches (build, config)"
    echo "  - perf: Performance"
    echo ""
    echo "Exemples :"
    echo "  - feat: Add user authentication"
    echo "  - fix(api): Correct endpoint validation"
    echo "  - docs: Update installation guide"
    echo ""
    echo "Votre message : $commit_msg"
    exit 1
fi

echo "[OK] Message de commit valide !"
exit 0
```

**Sauvegarde.**

---

**Rendre exécutable :**

```bash
chmod +x .git/hooks/commit-msg
```

---

**Explication :**

**`commit_msg=$(cat "$1")`**
- `$1` = Premier argument = Fichier contenant le message
- Cat lit le fichier et stocke dans la variable

**`regex='^(feat|fix|...)(\(.+\))?: .{1,50}'`**
- `^` = Début de ligne
- `(feat|fix|...)` = Type (liste d'options)
- `(\(.+\))?` = Scope optionnel entre parenthèses
- `: ` = Deux-points et espace (obligatoire)
- `.{1,50}` = Description (1 à 50 caractères)

**`grep -qE "$regex"`**
- `-q` = Quiet (pas de sortie)
- `-E` = Extended regex
- Retourne 0 si match, 1 si pas de match

---

**Tester avec un mauvais message :**

```bash
echo "test" > test.txt
git add test.txt
git commit -m "Added stuff"
```

**Résultat :**

```
[X] ERREUR : Message de commit invalide !

Format attendu : type(scope): description

Types valides :
  - feat: Nouvelle fonctionnalité
  ...

Votre message : Added stuff
```

**[X] Commit bloqué !**

---

**Tester avec un bon message :**

```bash
git commit -m "feat: Add test file"
```

**Résultat :**

```
[OK] Message de commit valide !
[main def5678] feat: Add test file
```

**[OK] Commit autorisé !**

---

### ÉTAPE 4 : Hook pre-push (tests avant push)

**Hook pre-push = Exécuté AVANT chaque push**

**Utile pour lancer des tests lourds (pas dans pre-commit)**

**Créer le hook :**

```bash
nano .git/hooks/pre-push
```

**Contenu :**

```bash
#!/bin/bash

echo "[TEST] Pre-push hook : Lancement des tests..."

# Simuler des tests (en vrai : npm test, pytest, etc.)
# Pour l'exemple, on vérifie juste que les fichiers JS sont valides

errors=0

for file in js/*.js; do
    if [ -f "$file" ]; then
        # Vérifier la syntaxe JavaScript avec node
        if ! node -c "$file" 2>/dev/null; then
            echo "[X] Erreur de syntaxe dans $file"
            errors=$((errors + 1))
        fi
    fi
done

if [ $errors -gt 0 ]; then
    echo "[X] $errors erreur(s) détectée(s). Push annulé."
    exit 1
fi

echo "[OK] Tous les tests passent !"
exit 0
```

**Sauvegarde et rendre exécutable :**

```bash
chmod +x .git/hooks/pre-push
```

---

**Explication :**

**`for file in js/*.js`**
- Boucle sur tous les fichiers .js

**`node -c "$file"`**
- `-c` = Check syntax (vérification syntaxe)
- `2>/dev/null` = Supprime les messages d'erreur (on gère nous-mêmes)

**`errors=$((errors + 1))`**
- Incrémente le compteur d'erreurs

---

**Tester :**

```bash
# Ajouter une erreur de syntaxe
echo "function broken() {" >> js/app.js

# Commiter
git add js/app.js
git commit -m "test: Add broken function"

# Essayer de push
git push
```

**Résultat :**

```
[TEST] Pre-push hook : Lancement des tests...
[X] Erreur de syntaxe dans js/app.js
[X] 1 erreur(s) détectée(s). Push annulé.
error: failed to push some refs to 'origin'
```

**[X] Push bloqué !**

---

**Corriger :**

```bash
# Enlever la ligne cassée
sed -i '$d' js/app.js

git add js/app.js
git commit --amend --no-edit
git push
```

**[OK] Push autorisé !**

---

### ÉTAPE 5 : Installer Husky (partager les hooks)

**Problème avec `.git/hooks/` : Pas versionné**

**Solution : **Husky** = Outil pour gérer les hooks Git avec npm**

**Avantages :**
- [OK] Hooks versionnés dans le repo
- [OK] Installés automatiquement (`npm install`)
- [OK] Partagés avec toute l'équipe

---

**Initialiser npm dans TaskMaster :**

```bash
cd ~/TaskMaster
npm init -y
```

**Crée `package.json`**

---

**Installer Husky :**

```bash
npm install --save-dev husky
```

---

**Initialiser Husky :**

```bash
npx husky init
```

**Ou manuellement :**

```bash
npm pkg set scripts.prepare="husky install"
npm run prepare
```

**Crée le dossier `.husky/` (versionné !)**

---

**Créer un hook pre-commit avec Husky :**

```bash
npx husky add .husky/pre-commit "npm run lint"
```

**Crée le fichier `.husky/pre-commit` :**

```bash
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm run lint
```

---

**Ajouter le script lint dans `package.json` :**

```bash
nano package.json
```

**Ajouter dans `"scripts"` :**

```json
{
  "scripts": {
    "prepare": "husky install",
    "lint": "echo '[RECHERCHE] Linting code...' && node -c js/*.js && echo '[OK] Lint passed!'"
  }
}
```

**Sauvegarde.**

---

**Tester :**

```bash
# Ajouter une erreur
echo "function broken() {" >> js/app.js

# Commiter
git add js/app.js
git commit -m "feat: Test husky"
```

**Résultat :**

```
[RECHERCHE] Linting code...
[X] Erreur de syntaxe
```

**[X] Commit bloqué par Husky !**

---

**Versionner Husky :**

```bash
git add .husky/ package.json package-lock.json
git commit -m "chore: Add Husky for Git hooks"
git push
```

**Maintenant, quand un nouveau dev fait `npm install`, Husky est installé automatiquement ! [BRAVO]**

---

### ÉTAPE 6 : Intégrer lint-staged (lint seulement les fichiers modifiés)

**Problème : `npm run lint` lint TOUS les fichiers (lent)**

**Solution : **lint-staged** = Lint seulement les fichiers en staging**

---

**Installer :**

```bash
npm install --save-dev lint-staged
```

---

**Configurer dans `package.json` :**

```bash
nano package.json
```

**Ajouter :**

```json
{
  "lint-staged": {
    "*.js": [
      "node -c",
      "git add"
    ],
    "*.css": [
      "echo 'Linting CSS...'",
      "git add"
    ]
  }
}
```

---

**Modifier le hook pre-commit :**

```bash
nano .husky/pre-commit
```

**Remplacer par :**

```bash
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx lint-staged
```

**Sauvegarde.**

---

**Maintenant, seuls les fichiers .js et .css modifiés sont vérifiés ! [RAPIDE]**

---

### ÉTAPE 7 : Ajouter Prettier (formatage automatique)

**Prettier = Formatteur de code (indentation, virgules, quotes, etc.)**

---

**Installer :**

```bash
npm install --save-dev prettier
```

---

**Créer config Prettier :**

```bash
nano .prettierrc.json
```

**Contenu :**

```json
{
  "semi": true,
  "trailingComma": "es5",
  "singleQuote": true,
  "printWidth": 100,
  "tabWidth": 2
}
```

---

**Ajouter dans lint-staged :**

```json
{
  "lint-staged": {
    "*.js": [
      "prettier --write",
      "node -c",
      "git add"
    ],
    "*.css": [
      "prettier --write",
      "git add"
    ],
    "*.html": [
      "prettier --write",
      "git add"
    ]
  }
}
```

---

**Maintenant, à chaque commit, Prettier formate automatiquement le code ! ***

---

### ÉTAPE 8 : Commitlint (valider messages avec outil)

**Au lieu d'un script bash, utiliser commitlint (plus robuste)**

---

**Installer :**

```bash
npm install --save-dev @commitlint/cli @commitlint/config-conventional
```

---

**Créer config :**

```bash
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js
```

---

**Ajouter le hook commit-msg :**

```bash
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'
```

---

**Tester :**

```bash
git commit -m "bad message"
```

**Résultat :**

```
⧗   input: bad message
[X]   subject may not be empty [subject-empty]
[X]   type may not be empty [type-empty]

[X]   found 2 problems, 0 warnings
```

**[X] Bloqué !**

---

```bash
git commit -m "feat: good message"
```

**[OK] Autorisé !**

---

### [OK] TESTS DE VALIDATION

**1. Hooks manuels fonctionnels**

- [ ] pre-commit bloque les console.log
- [ ] commit-msg valide le format
- [ ] pre-push lance les tests

---

**2. Husky installé**

- [ ] Dossier `.husky/` versionné
- [ ] `npm install` installe automatiquement les hooks
- [ ] Hooks partagés avec l'équipe

---

**3. lint-staged**

- [ ] Seuls les fichiers modifiés sont lintés
- [ ] Plus rapide que lint complet

---

**4. Prettier**

- [ ] Code formaté automatiquement avant commit
- [ ] Indentation cohérente

---

**5. commitlint**

- [ ] Messages non-conventionnels bloqués
- [ ] Messages conventionnels autorisés

---

### [IMPORTANT] POINTS CLÉS À RETENIR

**1. Git Hooks = Scripts automatiques**
- pre-commit : Avant commit
- commit-msg : Valider message
- pre-push : Avant push

**2. Emplacement**
- `.git/hooks/` : Local, non-versionné
- `.husky/` : Versionné, partagé

**3. Husky**
- Gère les hooks dans un projet npm
- Installé automatiquement avec npm install
- Hooks versionnés

**4. lint-staged**
- Lint seulement les fichiers modifiés
- Plus rapide

**5. Prettier + commitlint**
- Prettier : Formatage automatique
- commitlint : Validation des messages

---

## [COURS] CONCLUSION DE L'EXERCICE 8

**[OK] Félicitations ! Tu maîtrises les Git Hooks !**

**Ce que tu as appris :**
- Créer des hooks manuels
- Utiliser Husky pour partager
- lint-staged pour optimiser
- Prettier pour formater
- commitlint pour valider

**Compétences acquises :**
- [OK] Git Hooks (tous types)
- [OK] Husky
- [OK] lint-staged
- [OK] Prettier
- [OK] commitlint

**Temps moyen de réalisation :** 2-3 heures

**Prochaine étape :** Exercice 9 - Gestion de projet complexe ! [CONSTRUCTION]

---

---

# [ROUGE] EXERCICE 9 : GESTION DE PROJET COMPLEXE (MONOREPO)

## [LISTE] ÉNONCÉ

### Contexte professionnel

**TaskMaster est devenu un GROS projet :**

- Frontend (React)
- Backend API (Node.js)
- App mobile (React Native)
- Documentation (Docusaurus)
- Librairie partagée (TypeScript)

**Tout dans le même repository = **MONOREPO****

**Défis :**
- Gérer plusieurs applications
- Dépendances partagées
- Déploiements indépendants
- Historique propre

---

## [OBJECTIF] OBJECTIFS PÉDAGOGIQUES

À la fin de cet exercice, tu sauras :

- [OK] Structurer un monorepo
- [OK] Utiliser git submodules
- [OK] Utiliser git subtree
- [OK] Gérer les dépendances (npm workspaces, Lerna)
- [OK] CI/CD pour monorepo (GitHub Actions)
- [OK] Tagging et releases par package

---

## [DOCS] PRÉREQUIS

- Tous les exercices précédents terminés
- Compréhension de npm/yarn
- Notions de CI/CD

---

## [OK] SOLUTION COMPLÈTE

### ÉTAPE 1 : Structurer le monorepo

**Structure cible :**

```
TaskMaster/
├── packages/
│   ├── frontend/         (React app)
│   ├── backend/          (Node.js API)
│   ├── mobile/           (React Native)
│   ├── shared/           (Shared library)
│   └── docs/             (Documentation)
├── .github/
│   └── workflows/        (CI/CD)
├── package.json          (Root)
└── lerna.json           (Lerna config)
```

---

**Créer la structure :**

```bash
cd ~/TaskMaster
mkdir -p packages/{frontend,backend,mobile,shared,docs}
```

---

**Initialiser npm workspaces :**

```bash
nano package.json
```

**Ajouter :**

```json
{
  "name": "taskmaster-monorepo",
  "private": true,
  "workspaces": [
    "packages/*"
  ],
  "scripts": {
    "test": "npm run test --workspaces",
    "build": "npm run build --workspaces",
    "lint": "npm run lint --workspaces"
  }
}
```

---

**Créer un package dans `packages/shared/` :**

```bash
cd packages/shared
npm init -y
```

**Modifier `package.json` :**

```json
{
  "name": "@taskmaster/shared",
  "version": "1.0.0",
  "main": "index.js"
}
```

**Créer `index.js` :**

```bash
nano index.js
```

```javascript
// Shared utilities
export function formatDate(date) {
  return new Intl.DateTimeFormat('fr-FR').format(date);
}

export function validateEmail(email) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
```

---

**Utiliser le package shared dans frontend :**

```bash
cd ../frontend
npm init -y
npm install @taskmaster/shared
```

**Le package est installé depuis le monorepo (pas npm registry) ! [BRAVO]**

---

### ÉTAPE 2 : Git submodules (inclure un repo externe)

**Submodule = Repository Git à l'intérieur d'un autre**

**Cas d'usage : Inclure une librairie externe maintenue séparément**

---

**Ajouter un submodule :**

```bash
cd ~/TaskMaster
git submodule add https://github.com/lodash/lodash.git packages/lodash
```

**Résultat :**

```
Cloning into 'packages/lodash'...
done.
```

**Crée :**
- Dossier `packages/lodash/` (le repo cloné)
- Fichier `.gitmodules` (config des submodules)

---

**Voir `.gitmodules` :**

```bash
cat .gitmodules
```

```ini
[submodule "packages/lodash"]
	path = packages/lodash
	url = https://github.com/lodash/lodash.git
```

---

**Commiter :**

```bash
git add .gitmodules packages/lodash
git commit -m "chore: Add lodash as submodule"
```

---

**Cloner un repo avec submodules :**

**Personne A clone :**

```bash
git clone https://github.com/AliceMartin/TaskMaster.git
cd TaskMaster
```

**Le dossier `packages/lodash/` existe mais est VIDE !**

---

**Initialiser et mettre à jour les submodules :**

```bash
git submodule init
git submodule update
```

**Ou en une commande lors du clone :**

```bash
git clone --recurse-submodules https://github.com/AliceMartin/TaskMaster.git
```

---

**Mettre à jour un submodule (nouvelle version) :**

```bash
cd packages/lodash
git pull origin main
cd ../..
git add packages/lodash
git commit -m "chore: Update lodash submodule"
```

---

**Supprimer un submodule :**

```bash
git submodule deinit packages/lodash
git rm packages/lodash
rm -rf .git/modules/packages/lodash
git commit -m "chore: Remove lodash submodule"
```

---

**[ATTENTION] Problèmes avec submodules :**

[X] Complexe à gérer
[X] Oubli facile de `--recurse-submodules`
[X] Conflits lors de mises à jour

**Alternative : **subtree** (plus simple)**

---

### ÉTAPE 3 : Git subtree (alternative à submodules)

**Subtree = Intégration d'un repo externe DANS ton repo**

**Différence avec submodule :**

| Critère | Submodule | Subtree |
|---------|-----------|---------|
| **Complexité** | [X] Élevée | [OK] Simple |
| **Clone** | Nécessite `--recurse-submodules` | [OK] Automatique |
| **Historique** | Séparé | [OK] Intégré |
| **Mises à jour** | `git submodule update` | `git subtree pull` |

---

**Ajouter un subtree :**

```bash
git subtree add --prefix=packages/utils https://github.com/user/utils.git main --squash
```

**Explication :**

- `--prefix=packages/utils` : Dossier cible
- URL du repo externe
- `main` : Branche
- `--squash` : Squash l'historique (optionnel)

---

**Résultat :**

Le contenu du repo externe est copié dans `packages/utils/` et commité.

---

**Mettre à jour le subtree :**

```bash
git subtree pull --prefix=packages/utils https://github.com/user/utils.git main --squash
```

---

**Pousser des changements vers le repo externe :**

```bash
git subtree push --prefix=packages/utils https://github.com/user/utils.git main
```

---

**Avantages :**
- [OK] Plus simple que submodules
- [OK] Pas de commandes spéciales lors du clone
- [OK] Historique intégré

**Inconvénients :**
- [X] Historique peut devenir lourd
- [X] Bidirectionnel plus complexe

---

### ÉTAPE 4 : CI/CD pour monorepo (GitHub Actions)

**Objectif : Tester et déployer seulement les packages modifiés**

**Créer `.github/workflows/ci.yml` :**

```bash
mkdir -p .github/workflows
nano .github/workflows/ci.yml
```

**Contenu :**

```yaml
name: CI Monorepo

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  detect-changes:
    runs-on: ubuntu-latest
    outputs:
      frontend: ${{ steps.changes.outputs.frontend }}
      backend: ${{ steps.changes.outputs.backend }}
      shared: ${{ steps.changes.outputs.shared }}
    steps:
      - uses: actions/checkout@v3
      
      - uses: dorny/paths-filter@v2
        id: changes
        with:
          filters: |
            frontend:
              - 'packages/frontend/**'
            backend:
              - 'packages/backend/**'
            shared:
              - 'packages/shared/**'

  test-frontend:
    needs: detect-changes
    if: needs.detect-changes.outputs.frontend == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      - run: npm install
      - run: npm run test --workspace=packages/frontend

  test-backend:
    needs: detect-changes
    if: needs.detect-changes.outputs.backend == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      - run: npm install
      - run: npm run test --workspace=packages/backend

  test-shared:
    needs: detect-changes
    if: needs.detect-changes.outputs.shared == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      - run: npm install
      - run: npm run test --workspace=packages/shared
```

---

**Explication :**

**Job `detect-changes`** :
- Utilise `dorny/paths-filter` pour détecter quels dossiers ont changé
- Retourne des outputs (frontend, backend, shared)

**Jobs `test-*`** :
- Exécutés SEULEMENT si le package correspondant a changé
- `if: needs.detect-changes.outputs.frontend == 'true'`

**Résultat : Tests uniquement sur ce qui a changé ! [RAPIDE]**

---

### ÉTAPE 5 : Tagging et releases par package

**Problème : Comment versionner indépendamment chaque package ?**

**Solution : Tags avec préfixes**

---

**Convention :**

- `frontend-v1.0.0` : Frontend version 1.0.0
- `backend-v2.3.1` : Backend version 2.3.1
- `shared-v1.1.0` : Shared version 1.1.0

---

**Créer un tag pour frontend :**

```bash
git tag -a frontend-v1.0.0 -m "Frontend: Release 1.0.0

- Feature A
- Feature B
- Bug fix C"
git push origin frontend-v1.0.0
```

---

**Lister les tags d'un package :**

```bash
git tag -l "frontend-v*"
```

**Résultat :**

```
frontend-v1.0.0
frontend-v1.0.1
frontend-v1.1.0
```

---

**Automatiser avec Lerna :**

```bash
npm install --save-dev lerna
npx lerna init
```

**Configure `lerna.json` :**

```json
{
  "packages": ["packages/*"],
  "version": "independent",
  "npmClient": "npm",
  "command": {
    "publish": {
      "conventionalCommits": true,
      "message": "chore(release): publish"
    }
  }
}
```

---

**Publier avec Lerna :**

```bash
npx lerna version
```

**Lerna :**
1. Détecte les packages modifiés
2. Demande quelle version (patch, minor, major)
3. Crée les tags
4. Pousse vers GitHub

---

## [COURS] CONCLUSION DE L'EXERCICE 9

**[OK] Félicitations ! Tu maîtrises les monorepos complexes !**

**Ce que tu as appris :**
- Structurer un monorepo
- npm workspaces
- git submodules vs subtree
- CI/CD optimisé pour monorepo
- Versioning indépendant par package

**Compétences acquises :**
- [OK] Monorepo avec npm workspaces
- [OK] git submodules
- [OK] git subtree
- [OK] CI/CD pour monorepo
- [OK] Lerna

**Temps moyen de réalisation :** 4-5 heures

**Prochaine étape :** Exercice 10 - GitOps et CI/CD avec GitHub Actions ! [RAPIDE]

---

---

# [ROUGE] EXERCICE 10 : GITOPS ET CI/CD AVEC GITHUB ACTIONS (EXPERT)

## [LISTE] ÉNONCÉ

### Contexte professionnel

**TaskMaster est maintenant en PRODUCTION avec des milliers d'utilisateurs.**

**Le CTO exige :**

[OK] **Déploiement automatique** à chaque push sur main
[OK] **Tests automatiques** sur chaque PR
[OK] **Releases automatiques** avec changelog
[OK] **Rollback** facile en cas de problème
[OK] **Infrastructure as Code** (tout dans Git)

**Solution : GitOps + GitHub Actions**

---

## [OBJECTIF] OBJECTIFS PÉDAGOGIQUES

À la fin de cet exercice, tu sauras :

- [OK] Créer des workflows GitHub Actions complets
- [OK] Déploiement continu (CD)
- [OK] Tests automatisés (CI)
- [OK] Semantic Release automatique
- [OK] Docker avec GitHub Actions
- [OK] Déploiement sur cloud (Vercel, Netlify, AWS)
- [OK] GitOps avec ArgoCD (bonus)

---

## [DOCS] PRÉREQUIS

- Tous les exercices précédents terminés
- Compte GitHub
- Compréhension de CI/CD
- Notions de Docker (optionnel)

---

## [OK] SOLUTION COMPLÈTE (CONDENSÉE)

### ÉTAPE 1 : Workflow CI complet

**`.github/workflows/ci.yml` :**

```yaml
name: CI Pipeline

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'
      - run: npm ci
      - run: npm run lint

  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'
      - run: npm ci
      - run: npm test -- --coverage
      - uses: codecov/codecov-action@v3
        with:
          files: ./coverage/coverage-final.json

  build:
    runs-on: ubuntu-latest
    needs: [lint, test]
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      - run: npm ci
      - run: npm run build
      - uses: actions/upload-artifact@v3
        with:
          name: build
          path: dist/
```

---

### ÉTAPE 2 : Workflow CD (Déploiement automatique)

**`.github/workflows/deploy.yml` :**

```yaml
name: Deploy to Production

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://taskmaster.app
    steps:
      - uses: actions/checkout@v3
      
      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'
```

---

### ÉTAPE 3 : Semantic Release automatique

**`.github/workflows/release.yml` :**

```yaml
name: Release

on:
  push:
    branches: [ main ]

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
      
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      
      - run: npm ci
      
      - name: Semantic Release
        uses: cycjimmy/semantic-release-action@v3
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
        with:
          extra_plugins: |
            @semantic-release/changelog
            @semantic-release/git
```

**Configuration `.releaserc.json` :**

```json
{
  "branches": ["main"],
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    "@semantic-release/changelog",
    "@semantic-release/npm",
    "@semantic-release/github",
    [
      "@semantic-release/git",
      {
        "assets": ["CHANGELOG.md", "package.json"],
        "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
      }
    ]
  ]
}
```

**Semantic Release :**
- Analyse les commits (feat, fix, breaking)
- Détermine la version (major, minor, patch)
- Génère le CHANGELOG
- Crée le tag et la release GitHub
- Publie sur npm

**TOUT AUTOMATIQUE ! [BRAVO]**

---

### ÉTAPE 4 : Docker + GitHub Container Registry

**`Dockerfile` :**

```dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]
```

---

**`.github/workflows/docker.yml` :**

```yaml
name: Docker Build and Push

on:
  push:
    branches: [ main ]
    tags: [ 'v*' ]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v3
      
      - name: Log in to Container Registry
        uses: docker/login-action@v2
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      
      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v4
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
      
      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
```

---

### ÉTAPE 5 : Environnements et déploiements progressifs

**Stratégie : develop -> staging -> production**

**`.github/workflows/deploy-staging.yml` :**

```yaml
name: Deploy Staging

on:
  push:
    branches: [ develop ]

jobs:
  deploy-staging:
    runs-on: ubuntu-latest
    environment:
      name: staging
      url: https://staging.taskmaster.app
    steps:
      - uses: actions/checkout@v3
      - name: Deploy to Staging
        run: |
          echo "Deploying to staging..."
          # Scripts de déploiement
```

---

**`.github/workflows/deploy-production.yml` (avec approbation manuelle) :**

```yaml
name: Deploy Production

on:
  workflow_dispatch:
  push:
    tags: [ 'v*' ]

jobs:
  deploy-production:
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://taskmaster.app
    steps:
      - uses: actions/checkout@v3
      - name: Deploy to Production
        run: |
          echo "Deploying to production..."
```

**`environment: production` nécessite une approbation manuelle (configuré dans GitHub)**

---

### ÉTAPE BONUS : GitOps avec ArgoCD

**GitOps = L'état désiré de l'infra est dans Git**

**ArgoCD surveille le repo Git et synchronise automatiquement Kubernetes.**

**Structure :**

```
TaskMaster/
├── k8s/
│   ├── deployment.yaml
│   ├── service.yaml
│   └── ingress.yaml
└── .github/workflows/
    └── update-k8s.yml
```

**Workflow pour mettre à jour l'image Docker :**

```yaml
name: Update Kubernetes Manifest

on:
  push:
    tags: [ 'v*' ]

jobs:
  update-manifest:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Update image tag
        run: |
          TAG=${GITHUB_REF#refs/tags/}
          sed -i "s|image: .*|image: ghcr.io/${{ github.repository }}:${TAG}|" k8s/deployment.yaml
      
      - name: Commit and push
        run: |
          git config user.name "GitHub Actions"
          git config user.email "actions@github.com"
          git add k8s/deployment.yaml
          git commit -m "chore: Update image to ${TAG}"
          git push
```

**ArgoCD détecte le changement et déploie automatiquement ! [RAPIDE]**

---

## [COURS] CONCLUSION FINALE - EXERCICE 10 ET SÉRIE COMPLÈTE

**[BRAVO] FÉLICITATIONS ! TU AS TERMINÉ LES 10 EXERCICES GIT & GITHUB ! [BRAVO]**

---

### [GRAPHIQUE] RÉCAPITULATIF COMPLET

**[VERT] Exercice 1** - Premiers pas avec Git
- Installation, configuration, commits, historique

**[VERT] Exercice 2** - Branches et fusion
- Création de branches, merge, fast-forward, 3-way, stash

**[JAUNE] Exercice 3** - Collaboration GitHub
- Remote, push, pull, clone, pull requests

**[JAUNE] Exercice 4** - Gestion des conflits
- Résolution manuelle, mergetool, prévention

**[JAUNE] Exercice 5** - Pull Requests et Code Review
- Workflow PR, reviews, protection de branches

**[ROUGE] Exercice 6** - Git Flow
- Stratégies de branching, releases, hotfixes, tags

**[ROUGE] Exercice 7** - Rebase, Cherry-pick, Stash
- Rebase interactif, squash, cherry-pick, reflog

**[ROUGE] Exercice 8** - Git Hooks
- Automatisation, Husky, lint-staged, Prettier

**[ROUGE] Exercice 9** - Monorepo complexe
- Workspaces, submodules, subtree, Lerna

**[ROUGE] Exercice 10** - GitOps et CI/CD
- GitHub Actions, Semantic Release, Docker, déploiements

---

### [TROPHEE] COMPÉTENCES MAÎTRISÉES

Tu maîtrises maintenant :

[OK] **Git complet** (commits, branches, merges, rebase)
[OK] **Collaboration GitHub** (PRs, reviews, forks)
[OK] **Résolution de conflits** (manuelle et avec outils)
[OK] **Stratégies de branching** (Git Flow, GitHub Flow)
[OK] **Historique propre** (rebase interactif, squash)
[OK] **Automatisation** (hooks, Husky, CI/CD)
[OK] **Monorepo** (workspaces, submodules)
[OK] **DevOps** (GitHub Actions, Docker, GitOps)

---

### [RAPIDE] TU ES MAINTENANT UN EXPERT GIT !

**Temps total estimé : 25-30 heures**

**Tu peux maintenant :**
- Travailler sur n'importe quel projet Git
- Collaborer efficacement en équipe
- Résoudre tous les problèmes Git courants
- Mettre en place des workflows professionnels
- Automatiser avec CI/CD
- Gérer des projets complexes (monorepos)

---

### [DOCS] RESSOURCES POUR ALLER ENCORE PLUS LOIN

**Documentation officielle :**
- https://git-scm.com/doc
- https://docs.github.com

**Livres :**
- Pro Git (gratuit) : https://git-scm.com/book
- Git Pocket Guide (O'Reilly)

**Outils :**
- GitKraken (GUI)
- Sourcetree (GUI)
- lazygit (TUI)
- GitHub CLI (gh)

**Pratique :**
- https://learngitbranching.js.org/ (interactif)
- https://gitexercises.fracz.com/ (exercices)

---

**BRAVO ENCORE UNE FOIS ! [BRAVO][RAPIDE][FORCE]**

**Tu es prêt pour le monde professionnel du développement logiciel !**

---

**FIN DES EXERCICES GIT & GITHUB - PARTIE 3**