

- Description
- Aiguillage ferroviaire vu de près, où la voie se sépare en deux.
- Source
- Xunil · page d’origine
- Licence
- PD Domaine public
Git contre TFVC : comparer, migrer, faire coexister
Comparer Git et TFVC de façon notée et contextualisée, sans dogme.
En bref
- Comparer Git et TFVC de façon notée et contextualisée, sans dogme.
- Choisir selon des scénarios (équipe, dépôt, contraintes de droits, binaires, audit, CI).
- Connaître les voies de migration TFVC → Git avec ou sans historique, les outils (
git-tfs,git-tf, import Azure DevOps) et leurs limites. - Décrire la coexistence d'un dépôt Git local au-dessus d'un TFVC officiel, et ses risques.
- Disposer d'un plan de migration par étapes et d'une liste de pièges.
Prérequis : Git en profondeur, TFVC en profondeur.
Niveau : 🟡→🔴
Deux philosophies#
🟡 Niveau pratique
| Dimension | TFVC | Git |
|---|---|---|
| Architecture | Centralisée : serveur de vérité | Distribuée : dépôt complet partout |
| Unité d'enregistrement | Changeset serveur | Commit local (puis push) |
| Identifiant | Numéro séquentiel | Hachage |
| Branche | Dossier serveur (objet lourd, coordonné) | Pointeur léger |
| Verrouillage | Possible (checkout lock) | Pas natif (verrouillage de fichiers via Git LFS) |
| Revue de code | Revue Visual Studio, shelvesets | Pull requests, politiques de branche |
| Droits | Par chemin (jusqu'au fichier) | Par dépôt ou par branche |
TFVC raisonne « le serveur sait » ; Git raisonne « l'historique est un graphe que chacun possède ». Ce renversement explique la plupart des difficultés de passage : plus de checkout, un commit n'est pas un check-in, la branche devient banale, l'historique est modifiable localement.
Équivalences de vocabulaire et de gestes#
🟡 Niveau pratique
| Geste | TFVC (tf) |
Git |
|---|---|---|
| Récupérer | tf get |
git pull (= fetch + merge/rebase) |
| Éditer | tf checkout (workspace serveur) |
rien : on édite |
| Enregistrer | tf checkin |
git add + git commit puis git push |
| Annuler | tf undo |
git restore / git reset |
| Historique | tf history |
git log |
| Mise de côté | tf shelve |
git stash (local) ou branche poussée |
| Branche | tf branch |
git switch -c |
| Fusionner | tf merge |
git merge / git rebase |
| Étiquette | tf label |
git tag |
| Ignorer | .tfignore |
.gitignore |
| Qui a modifié | Annoter (Visual Studio ; pas de commande tf) |
git blame |
| Lier à un ticket | Boîte de dialogue d'archivage (Visual Studio), ou tf checkin -associate:123 (client Team Explorer Everywhere) |
#123 dans le message (Azure Repos), AB#123 (GitHub relié à Azure Boards), ou lien en PR |
Le piège mental n°1 : « un commit n'est pas un check-in ». Un check-in publie ; un commit est une sauvegarde locale. Rien n'est partagé tant qu'on n'a pas fait git push. Enseignez donc deux rituels distincts.
Comparatif noté#
🟡 Niveau pratique
Notes /5 d'expert. Contexte : équipe de 5 à 30 développeurs, projet SQL + Power BI + scripts, dépôt de quelques Go, Azure DevOps (Server ou Services), livraisons par versions produit. Appréciations contextuelles (voir NOTATION).
| Critère | Git | TFVC | Justification |
|---|---|---|---|
| Courbe d'apprentissage | 2/5 | 4/5 | Git expose index, rebase, HEAD ; TFVC est linéaire |
| Performance sur gros dépôts | 3/5 | 4/5 | Git : partial clone/Scalar nécessaires ; TFVC : mapping partiel |
| Branches / fusions | 5/5 | 3/5 | Branches triviales, fusion par graphe vs branche = dossier |
| Traçabilité / audit | 4/5 | 4/5 | Commits signables / changesets numérotés et liés aux work items |
| Granularité des droits | 2/5 | 5/5 | Chemin vs dépôt |
| Fichiers binaires / volumineux | 2/5 | 4/5 | LFS requis vs natif |
| Intégration CI/CD | 5/5 | 3/5 | Pipelines YAML déclenchés par PR vs builds classiques |
| Revue de code | 5/5 | 2/5 | Pull requests et politiques vs revue ponctuelle |
| Adéquation SQL/BI | 4/5 | 3/5 | Diff et fusion de TMDL/JSON par PR vs sans revue structurée |
| Travail hors ligne | 5/5 | 2/5 | Dépôt complet vs dépendance serveur |
| Pérennité de l'écosystème | 5/5 | 2/5 | Investissement vs « feature complete » |
| Disponibilité de compétences | 5/5 | 2/5 | Marché de l'emploi, formation |
| Coût de transition | n/a | n/a | Voir plan de migration |
Lecture : Git l'emporte nettement sur les axes « écosystème » (CI, revue, IA, recrutement, pérennité) ; TFVC garde l'avantage sur droits par chemin, binaires, simplicité. Aucun des deux ne gagne partout, et une note moyenne serait trompeuse : pondérez par vos contraintes.
Scénarios#
🟡 Niveau pratique
| Scénario | Recommandation | Pourquoi |
|---|---|---|
| Nouveau projet data/BI en 2026 | Git | Défaut Microsoft, écosystème, PBIP/TMDL texte |
| Équipe 8 personnes, dépôt TFVC stable, livraisons par kit, peu de CI | Rester TFVC, préparer l'avenir (coexistence, policies migrées) | Pas de gain immédiat suffisant |
| Équipe 25 personnes, besoin de revues systématiques et pipeline de validation | Migrer vers Git | PR et policies de branche |
| Sous-traitants à droits restreints par dossier | TFVC, ou plusieurs dépôts Git | Droits par chemin vs découpage |
| Énormes binaires (assets, bases d'exemple) | TFVC/Perforce, ou Git + LFS discipliné | Coût de stockage/clone |
| Historique réglementaire à conserver 10 ans | TFVC conservé en lecture + Git pour la suite | Garder l'archive sans migration risquée |
| Maintien de 4 versions produit en parallèle | Git (branches de release) ou TFVC (dossiers de release) | Voir 05 |
| Formation de juniors, recrutement | Git | Compétence attendue |
| Dépendance forte à Visual Studio et au « tout Microsoft sur site » | Git sur Azure DevOps Server | Même plateforme, autre moteur |
Faut-il migrer#
🔴 Niveau expert
Migrer a un coût : formation, outillage, risques sur l'historique et les liens work items, rupture de l'habitude. Les déclencheurs légitimes :
- Besoin de revue de code outillée (pull requests, politiques) pour élever la qualité.
- Besoin de CI/CD moderne sur chaque changement.
- Pérennité : sortie d'un moteur gelé (voir 03).
- Recrutement et montée en compétence.
- Usage de l'IA de développement native aux plateformes Git.
- Besoin de branches par tâche à faible coût.
Non-déclencheurs : « Git, c'est la mode », « les autres le font », un seul dev gêné par une commande. Mesurez : fréquence des conflits, durée de revue, lead time de livraison, onboarding. Une équipe sans pratique de revue sous TFVC n'en aura pas davantage sous Git.
Migrer l'outil sans migrer les pratiques : on obtient TFVC en pire (commits géants, force-push, branches éternelles). Prévoyez formation, conventions de branches (05) et protections.
Options de migration#
🔴 Niveau expert
| Option | Description | Historique | Effort | Risque |
|---|---|---|---|---|
| Tip migration (instantané) | Importer la dernière version dans un nouveau dépôt Git ; l'ancien TFVC est conservé en lecture seule | Aucun (ou référence au changeset d'origine) | 1/5 | Faible : perte d'historique accessible, mais archivé |
| Migration avec historique | Rejouer les changesets en commits | Complet (ou N derniers mois) | 3-4/5 | Moyen : mappage des auteurs, branches, renommages |
| Migration partielle | Importer certaines branches/dossiers seulement | Sélectif | 2-3/5 | Moyen |
| Approche hybride | TFVC archive en lecture ; Git démarre à un changeset donné | Les deux séparés | 2/5 | Faible, mais deux sources à connaître |
Microsoft recommande la migration « tip », avec au plus un historique limité (l'outil d'import natif plafonne à 180 jours) : l'historique complet est difficile à rejouer fidèlement et peu consulté.
Conservez le dépôt TFVC en lecture seule pendant la période réglementaire ; placez dans le premier commit Git une référence (« importé depuis TFVC $/Projet/Main, changeset 45815 »), et dans les notes de version les correspondances de numéros.
Points structurants à décider :
- Branches : une branche TFVC = un dossier ; les branches mortes sont à ignorer. Souvent on migre Main + les branches de release vivantes.
- Auteurs : table de correspondance
DOMAINE\nom→Nom <email>. - Work items : les liens vers changesets deviennent obsolètes ; on peut conserver les numéros dans les messages de commit migrés pour la recherche.
- Labels : deviennent des tags (si importés) ; vérifiez qu'ils ne mélangent pas des versions.
- Fichiers volumineux : à trier (LFS ? sortir du dépôt ?).
- Encodages/fins de ligne : normalisez avant l'import (06) ; sinon l'historique entier est « modifié » au premier commit de normalisation.
Outils#
🔴 Niveau expert
| Outil | Nature | Atouts | Limites |
|---|---|---|---|
| Import Git Azure DevOps (Repos > Importer) | Fonction native de la plateforme, option « Migrate history » | Aucun outil à installer ; instantané ou N jours d'historique ; adapté au « tip » | Historique plafonné à 180 jours ; dépôt importé limité à 1 Go ; une seule branche (ou la racine) par import |
| git-tfs (projet communautaire) | Pont bidirectionnel git tfs clone/fetch/checkin |
Historique complet, travail en Git local avec check-in TFVC, branches | Dépend du client TFVC installé (Team Explorer ou Visual Studio) ; plus activement maintenu ; Windows |
| git-tf (Microsoft) | Outil Java historique de Microsoft | Clone TFVC → Git | Aucune nouvelle version depuis 2013 (dernière version 2.0.3, prévue pour TFS 2010 à 2013) ; à éviter pour de nouveaux projets |
Scripts maison (tf history → git fast-import) |
Conversion sur mesure | Contrôle total (mappage, filtrage, normalisation) | Effort, maintenance ; réservé aux cas particuliers |
| Outils commerciaux (ex. offres d'éditeurs de migration) | Services/outils tiers | Support | Coût ; évaluer sur pilote |
Exemple d'usage de git-tfs (poste Windows, Visual Studio/Team Explorer installé) :
# Historique complet d'une branche
git tfs clone https://tfs.exemple.local/tfs/Collection $/Projet/Main D:\Migration\Main --branches=none
# Historique partiel : à partir d'un changeset
git tfs clone https://tfs.exemple.local/tfs/Collection $/Projet/Main D:\Migration\Main --changeset=45000
# Auteurs
git tfs clone ... --authors=auteurs.txt
# Nettoyage avant publication : retirer les métadonnées git-tfs-id si non souhaitées
git filter-repo --message-callback "..." # selon besoins
git remote add origin https://dev.azure.com/org/projet/_git/mon-produit
git push -u origin --all
Limites de la fonction d'import native : historique limité à 180 jours, dépôt importé limité à 1 Go, une seule branche par import. Symptôme : import refusé pour dépôt trop volumineux (ou historique tronqué). Cause : limites de la fonctionnalité. Remède : nettoyer et réduire d'abord, ou utiliser git-tfs, ou migrer en « tip ».
Coexistence git local et TFVC officiel#
🔴 Niveau expert
Situation courante : l'organisation impose TFVC comme archive officielle (builds, audit), mais l'équipe veut les bénéfices de Git à son échelle : commits fréquents, branches, stash, bisect, blame, outils IA. Solution pragmatique : un dépôt git local sans remote dans le même dossier que le workspace TFVC.
Fonctionnement :
- On travaille et on commit en Git local pendant la journée (commits atomiques, historique fin).
- Aux jalons (fin de chantier, fin de journée), on archive en TFVC :
tf adddes nouveaux fichiers,tf checkinavec lien vers le work item. - Les deux historiques coexistent : Git est le brouillon fin, TFVC la vérité officielle.
Règles pour que ça tienne :
- Deux listes d'exclusion alignées :
.gitignoreet.tfignore; un fichier ignoré par l'un doit l'être par l'autre (sauf cas délibéré). Voir 03. - Dossier
.gitexclu de TFVC (ne jamais l'ajouter au contrôle de source) et fichiers TFVC internes ($tf,.tf) exclus de Git. - Fins de ligne et encodage normalisés de la même manière des deux côtés (
.gitattributes+ convention TFVC), sinon chaque aller-retour provoque des diffs parasites. - Dates et auteurs : le commit TFVC ne reprend pas l'historique Git ; conservez des commentaires de check-in porteurs de sens, car ils sont ce que verra l'audit.
- Droit de lecture seule en workspace TFVC : en workspace serveur, après
tf get, les fichiers sont en lecture seule et il faut untf checkoutpréalable avant que Git ne les modifie. En workspace local, les fichiers restent modifiables : les éditions sont détectées automatiquement, ettf reconcile /promotetransforme les ajouts/suppressions faits hors de Visual Studio en modifications en attente. - Un seul sens d'écriture : ne jamais « synchroniser » TFVC → Git → TFVC automatiquement sans règle ; le plus sûr est
tf getpuisgit add -A && git commit(« ce que TFVC m'a livré »), puis le travail, puis check-in.
| Critère | Note /5 | Justification |
|---|---|---|
| Gain de confort quotidien | 4/5 | Commits locaux, stash, bisect |
| Risque de divergence entre les deux | 3/5 | Dépend de la discipline |
| Valeur pour une migration future | 4/5 | Historique Git fin déjà disponible, mais local |
| Sauvegarde | 2/5 | L'historique Git local n'existe qu'à un endroit : sauvegarde du poste ou dépôt miroir interne |
Le dépôt Git local sans remote n'est sauvegardé nulle part : perte du disque = perte des commits fins. Remède : git bundle régulier ou miroir vers un dépôt interne privé (hors TFS) ; ou simplement archiver le dossier .git.
Un correctif sur une procédure de consolidation : trois commits Git locaux (« correction jointure », « ajout contrôle », « test partiel ») puis un changeset TFVC lié à la tâche : « Correctif consolidation couverture ». L'audit voit un changeset net ; le développeur garde la granularité fine pour bisect si la régression revient.
Plan de migration par étapes#
🔴 Niveau expert
Plan type pour une équipe de 10-20 personnes, sur 6 à 12 semaines (ordre de grandeur, dépend de la taille et de la préparation) :
1. Cadrer (1 semaine) — Décider : migrer quoi (Main seule ? + releases ?), avec quel historique, pour quels bénéfices mesurables. Inventaire : taille de la collection, fichiers volumineux, branches vivantes, policies, builds, liens work items. Sponsor identifié.
2. Préparer (2-3 semaines) — Nettoyer le dépôt (binaires, caches, doublons). Normaliser encodages et fins de ligne. Rédiger .gitattributes, .gitignore, conventions de branches et de messages, politiques de branche (PR, build de validation). Établir la table des auteurs. Sécuriser les droits (groupes, dépôts découpés si droits par dossier).
3. Pilote (2 semaines) — Migrer un périmètre non critique (ou une copie du réel) avec l'outil retenu ; comparer le contenu au changeset de référence (liste de fichiers + sommes de contrôle) pour prouver la fidélité ; rejouer une livraison complète (kit installable) depuis le dépôt Git ; mesurer clone, status, build.
4. Former (en continu) — 1 session pratique de 3 h : modèle objet simplifié, cycle quotidien, PR, résolution de conflits ; fiche aide-mémoire TFVC→Git (équivalences) ; « champion Git » par équipe.
5. Basculer (1 week-end ou 1 journée calme) — Geler TFVC (droits en lecture seule), migration finale, vérification (fichiers, tags, quelques fichiers sensibles ouverts à la main), mise à jour des pipelines, hooks, documentation, liens. Communication claire : « à partir de lundi, on commit ici ».
6. Consolider (4 semaines) — Support rapproché, rétrospective, métriques (conflits, durée de revue, lead time), suppression des anciens workspaces, archivage TFVC (lecture seule, conservé).
Critères de réussite : toutes les versions produit en cours reconstructibles depuis Git ; pipeline de build vert ; plus personne ne commit en TFVC ; équipe autonome sur les opérations courantes.
Prévoyez un retour arrière : tant que TFVC n'est pas figé, la migration est réversible ; après le gel, gardez la source TFVC intacte 3 à 6 mois.
Pièges de migration#
🔴 Niveau expert
| Piège | Symptôme | Cause | Remède |
|---|---|---|---|
| Normalisation tardive | Premier commit Git « modifie tout » | Encodage/fins de ligne non unifiés | Normaliser avant, ou isoler dans un commit dédié |
| Accents corrompus | « é » dans libellés | Fichiers UTF-8 relus en ANSI, ou BOM perdu | Contrôle automatisé des octets ; voir 06 |
| Historique « fantôme » | Ajouts/suppressions bizarres | Branche par copie dans TFVC | Migrer à partir d'un point propre |
| Casse des chemins | Doublons sous Linux | TFVC insensible à la casse | Détecter les collisions avant |
| Liens work items morts | Pas de changeset dans la tâche | Numéros TFVC perdus | Garder les numéros dans les messages |
| Gros binaires oubliés | Clone de plusieurs Go | Historique complet importé | LFS, filtres, ou tip |
| Équipe en mode « TFVC dans Git » | Force-push, commits géants | Pas de formation | Protections de branche + formation |
| Pipelines non adaptés | Builds cassés | Déclencheurs TFVC | Réécrire en YAML, tester sur branche |
| Droits par dossier perdus | Sous-traitant voit tout | Git ne les gère pas | Dépôts séparés |
| Oubli des scripts internes | Outil d'archivage appelle tf |
Dépendances cachées | Inventaire des scripts (PowerShell, hooks, builds) |
Contribution de l'IA#
Utile à plusieurs étapes d'une migration, dangereuse si on délègue le jugement.
| Cas d'usage | Gain | Risque | Maturité | Prérequis | Garde-fous |
|---|---|---|---|---|---|
Générer la table de correspondance auteurs depuis tf history |
3/5 | 2/5 | 4/5 | Export tf history |
Validation RH/propriétaire |
| Écrire les scripts de conversion/contrôle (comparaison arborescences, sommes) | 4/5 | 3/5 | 4/5 | Spécification claire | Pilote sur copie, comparaison systématique |
Rédiger .gitattributes / .gitignore |
4/5 | 2/5 | 4/5 | Liste des types de fichiers | Tester sur échantillon (accents, CRLF) |
| Générer la fiche TFVC→Git et le support de formation | 4/5 | 1/5 | 4/5 | Contexte d'équipe | Relecture technique |
| Expliquer un historique converti, détecter des anomalies | 3/5 | 3/5 | 3/5 | Extraits ciblés | Ne pas conclure sans vérification dans l'outil |
| Revue de code assistée après bascule | 3/5 | 3/5 | 3/5 | Politiques de PR | L'humain reste le relecteur responsable |
Prompt type : « Voici un extrait de tf history détaillé. Produis un CSV compte_tfs;nom;email sans inventer d'adresse : laisse vide si inconnue. » L'IA ne remplace ni la décision de migrer, ni la vérification de fidélité (sommes de contrôle), ni la responsabilité sur la conformité de l'archive. Voir IA et outils.
Voir aussi#
- Panorama · Git · TFVC · Stratégies de branches · SQL et BI
- Azure DevOps / TFS en profondeur · Comparatif d'outils
- Matrice : gestion de version et branches
- CI/CD pour la data · Glossaire
✻ Rédigé par Claude Sonnet 5.5