clement13.net
Photo d’origine : Livre de comptes ancien ouvert, aux colonnes tracées à la main et aux écritures manuscrites.
Description
Livre de comptes ancien ouvert, aux colonnes tracées à la main et aux écritures manuscrites.
Source
Daderot · page d’origine
Licence
CC0 Domaine public
Photo d’origine, non retouchée. L’arrière-plan en est une version stylisée par le site.

TFVC en profondeur

Comprendre le modèle de Team Foundation Version Control : serveur central, workspaces, changesets numérotés.

Guide≈ 15 min de lectureVérifié en partieContrôle partielLes faits principaux ont été contrôlés par recherche dans des sources citées. Les éléments ci-dessous restent à recontrôler avant de s’y fier.À recontrôler
  • Numéros d'erreur TF203069, TF14061, TF10121 : comportements cohérents avec la documentation, mais numéros non retrouvés dans une source Microsoft.
  • Calendrier exact de la phase finale de blocage des check-in policies obsolètes (blog du 18 février 2026 : aucune date ; notes de version sprint 268 : politiques obsolètes désactivées) : à revérifier avant citation.
  • Notion « Modern Lifecycle » (champ fresh et section pérennité) : non retrouvée dans une source Microsoft.
Rédaction assistée par IA ; sources citées en bas de page. Une erreur ? Signalez-la via le site clement13.net.
Lecture
En bref
  • Comprendre le modèle de Team Foundation Version Control : serveur central, workspaces, changesets numérotés.
  • Maîtriser les objets : shelvesets, labels, branches, merges, check-in policies, gated check-in.
  • Utiliser tf.exe en ligne de commande avec assurance (get, add, checkout, checkin, undo, delete, history, merge, branch, status, workfold) et connaître les pièges (TF203069 et consorts).
  • Connaître les limites, la performance, les droits, et l'état de pérennité de TFVC (état 2026-10).
Sur cette page

Niveau : 🟢→🔴

Principes#

🟢 Niveau novice

TFVC est une GDS centralisée : le serveur (collection de projets d'Azure DevOps Server ou organisation Azure DevOps Services) détient l'historique. Chaque enregistrement est un changeset, numéroté séquentiellement pour toute la collection (changeset 45815, par exemple). Le poste ne contient que les fichiers demandés (get) dans un workspace : un lien nom de dossier serveur ↔ dossier local.

Cycle de base :

  1. Get : récupérer la dernière version.
  2. Checkout (édition) : signaler qu'on modifie (explicite en workspace serveur, implicite en workspace local).
  3. Modifier les fichiers.
  4. Check-in : valider ; crée un changeset atomique, avec commentaire et work items associés.

Trois atouts : numéros de changeset lisibles, droits fins par dossier, et intégration native Visual Studio/work items. Trois limites : dépendance au serveur, branches lourdes en concept (une branche est un dossier), outils de revue et de CI plus pauvres que sur Git.

Workspaces serveur et locaux#

🟡 Niveau pratique

Aspect Workspace serveur Workspace local (défaut moderne)
Où l'état est connu Serveur : il sait quels fichiers vous avez Poste : comparaison locale à la demande
Fichiers en lecture seule Oui, jusqu'au checkout Non : fichiers modifiables, modifications détectées par comparaison avec la copie en cache
Hors ligne Limité : mode « hors connexion » de Visual Studio, à repasser en ligne ensuite Possible : tf reconcile ensuite
Performance pour très gros dépôts (millions de fichiers) Meilleure Se dégrade vers 100 000 éléments (analyse du disque, copies multiples)
Verrouillage lock:checkout possible Pas de checkout verrouillant à l'édition

Choix : un workspace local convient à la plupart des équipes ; le serveur reste pertinent sur des arborescences gigantesques ou pour imposer le verrouillage. Les workspaces sont par machine et par utilisateur (nom du poste + propriétaire).

tf workspace /new MonWS /collection:https://tfs.exemple.local/tfs/Collection /login:... /noprompt
tf workfold /map $/Projet/Main D:\TFS\Main /workspace:MonWS
tf workspaces                      # liste
tf workspace /delete MonWS;ProprioXX
⚠️ Piège

Un workspace est mappé à un chemin local ; un dossier local ne peut dépendre que d'un workspace. Symptôme : « The path is already mapped in workspace… » (TF400... / TF203...). Remède : tf workspaces, supprimer ou démapper l'ancien (tf workfold /unmap).

Changesets#

🟢 Niveau novice

Un changeset est l'ensemble atomique : fichiers ajoutés/modifiés/supprimés/renommés/fusionnés, commentaire, work items liés, résultats des policies. Il est immuable (le commentaire peut être modifié après coup, pas le contenu). Particularités :

  • Numéro global croissant dans la collection : repère naturel pour dater et dire « ce correctif est dans le CS 45643 ».
  • Versionnage des renommages et suppressions : TFVC enregistre explicitement les opérations ; l'historique suit un fichier déplacé.
  • Spécificateurs de version : C45643 (changeset), D2026-09-16 (date), L<label> (label), T (dernière), W (workspace).

Un changeset peut être rattaché à plusieurs work items ; chacun conserve alors un lien vers le même changeset.

💡 Astuce d'expert

Dans un compte rendu de livraison, citez les changesets avec un texte explicite (« CS 45643 – correctif PREBUILD ») : un lien brut est opaque, et c'est ce numéro qui relie code, work item, build et kit.

Shelvesets#

🟡 Niveau pratique

Un shelveset met de côté des modifications sur le serveur, nommées, sans les valider. Usages : sauvegarde intermédiaire, partage pour revue, changement de contexte, build d'essai (builds « shelveset »).

tf shelve MonShelveset /comment:"WIP KPI" /noprompt
tf shelvesets /owner:*                 # lister
tf unshelve MonShelveset;Proprio       # restaurer dans le workspace
tf shelve /delete MonShelveset

Différences avec git stash : un shelveset est nommé, serveur, partageable, visible dans les outils, quand le stash est local et anonyme. Il ne porte pas de graphe de fusion : c'est un instantané de modifications.

⚠️ Piège

Un shelveset n'est pas sauvegardé par le workspace : il l'est avec la base de collection. Mais il s'accumule ; sans politique de nettoyage (suppression des vieux), la base grossit. Les shelvesets contenant des secrets sont lisibles par ceux qui ont le droit de lecture.

Labels#

🟡 Niveau pratique

Un label nomme un ensemble de versions de fichiers (pas forcément cohérent : on peut mélanger des versions). Il sert à marquer une livraison, mais il est mutable : on peut déplacer, ajouter, retirer des éléments d'un label (et à moins de droits adaptés, le supprimer). Contraste avec le tag Git, qui est un pointeur vers un commit atomique.

tf label Livraison_9.1.0 $/Projet/Releases/9.1 /recursive /comment:"Kit 9.1.0"
tf labels /collection:... 
tf label /delete Livraison_9.1.0@$/Projet
✅ Bonne pratique

Pour une livraison, privilégiez le numéro de changeset (immuable) + une branche de release dédiée, plutôt que le label seul. Si vous utilisez un label, notez dans la documentation de livraison le changeset correspondant.

Branches et fusions#

🟡 Niveau pratique

En TFVC, une branche est un dossier serveur déclaré « branche » (objet versionné) : $/Projet/Main → $/Projet/Dev, $/Projet/Releases/9.1. Créer une branche copie logiquement l'arborescence (côté serveur, coûteux seulement en métadonnées). La relation parent/enfant est enregistrée : les fusions ne sont autorisées par défaut que selon cette relation (aval/amont).

tf branch $/Projet/Main $/Projet/Dev /collection:... /comment:"Branche de dev"
tf merge $/Projet/Main $/Projet/Dev /recursive                   # Main -> Dev (réintégration descendante)
tf merge $/Projet/Dev $/Projet/Main /recursive /version:C45000~C45600  # sélectif par plage de changesets
tf checkin /comment:"Merge Main vers Dev" /noprompt
tf resolve /auto:AutoMerge                                       # résolution automatique
tf resolve fichier /auto:TakeTheirs                              # TakeTheirs / KeepYours
tf merges $/Projet/Main $/Projet/Dev /recursive                  # ce qui reste à fusionner
tf history $/Projet/Dev /recursive /format:brief

Le serveur calcule la fusion de deux versions avec leur base commune (en suivant la relation de branche). Les fusions TFVC suivent les changesets : on peut fusionner seulement le changeset 45643, ce qui est puissant (rétro-portage chirurgical) et dangereux (ordre incohérent des changesets partiellement fusionnés).

Fusion sans base (baseless merge) : fusionner entre deux dossiers sans relation de branche déclarée (typiquement un dossier copié plutôt que branché). Option /baseless : sans ancêtre, tout est un conflit potentiel car l'outil n'a pas de base de comparaison. À réserver aux cas d'import ou de reconstruction.

Structure classique (standard Main/Dev/Release) :

$/Projet
 ├─ Main                  (code stable, intégration)
 ├─ Dev
 │   ├─ Feature-A         (branches de fonctionnalité)
 │   └─ Feature-B
 └─ Releases
     ├─ 9.0               (branches de release / maintenance)
     └─ 9.1

Règle de flux : les fusions vont de l'enfant au parent (reverse integration) et du parent à l'enfant (forward integration) ; on ne fusionne pas « latéralement » (Release 9.0 → Release 9.1) sauf par Main, sauf baseless. Voir la mise en perspective dans 05.

⚠️ Piège

Une branche par copie de dossier (clic droit « copier » et non « Branch ») donne un dossier sans historique de branche : les fusions suivantes seront baseless. Symptôme : tout est conflit. Remède : convertir en branche (Convert to Branch) tant qu'il n'y a pas eu de divergence, ou recréer proprement.

Politiques de check-in et gated check-in#

🔴 Niveau expert

Check-in policies : règles évaluées côté client au moment du check-in (Visual Studio) : association obligatoire à un work item, commentaire non vide, build propre, analyse de code, notes de check-in. Elles s'activent par projet d'équipe. Limite structurelle : elles s'exécutent chez le client, donc contournables (/override avec justification journalisée).

Gated check-in : le check-in n'est accepté que si un build validant le changement passe. Le serveur crée un shelveset, lance la build, et ne committe qu'en cas de succès. Utile sur un tronc partagé : garantit que Main compile. Coût : latence, file d'attente de builds, contention.

Évolution récente : Microsoft a annoncé en avril 2025 la dépréciation des anciennes check-in policies (stockage et implémentation historiques). Le calendrier prévoit des phases de notification puis un blocage : à l'étape finale, des policies obsolètes non migrées peuvent bloquer tous les check-ins du dépôt. En février 2026, le billet de l'équipe Azure DevOps indiquait la phase II avec appel à retirer ou remplacer les policies obsolètes. À faire : auditer les policies de chaque projet TFVC, supprimer les obsolètes, recréer celles utiles au nouveau format (état 2026-10 ; détail et dates à vérifier sur le blog Azure DevOps).

⚠️ Piège

Symptôme : message de non-conformité des policies à chaque check-in, invisible dans tf.exe. Cause : policies obsolètes stockées sur le serveur. Remède : les retirer via Team Explorer ou l'interface d'administration du projet avant la phase finale de blocage.

tf.exe en ligne de commande#

🟡 Niveau pratique

tf.exe est livré avec Visual Studio (Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\TF.exe). Il fonctionne en authentification intégrée Windows ou avec /login:. Dans un dossier mappé, la collection est déduite du workspace.

Commande Rôle Exemple
tf get Récupérer des versions tf get $/Projet/Main /recursive ; /force pour re-télécharger ; /version:C45643 ; /preview simule
tf add Ajouter à la source tf add *.sql /recursive ; /noprompt ; /exclude n'existe pas : passer par .tfignore
tf checkout (tf edit) Marquer pour modification tf checkout script.sql ; /lock:none
tf checkin Valider tf checkin /comment:"Message" /associate:12345 /noprompt ; /override:"raison"
tf undo Annuler des modifications en attente tf undo /recursive * ; tf undo /workspace:MonWS;Proprio * (annule dans un autre workspace)
tf delete Supprimer tf delete fichier.sql ; /recursive ; /lock:none
tf rename / tf move Renommer/déplacer tf rename ancien.sql nouveau.sql
tf status Modifications en attente tf status /recursive /format:detailed
tf history Historique tf history $/Projet/Main/dossier /recursive /stopafter:20 /format:detailed
tf diff Comparer tf diff fichier.sql /version:C45000~T
tf changeset Détails d'un changeset tf changeset 45643 /noprompt
tf branch / tf merge / tf merges Branches, fusions voir plus haut
tf workfold Mappings du workspace tf workfold ; /map ; /unmap
tf workspace / tf workspaces Gérer les workspaces /new, /delete
tf shelve / tf unshelve Shelvesets voir plus haut
tf label Labels voir plus haut
tf reconcile Rapprocher modifications hors ligne tf reconcile /promote /recursive
tf rollback Annuler un changeset tf rollback /changeset:45643 /recursive
tf destroy Détruire définitivement tf destroy $/Projet/.../x (irréversible, droits admin)

Recette de travail typique en ligne de commande :

Set-Location D:\TFS
tf get . /recursive                       # synchroniser
tf status . /recursive                    # contrôle avant travail
# ... modifications ...
tf add "Datamart\nouveau script.sql"      # nouveaux fichiers
tf checkin . /recursive /comment:"Correctif KPI couverture" /associate:12345 /noprompt
💡 Astuce d'expert

Dans un script d'archivage, lisez le code de sortie : 0 succès, 1 succès partiel, 2 commande non reconnue, 100 aucun succès. Un tf checkin qui n'a « rien à valider » peut renvoyer un code non nul sans que ce soit une erreur : testez d'abord tf status. Protégez les chemins contenant des espaces par des guillemets.

⚠️ Piège

tf add applique les règles de .tfignore quand l'argument contient un caractère générique (/noignore les outrepasse), mais tf add . /recursive sur un dossier contenant bin/, obj/ et des caches non ignorés ajoutera du bruit. Vérifiez tf status avant checkin : c'est la dernière barrière.

🧪 Exemple

Retrouver qui a modifié un script de consolidation depuis la dernière livraison : tf history "$/Projet/Main/Datamart/script.sql" /version:C45000~T /format:detailed. Pour des audits en masse, tf history ... /format:detailed /noprompt redirigé dans un fichier, puis analyse PowerShell.

Exclusions .tfignore#

🟡 Niveau pratique

.tfignore est le pendant TFVC de .gitignore : un fichier texte à la racine d'un dossier mappé, pris en compte par tf add et par Visual Studio (le détecteur de changements ne propose plus les fichiers ignorés). Syntaxe voisine mais séparateur \ et chemin commençant par \ = relatif au dossier du .tfignore ; ! pour réintégrer.

# Exclusions
*.user
*.suo
\bin
\obj
\node_modules
!\bin\keep.dll          # exception : forcer l'ajout

Règles à connaître :

  • .tfignore est sans effet sur un élément déjà sous contrôle de source. Pour sortir un fichier du contrôle : tf delete (puis check-in), le fichier reste sur disque si on l'a supprimé de la version seulement via workspace local ; attention, tf delete supprime aussi localement par défaut.
  • Si une modification est déjà en attente sur l'élément, faire d'abord tf undo, sinon TF203069 (voir pièges).
  • tf delete refuse un élément jamais rapatrié dans le workspace (« introuvable dans votre espace de travail ») : faire d'abord un tf get de l'élément.
  • Le .tfignore doit être lui-même versionné pour que toute l'équipe ait les mêmes exclusions ; sur un dépôt qui est aussi suivi par Git en local, conservez deux listes alignées (.gitignore et .tfignore).

Intégration des work items#

🟡 Niveau pratique

TFVC relie nativement changesets et work items : à l'enregistrement, /associate:<id> (ou le panneau Visual Studio) crée le lien Changeset sur le work item, et la résolution éventuelle (/resolve:) peut changer son état. Bénéfices : de la tâche on retrouve le code (et inversement), les builds remontent les changesets inclus, et l'audit de livraison se fait par requête. Avec les branches, l'onglet « Développement » montre la propagation d'un changeset entre branches.

✅ Bonne pratique

Imposez la policy « work item associé » : sans cela, la traçabilité se perd en quelques semaines. Un changeset peut porter plusieurs tâches, mais évitez le fourre-tout : un changeset par sujet (voir aussi Azure DevOps / TFS en profondeur).

Droits et sécurité#

🔴 Niveau expert

Les permissions TFVC se définissent par chemin serveur (héritage, refus explicite) : Lecture, Check-out, Check-in, Étiquetage, Fusion, Gestion des branches, Verrouillage, Gestion des permissions, gestion des étiquettes, révision des modifications d'autrui… Cette granularité est supérieure à Git (qui se règle au dépôt). Cas d'usage : un sous-traitant ne voit que $/Projet/Releases/9.1/Docs, la production peut seulement lire Releases.

Principes : droits par groupes et non par individus ; refus explicite à réserver aux exceptions (un refus l'emporte) ; auditer périodiquement avec tf permission /collection:... $/Projet /recursive.

Performance et limites#

🔴 Niveau expert

  • Points forts : bonne tenue sur très gros arbres (nombreux fichiers), chargement partiel naturel (seulement les dossiers mappés), binaires volumineux gérés sans extension.
  • Points faibles : status lent en workspace local sur des centaines de milliers de fichiers ; opérations de fusion lourdes sur de grosses arborescences ; dépendance du réseau/serveur ; une base de collection qui grossit avec les shelvesets et les binaires.
  • Limites : chemins locaux limités par Windows (260 caractères) ; revue de code moins riche (demandes de revue de code Visual Studio, sans équivalent des politiques de PR) ; hors-ligne limité (espace de travail local et tf reconcile), sans historique sur le poste.
  • Atténuations : mapping minimal (workfold), dossiers racine courts, nettoyage régulier des shelvesets/workspaces inactifs, supervision de la taille de la base de collection.

Notes /5 de TFVC (contexte : équipe de 5 à 30 développeurs, Azure DevOps Server sur site, projet mixte SQL/BI/scripts) :

Critère Note Justification
Courbe d'apprentissage 4/5 Modèle proche de SVN, Visual Studio guide
Performance sur gros dépôts 4/5 Mapping partiel, très gros arbres corrects
Branches / fusions 3/5 Fonctionnelles, rigides, baseless pénibles
Traçabilité / audit 4/5 Changesets numérotés, work items
Granularité des droits 5/5 Par chemin, héritage/refus
Fichiers binaires / volumineux 4/5 Pas de contournement requis
Intégration CI/CD 3/5 Builds OK, mais l'écosystème moderne cible Git
Adéquation SQL/BI 3/5 Diffs textes OK ; PBIP/TMDL sans revue par PR
Pérennité de l'écosystème 2/5 Maintenu mais « feature complete » (voir ci-dessous)

Pièges et codes d'erreur#

🔴 Niveau expert

Code / symptôme Cause Remède
TF203069 — modification en attente sur l'élément Tentative de delete/rename/add alors qu'une modification est déjà en attente tf undo de l'élément, puis refaire l'opération
« introuvable dans votre espace de travail » (tf delete) Élément jamais rapatrié localement tf get de l'élément, puis tf delete
TF14061 — workspace introuvable Workspace supprimé ou propriétaire différent tf workspaces /computer:*, recréer ou mapper
TF10121 — chemin invalide Chemin serveur mal écrit ($/ manquant) Vérifier par tf dir $/
TF400xxx — conflit de version Fichier modifié par un autre depuis votre get tf get puis tf resolve
Conflits massifs après copie de dossier Fusion baseless Reconstruire la branche proprement
Check-in qui échoue sur policies Policies obsolètes (2025-26) Les migrer, voir section policies
tf checkin « rien à valider » Modifications non détectées (workspace local, fichier en lecture seule) tf reconcile, vérifier tf status
Fichiers « fantômes » à l'ajout Pas de .tfignore Ajouter .tfignore avant le premier add
Mojibake sur les accents Fichiers sans BOM lus en ANSI, ou inverse Voir 06
⚠️ Piège

Les messages TFxxxxxx varient selon les versions : consultez le texte complet et l'aide Microsoft correspondante plutôt que de vous fier au seul code. Je n'ai pas vérifié chaque numéro pour toutes les versions : la section est une orientation, à confirmer en cas de doute.

Pérennité et état du produit#

🔴 Niveau expert

État vérifié par recherche (sources : documentation Microsoft Learn « Choosing the right version control for your project », billets de la feuille de route Azure DevOps, blog Azure DevOps) :

  • Git est le contrôle de version par défaut pour les nouveaux projets Azure DevOps ; Microsoft recommande Git et d'envisager la migration des projets TFVC existants.
  • TFVC est « feature complete » : Microsoft maintient la compatibilité (il reste supporté dans Azure DevOps et dans Azure DevOps Server), mais tout investissement futur va à Git. Pas de fonctionnalité nouvelle attendue.
  • La feuille de route annonçait une suppression progressive de TFVC pour les nouveaux projets et organisations sans usage existant, avec un paramètre permettant de désactiver la création de dépôts TFVC. Les dépôts TFVC existants restent utilisables.
  • Les check-in policies historiques sont en cours de dépréciation (calendrier 2025-2026, voir plus haut).
  • Visual Studio : l'intégration TFVC est maintenue mais l'effort porte sur Git.
  • À vérifier à chaque montée de version : la version d'Azure DevOps Server installée et ses notes de version ; la politique de support (modèle « Modern Lifecycle ») ; toute annonce de fin de création de dépôts TFVC pour votre collection.

Lecture d'expert : TFVC n'est pas retiré ; il est gelé. Une organisation qui l'utilise en production n'a pas d'urgence technique, mais a un risque stratégique : dette de compétence, absence d'innovation (pas de pull requests, pas d'IA de revue native comparables à Git), et risque que les outils tiers abandonnent le support. L'échéance réaliste de migration se décide par les besoins métier (revues, CI, recrutement), pas par une date imposée. La démarche est détaillée dans 04.

Contribution de l'IA#

🤖 IA

Avec TFVC, l'apport de l'IA est réel mais plus pauvre qu'avec Git.

Cas d'usage Gain Risque Maturité Garde-fous
Écrire/expliquer une commande tf.exe ou un script PowerShell d'archivage 4/5 3/5 3/5 Tester avec /preview, relire les chemins
Analyser un export tf history pour un audit 4/5 2/5 4/5 Contrôler les chiffres par un recompte
Rédiger commentaires de check-in 3/5 2/5 4/5 Rattacher un work item réel
Assistants dans Visual Studio (Copilot) pour code et messages 3/5 2/5 3/5 Les fonctions IA de PR/revue ciblent surtout Git
Expliquer un code d'erreur TFxxxxxx 3/5 4/5 2/5 L'IA hallucine volontiers les numéros : vérifier sur la doc Microsoft

L'IA ne remplace pas la connaissance du modèle serveur (workspaces, mappings) ni la décision d'archiver. Voir IA et outils.

Voir aussi#

✻ Rédigé par Claude Sonnet 5.5