Chapitre 316 minDébutant
Le fichier .gitignore et les secrets
Par Josselyn C., prof de BTS SIO. Mis à jour le .
À la fin de ce chapitre, tu sauras
- dire ce qui ne doit jamais entrer dans un dépôt ;
- écrire un
.gitignoreadapté à ton projet ; - garder les secrets dans un
.envet fournir un.env.example; - réagir si un secret est parti dans un commit.
3 exercices corrigés
Le fichier .gitignore liste les fichiers et dossiers que Git doit ignorer : dépendances réinstallables, fichiers générés, réglages personnels de l'éditeur et surtout les fichiers qui contiennent des secrets, comme le .env. Ce chapitre donne sa syntaxe, des modèles prêts pour les langages du BTS SIO, la méthode pour arrêter de suivre un fichier déjà commité, et la procédure à suivre quand un mot de passe est parti sur GitHub.
Ce qui ne doit pas entrer dans un dépôt
Un dépôt contient ce qu'il faut pour reconstruire le projet, et rien d'autre.
| À ignorer | Exemples | Pourquoi |
|---|---|---|
| Les dépendances | node_modules/, vendor/ (Composer), packages/ | Énormes, réinstallables avec npm install ou composer install à partir du fichier de dépendances, qui lui est versionné |
| Les fichiers générés | dist/, build/, bin/, obj/, *.class, __pycache__/ | Produits par la compilation : on versionne la source, pas le résultat |
| Les secrets | .env, appsettings.Development.json avec un mot de passe, clés privées *.pem | Quiconque lit le dépôt lirait les mots de passe |
| Les données | Sauvegardes *.sql de production, fichiers déposés par les utilisateurs (uploads/), bases SQLite de travail | Données personnelles, volume, et ce n'est pas du code |
| Les journaux et fichiers temporaires | *.log, *.tmp, *.swp | Propres à une exécution |
| Les fichiers du système et de l'éditeur | .DS_Store (macOS), Thumbs.db (Windows), .idea/, .vs/ | Propres à ta machine |
La syntaxe du .gitignore
Le fichier s'appelle exactement .gitignore, sans extension, et se place à la racine du dépôt. Une règle par ligne :
| Règle | Ce qu'elle ignore |
|---|---|
fichier.txt | Tout fichier ou dossier nommé fichier.txt, à n'importe quel niveau |
/fichier.txt | Seulement celui de la racine (le / initial ancre la règle au dossier du .gitignore) |
dossier/ | Un dossier de ce nom et tout son contenu, à n'importe quel niveau (le / final vise les dossiers seulement) |
*.log | Tous les fichiers qui finissent par .log ; * remplace n'importe quelle suite de caractères sauf / |
config/*.json | Les .json directement dans config/, pas dans ses sous-dossiers |
**/temp | temp dans n'importe quel sous-dossier ; ** traverse les niveaux |
logs/**/*.log | Les .log à n'importe quelle profondeur sous logs/ |
!important.log | Exception : ce fichier n'est pas ignoré, même si une règle précédente l'ignorait |
# Dépendances | Un commentaire |
L'ordre compte : la dernière règle qui correspond l'emporte. Une exception ! ne fonctionne pas si le dossier parent est lui-même ignoré, car Git n'entre pas dans un dossier ignoré.
# Ignorer tous les fichiers de logs/ sauf le .gitkeep qui garde le dossier dans le dépôt
logs/*
!logs/.gitkeep
Git ne versionne pas les dossiers vides. Pour qu'un dossier existe dans le dépôt, on y place par convention un fichier vide nommé .gitkeep.
Des .gitignore pour les projets du BTS SIO
Tu n'as pas à tout écrire de zéro. GitHub propose un modèle par langage quand tu crées un dépôt, et le dépôt public github/gitignore en rassemble des centaines. Voici des bases courtes pour les projets que tu feras.
Node.js, Express et React :
# Dépendances
node_modules/
# Builds
dist/
build/
# Secrets et configuration locale
.env
.env.*
!.env.example
# Journaux
*.log
npm-debug.log*
# Couverture des tests
coverage/
# Système et éditeurs
.DS_Store
Thumbs.db
.idea/
.vscode/*
!.vscode/extensions.json
PHP et Symfony :
/vendor/
/var/
/public/uploads/
.env.local
.env.*.local
/.phpunit.cache/
Symfony a une convention à lui : le fichier .env est versionné et ne contient que des valeurs par défaut sans secret ; les vraies valeurs vont dans .env.local, ignoré. Les modèles créés par symfony new ou par Flex l'appliquent déjà.
C# et .NET (Visual Studio) :
bin/
obj/
.vs/
*.user
appsettings.Development.json
dotnet new gitignore génère le modèle complet maintenu par Microsoft. Pour un projet WinForms ou ASP.NET, c'est la bonne solution.
Python et Java : __pycache__/, .venv/, *.pyc d'un côté ; target/ (Maven), build/ et .gradle/ (Gradle), *.class de l'autre.
Le .env et le .env.example
Une application a besoin de réglages qui changent selon l'endroit où elle tourne : l'adresse de la base, son mot de passe, la clé qui signe les jetons de connexion. On les range dans des variables d'environnement, souvent lues depuis un fichier .env à la racine du projet.
# .env : jamais versionné
DB_HOST=localhost
DB_USER=sorbier_app
DB_PASSWORD=Kq7!vT2pL9zR
JWT_SECRET=4f9d2c7e8b1a6f3d0c5e9b2a7d4f1c8e
Le problème : un nouveau membre de l'équipe, ou la commission de l'E6, ne sait pas quelles variables créer. La solution est un fichier .env.example, versionné, qui liste les mêmes variables avec des valeurs factices :
# .env.example : versionné, copie-le en .env et remplis les valeurs
DB_HOST=localhost
DB_USER=sorbier_app
DB_PASSWORD=change-moi
JWT_SECRET=genere-une-longue-chaine-aleatoire
Le README explique : « copie .env.example en .env et remplis les valeurs ». Ce couple .env ignoré et .env.example versionné est ce que la commission s'attend à trouver dans ton dépôt (préparer son dépôt pour l'examen).
Vérifier qu'un fichier est bien ignoré
Après avoir écrit ton .gitignore, git status ne doit plus afficher les fichiers ignorés. Pour comprendre pourquoi un fichier est ignoré, ou ne l'est pas :
git check-ignore -v .env
.gitignore:7:.env .env
La règle .env de la ligne 7 du .gitignore ignore ce fichier. Si la commande n'affiche rien, aucune règle ne l'ignore. git status --ignored liste en plus les fichiers ignorés présents dans ton dossier.
Un fichier ignoré mais déjà suivi
C'est le piège classique. Tu ajoutes .env au .gitignore, mais git status continue d'afficher modified: .env. La raison : le .gitignore ne concerne que les fichiers non suivis. Un fichier déjà commité reste suivi, quelles que soient les règles.
Pour arrêter de le suivre sans le supprimer de ton disque :
git rm --cached .env
git commit -m "Retire .env du suivi"
--cached agit seulement sur la zone de préparation : le fichier reste sur ton disque, mais il ne fera plus partie des prochains commits. Pour un dossier entier, ajoute -r : git rm -r --cached node_modules.
Le .gitignore global
Les fichiers propres à ta machine (.DS_Store, Thumbs.db, les réglages de ton éditeur) n'ont pas leur place dans le .gitignore de chaque projet. Range-les dans un fichier global, valable pour tous tes dépôts :
git config --global core.excludesFile ~/.gitignore_global
Puis écris tes règles dans ~/.gitignore_global. Pour ignorer un fichier dans un seul dépôt sans toucher au .gitignore partagé, utilise .git/info/exclude, qui n'est jamais versionné.
Que faire si un secret est parti dans un commit
Ça arrive à tout le monde, une fois. Le réflexe à avoir dépend d'une seule question : le commit a-t-il été poussé ?
Le commit n'a pas été poussé. Le secret n'existe que sur ta machine. Retire-le du commit avant que quiconque le voie :
# Le secret est dans le dernier commit
echo ".env" >> .gitignore
git rm --cached .env
git add .gitignore
git commit --amend --no-edit
--amend remplace le dernier commit par une version sans le .env (modifier le dernier commit). Si le secret est dans un commit plus ancien, mais toujours non poussé, un rebase interactif permet de corriger ce commit (chapitre 7).
Le commit a été poussé. Considère le secret comme public, même si le dépôt est privé et même s'il n'est resté en ligne que trente secondes : des robots scrutent en permanence les dépôts publics à la recherche de clés, et un dépôt privé se clone, se partage et devient parfois public. La procédure, dans cet ordre :
- Révoquer le secret. Change le mot de passe de la base, régénère la clé d'API, crée un nouveau jeton. C'est la seule étape qui protège vraiment : un secret révoqué ne vaut plus rien, qu'il traîne dans l'historique ou non.
- Vérifier les dégâts. Consulte les journaux du service concerné : connexions inconnues, appels d'API, frais facturés. Préviens ton responsable ou ton tuteur.
- Retirer le fichier du suivi avec
git rm --cachedet l'ajouter au.gitignore, comme ci-dessus, puis pousser. - Nettoyer l'historique si le dépôt est public ou si le secret ne peut pas être changé. L'outil recommandé par la documentation de Git est
git filter-repo, un programme Python à installer à part (pip install git-filter-repo, ou le paquetgit-filter-repode ta distribution) :
# Dans un clone frais du dépôt
git filter-repo --invert-paths --path .env
git remote add origin https://github.com/ton-pseudo/sorbier-frais.git
git push origin --force --all
git push origin --force --tags
--path .env --invert-paths réécrit chaque commit de l'historique en supprimant ce fichier. Par sécurité, git filter-repo retire le dépôt distant origin de ta configuration : tu dois le rajouter avant de pousser. Chaque commit réécrit change d'empreinte : tous les membres de l'équipe doivent ensuite recloner le dépôt, sinon un simple git push de leur part réintroduirait l'ancien historique. Sur GitHub, des copies peuvent subsister dans les forks et dans les pull requests en cache : pour un secret sensible, le support de GitHub peut les purger.
Les garde-fous automatiques
Mieux vaut que l'outil t'arrête avant le push :
- La protection contre les secrets de GitHub (secret scanning push protection) est active par défaut sur les dépôts publics : si ton commit contient une clé reconnue (jeton GitHub, clé AWS, clé Stripe…), GitHub refuse le
pushet t'indique le fichier et la ligne. Elle ne reconnaît pas un simple mot de passe de base de données : elle ne remplace pas ta vigilance. - Des outils comme Gitleaks analysent ton dépôt et son historique en local ou dans ton pipeline d'intégration continue, et détectent aussi des motifs génériques.
- Un
.gitignoreposé au premier commit, avec.envdedans, avant toutgit add ..
Exercices
Exercice 1 sur 3 Que fait cette règle ? Réussi À revoir
Pour chaque fichier, dis s'il est ignoré par ce .gitignore, placé à la racine du dépôt :
*.log
!erreurs.log
/build/
config/*.local.json
serveur.loglogs/erreurs.logbuild/app.jssrc/build/outil.jsconfig/base.local.jsonconfig/prod/base.local.json
Voir la réponseMasquer la réponse de l'exercice 1
- Ignoré : il correspond à
*.log. - Non ignoré :
*.logl'ignore, mais l'exception!erreurs.log, écrite après, l'emporte. Sans/, elle vaut à n'importe quel niveau. - Ignoré :
/build/vise le dossierbuildde la racine. - Non ignoré : le
/initial ancre la règle à la racine,src/build/n'est pas concerné. - Ignoré : il est directement dans
config/et correspond à*.local.json. - Non ignoré :
*ne traverse pas les/, et le fichier est dans un sous-dossier deconfig/. Il faudraitconfig/**/*.local.json.
Tu avais trouvé ?
Exercice 2 sur 3 Le .env déjà commité Réussi À revoir
Hugo a commité et poussé le .env de l'API il y a trois jours, avec le mot de passe de la base de test et la clé qui signe les jetons de connexion. Le dépôt est public. Il vient d'ajouter .env au .gitignore, mais git status affiche toujours modified: .env.
- Pourquoi le
.gitignoren'a-t-il aucun effet ? - Donne, dans l'ordre, les actions à mener.
- Que doit faire Lina après le nettoyage de l'historique ?
Voir la réponseMasquer la réponse de l'exercice 2
- Le
.gitignorene s'applique qu'aux fichiers non suivis. Le.enva déjà été commité : Git continue de le suivre. - D'abord révoquer : changer le mot de passe du compte MySQL et générer une nouvelle clé de signature des jetons (les anciens jetons deviennent invalides, les utilisateurs devront se reconnecter). Ensuite vérifier les journaux du serveur de test. Puis
git rm --cached .env, commit et push. Enfin, comme le dépôt est public, nettoyer l'historique avecgit filter-repo --invert-paths --path .envdans un clone frais, rajouter le distant et pousser avec--force. Créer au passage un.env.exampleavec des valeurs factices. - Sauvegarder son propre
.env, puis supprimer son clone et recloner le dépôt. Si elle poussait depuis son ancien clone, elle réintroduirait les commits qui contiennent le secret.
Tu avais trouvé ?
Exercice 3 sur 3 Écrire un .gitignore Réussi À revoir
Écris le .gitignore d'un projet Symfony qui contient aussi un dossier front/ avec une application React. Le front a ses propres dépendances npm et produit un dossier front/dist. Les utilisateurs déposent des justificatifs dans public/uploads/. On garde le dossier public/uploads/ dans le dépôt, vide.
Voir la réponseMasquer la réponse de l'exercice 3
# Symfony
/vendor/
/var/
.env.local
.env.*.local
# Justificatifs déposés : on garde le dossier, pas son contenu
/public/uploads/*
!/public/uploads/.gitkeep
# Front React
/front/node_modules/
/front/dist/
# Système et éditeurs
.DS_Store
Thumbs.db
.idea/
Il faut créer le fichier vide public/uploads/.gitkeep et le versionner. La règle /public/uploads/* ignore le contenu du dossier, pas le dossier lui-même : c'est pour cela que l'exception fonctionne. Avec /public/uploads/, Git n'entrerait plus dans le dossier et l'exception serait sans effet.
Tu avais trouvé ?