Git : Filter-repo
We used AI while writing this content.
git filter-repo est un outil polyvalent et performant pour réécrire l'historique Git. Il remplace git filter-branch en offrant de meilleures performances (plusieurs ordres de grandeur plus rapide), plus de fonctionnalités, et une conception plus sûre. Le projet Git lui-même recommande maintenant d'utiliser git filter-repo plutôt que git filter-branch.
Prérequis
Avant d'utiliser git filter-repo, assurez-vous d'avoir :
- Git >= 2.36.0
- Python >= 3.6
Installation
1. Installation simple
Le moyen le plus simple est de placer le script dans votre $PATH :
# Télécharger le script
curl -o ~/.local/bin/git-filter-repo https://raw.githubusercontent.com/newren/git-filter-repo/main/git-filter-repo
# Rendre exécutable
chmod +x ~/.local/bin/git-filter-repo
2. Installation via gestionnaire de paquets
# Via pip (Python)
pip install git-filter-repo
# Ubuntu/Debian
sudo apt install git-filter-repo
# macOS (Homebrew)
brew install git-filter-repo
# Fedora
sudo dnf install git-filter-repo
3. Vérification de l'installation
git filter-repo --version
Cas d'usage courants
Supprimer un fichier de tout l'historique
git filter-repo --path fichier-sensible.txt --invert-paths
L'option --invert-paths inverse la sélection : au lieu de garder le fichier, on le supprime.
Supprimer un dossier entier
git filter-repo --path dossier-a-supprimer/ --invert-paths
Conserver uniquement certains chemins
# Garder uniquement le dossier src/
git filter-repo --path src/
# Garder plusieurs dossiers
git filter-repo --path src/ --path docs/ --path README.md
Déplacer tous les fichiers dans un sous-répertoire
git filter-repo --to-subdirectory-filter mon-projet/
Avant :
repo/
├── README.md
├── src/
└── docs/
Après :
repo/
└── mon-projet/
├── README.md
├── src/
└── docs/
Cette opération réécrit tout l'historique comme si les fichiers avaient toujours été dans ce sous-répertoire.
Renommer des fichiers ou dossiers
# Renommer un fichier
git filter-repo --path-rename ancien-nom.txt:nouveau-nom.txt
# Renommer un dossier
git filter-repo --path-rename old-dir/:new-dir/
# Renommer plusieurs éléments
git filter-repo \
--path-rename src/:lib/ \
--path-rename README.txt:README.md
Modifier les préfixes de tags
# Ajouter un préfixe aux tags
git filter-repo --tag-rename '':'v'
# Remplacer un préfixe
git filter-repo --tag-rename 'old-':'new-'
Options avancées
Analyse préliminaire
Avant de modifier votre dépôt, analysez-le pour identifier ce qui prend de la place :
git filter-repo --analyze
Cela créé un dossier .git/filter-repo/analysis/ avec des rapports détaillés sur :
- Les plus gros fichiers
- Les extensions de fichiers
- Les chemins les plus fréquents
- L'historique des noms de fichiers
Combiner plusieurs opérations
git filter-repo \
--path src/ \
--path-rename src/:lib/ \
--to-subdirectory-filter mon-module/ \
--tag-rename '':'mon-module-'
Cette commande :
- Ne garde que le dossier
src/ - Le renomme en
lib/ - Place tout dans
mon-module/ - Ajoute
mon-module-aux tags
Utilisation avec des callbacks Python
Pour des modifications complexes, utilisez des callbacks :
git filter-repo --blob-callback '
if filename == b"config.py":
return blob.data.replace(b"SECRET_KEY", b"REDACTED")
'
Comparaison des approches
| Outil | Vitesse | Facilité d'usage | Sécurité | Flexibilité |
|---|---|---|---|---|
| git filter-repo | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| git filter-branch | ⭐ | ⭐⭐ | ⭐⭐ | ⭐⭐⭐ |
| BFG Repo Cleaner | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
Avantages de git filter-repo
✅ Performance exceptionnelle : Plusieurs ordres de grandeur plus rapide que filter-branch
✅ Sécurité renforcée : Détecte automatiquement si vous travaillez dans un clone frais
✅ Nettoyage automatique : Supprime automatiquement les anciennes données et repacks le dépôt
✅ Fonctionnalités riches : Support de renommage, filtrage, analyse, callbacks Python
✅ Évite les pièges : Ne mélange pas ancien et nouvel historique
✅ Recommandé officiellement : Par le projet Git lui-même
Points d'attention critiques
⚠️ Avertissements importants
-
Clone frais obligatoire : Travaillez toujours dans un clone frais du dépôt
git clone https://github.com/user/repo.git repo-filtered cd repo-filtered git filter-repo [options] -
L'historique est complètement réécrit : Tous les hashes de commit changent
-
Coordination d'équipe nécessaire : Tous les collaborateurs devront cloner à nouveau
-
Force push requis :
git remote add origin https://github.com/user/repo.git git push origin --force --all git push origin --force --tags -
Sauvegardez avant : Créez une copie de secours
git clone --mirror https://github.com/user/repo.git repo-backup.git
Workflow complet recommandé
Exemple : Extraire un sous-projet pour le fusionner ailleurs
# 1. Analyser le dépôt source
git clone https://github.com/org/monorepo.git projet-extrait
cd projet-extrait
git filter-repo --analyze
# 2. Examiner les rapports dans .git/filter-repo/analysis/
# 3. Extraire et réorganiser
git filter-repo \
--path src/module/ \
--path-rename src/module/:src/ \
--to-subdirectory-filter projet-module/ \
--tag-rename '':'module-'
# 4. Vérifier le résultat
git log --oneline --graph --all
ls -la
# 5. Ajouter le remote et pousser
git remote add origin https://github.com/org/nouveau-repo.git
git push origin --force --all
git push origin --force --tags
Résolution des problèmes courants
Erreur : "not running in a fresh clone"
Cause : git filter-repo refuse de s'exécuter dans un dépôt qui n'est pas un clone frais.
Solution :
# Option 1 : Utiliser un nouveau clone
git clone https://github.com/user/repo.git repo-fresh
cd repo-fresh
# Option 2 : Forcer (non recommandé)
git filter-repo --force [options]
Les remotes ont disparu
Cause : git filter-repo supprime automatiquement les remotes pour éviter les pushs accidentels.
Solution :
# Rajouter le remote après le filtrage
git remote add origin https://github.com/user/repo.git
Commits vides créés
Cause : Certains commits ne contiennent plus de modifications après filtrage.
Solution : git filter-repo supprime automatiquement ces commits (c'est voulu). Pour les garder :
git filter-repo --prune-empty never [autres options]
Exemples pratiques détaillés
1. Supprimer un mot de passe committé par erreur
# Clone frais
git clone https://github.com/user/repo.git repo-clean
cd repo-clean
# Supprimer le fichier
git filter-repo --path config/passwords.yml --invert-paths
# Vérifier
git log --all --oneline -- config/passwords.yml
# (ne devrait rien retourner)
# Pousser
git remote add origin https://github.com/user/repo.git
git push origin --force --all
2. Diviser un monorepo en plusieurs dépôts
# Pour chaque sous-projet
for module in frontend backend api; do
git clone monorepo.git ${module}-repo
cd ${module}-repo
git filter-repo --path ${module}/ --path-rename ${module}/:
git remote add origin https://github.com/org/${module}.git
git push origin --force --all
git push origin --force --tags
cd ..
done
3. Fusionner plusieurs dépôts dans un monorepo
# Préparer chaque dépôt
for repo in proj-a proj-b proj-c; do
git clone https://github.com/org/${repo}.git ${repo}-temp
cd ${repo}-temp
git filter-repo --to-subdirectory-filter ${repo}/
cd ..
done
# Créer le monorepo
git init monorepo
cd monorepo
# Fusionner chaque dépôt
for repo in proj-a proj-b proj-c; do
git remote add ${repo} ../${repo}-temp
git fetch ${repo}
git merge --allow-unrelated-histories ${repo}/main
git remote remove ${repo}
done
Utilisation comme bibliothèque Python
Pour des besoins très spécifiques, utilisez git-filter-repo comme module Python :
#!/usr/bin/env python3
import git_filter_repo as fr
def my_blob_callback(blob, callback_metadata):
# Remplacer du texte dans tous les fichiers
if b'OLD_TEXT' in blob.data:
blob.data = blob.data.replace(b'OLD_TEXT', b'NEW_TEXT')
args = fr.FilteringOptions.parse_args(['--force'])
filter = fr.RepoFilter(args, blob_callback=my_blob_callback)
filter.run()
Liens utiles
- Documentation officielle
- Dépôt GitHub
- Guide de conversion depuis filter-branch
- Guide de conversion depuis BFG
- FAQ
- Exemples avancés
Résumé des options essentielles
| Option | Usage | Exemple |
|---|---|---|
--path |
Garder/filtrer des chemins | --path src/ |
--invert-paths |
Inverser la sélection | --path temp/ --invert-paths |
--path-rename |
Renommer fichiers/dossiers | --path-rename old/:new/ |
--to-subdirectory-filter |
Déplacer tout dans un sous-dossier | --to-subdirectory-filter projet/ |
--tag-rename |
Renommer les tags | --tag-rename '':'v' |
--analyze |
Analyser le dépôt | --analyze |
--force |
Forcer sur dépôt non-frais | --force (déconseillé) |
--dry-run |
Simuler sans modifier | --dry-run |
Copyleft Statement
Renoncé du droit d'auteur
Much of our content is freely available under the Creative Commons BY-NC-ND 4.0 licence, which allows free distribution and republishing of our content for non-commercial purposes, as long as Ronzz.org is appropriately credited and the content is not being modified materially to express a different meaning than it is originally intended for. It must be noted that some images on Ronzz.org are the intellectual property of third parties. Our permission to use those images may not cover your reproduction. This does not affect your statutory rights.
Nous mettons la plupart de nos contenus disponibles gratuitement sous la licence Creative Commons By-NC-ND 4.0, qui permet une distribution et une republication gratuites de notre contenu à des fins non commerciales, tant que Ronzz.org est correctement crédité et que le contenu n'est pas modifié matériellement pour exprimer un sens différent que prévu à l'origine.Il faut noter que certaines images sur Ronzz.org sont des propriétés intellectuelles de tiers. Notre autorisation d'utiliser ces images peut ne pas couvrir votre reproduction. Cela n'affecte pas vos droits statutaires.
Member discussion