4.1 Version Control Architecture: TFVC vs Git in F&O
Key Takeaways
- Dynamics 365 Finance and Operations historically defaults to Team Foundation Version Control (TFVC) as a centralized repository with server-mapped workspaces, while Git provides a distributed repository model increasingly utilized in modern containerized development and the Unified Developer Experience (UDE).
- Workspace mapping rules strictly mandate mapping the source control metadata directory ($/Project/Trunk/Main/Metadata) directly to the local PackagesLocalDirectory on the developer VM, while mapping the projects directory ($/Project/Trunk/Main/Projects) to the local Visual Studio projects folder.
- Version control repositories in F&O track only declarative source assets: model descriptor XML files (Descriptor/ModelName.xml) and element XML files, while strictly excluding binary outputs, intermediate reflection metadata, and personal user settings.
- Exclusion files (.tfignore for TFVC or .gitignore for Git) must explicitly ignore binary assemblies (bin/, *.dll, *.pdb), intermediate compilation artifacts (XppMetadata/), resource caches, and user-specific project files (*.rnrproj.user, *.csproj.user) to prevent repository corruption.
- Enterprise check-in governance enforces linking commits to Azure Boards work items for traceability, establishing code review policies, and requiring automated gated check-in builds before code changes are committed to protected branches.
4.1 Version Control Architecture: TFVC vs Git in F&O
Quick Answer: Dynamics 365 Finance and Operations (F&O) supports two primary version control architectures: Team Foundation Version Control (TFVC) (a centralized system where developers map server folders directly to local disks) and Git (a distributed system where every developer possesses a complete local clone of the repository). For traditional Tier 1 Cloud-Hosted Environments (CHEs) and developer Virtual Machines (VMs), Microsoft's standard architecture relies on TFVC with a strict workspace mapping: the server folder
$/Project/Trunk/Main/Metadatamaps directly to the local application metadata folder (PackagesLocalDirectory, located onC:\AOSService\PackagesLocalDirectoryorK:\AosService\PackagesLocalDirectory), while$/Project/Trunk/Main/Projectsmaps to the local Visual Studio solution path. Repositories must track only declarative XML source elements and Model Descriptor files ([ModelName]/Descriptor/[ModelName].xml). Binary outputs (bin/,*.dll,*.pdb), intermediate generated code (XppMetadata/), and personal user settings (*.rnrproj.user,.vs/) must be explicitly excluded via.tfignoreor.gitignore.
1. Centralized TFVC vs. Distributed Git Architecture
Choosing and managing the version control system is a fundamental architectural decision in Dynamics 365 F&O implementations. While modern software engineering broadly embraces Git, Dynamics 365 F&O has deep architectural roots in TFVC, and both systems are heavily tested on the MB-500 exam.
Architectural Comparison: TFVC vs. Git
| Architectural Attribute | Team Foundation Version Control (TFVC) | Distributed Git Version Control |
|---|---|---|
| Topology | Centralized: A single centralized Azure DevOps server repository holds all revisions and branch histories. | Distributed: Every developer maintains a full local clone containing the entire commit history and all branches. |
| Workspace Model | Uses server-path or local-path workspace mappings that bind specific server paths directly to absolute local file system paths. | Clones the entire repository into a root directory; developers switch branches locally without changing workspace mappings. |
| Metadata Integration | Deep, native integration with the Visual Studio Application Explorer and Dynamics 365 menu tools. | Fully supported in modern Visual Studio and Unified Developer Experience (UDE); requires local branch hygiene. |
| Branching & Switching | Heavyweight: Branches exist as physical server directory trees (e.g., /Main, /Dev). Switching branches requires separate folder mappings. | Lightweight: Branches are discrete 41-byte pointer references to commits. Switching branches swaps files in-place within the working tree. |
| File Locking & Checkout | Supports pessimistic locking (check-out locks preventing others from editing) and server workspaces. | Strictly optimistic concurrency; no native file locking on standard repositories. All conflicts resolve post-commit at merge/pull. |
| Offline Work | Limited in server workspaces; local workspaces support offline edits but require server reconnection for check-in. | Full offline capability: developers can commit, branch, view log history, and diff revisions completely offline. |
| Target Environment | Traditional Tier 1 Cloud-Hosted Environments (CHEs) and downloaded VHDs. | Cloud-hosted VMs, local development, containerized builds, and Unified Developer Experience (UDE) in Power Platform. |
TFVC Workspace Types: Local vs. Server Workspaces
When configuring a TFVC workspace on a development VM, developers must choose between two workspace modes:
- Local Workspaces (Recommended Default):
- Visual Studio automatically detects file modifications, additions, and deletions outside the IDE using a client-side scanner.
- Files on disk are not marked read-only.
- Developers can edit code while disconnected from Azure DevOps; changes are queued and presented upon reconnecting.
- Ideal for standard development where workspace size does not exceed tens of thousands of files.
- Server Workspaces:
- All unedited files on disk have the Windows read-only attribute set.
- Visual Studio explicitly removes the read-only attribute only when a file is checked out via an active network call to Azure DevOps.
- Required when managing extremely massive repositories with hundreds of thousands of files where local scanning introduces disk I/O latency, or when teams mandate strict checkout locks to prevent concurrent modifications of binary resources.
2. Workspace Mapping Architecture & Rules
In Dynamics 365 F&O, the Application Object Server (AOS) runtime, the X++ compiler (xppc.exe), and the Visual Studio Application Explorer operate directly against a physical directory known as PackagesLocalDirectory. If files are checked out to an arbitrary folder on the dev machine, the F&O tooling cannot locate, build, or debug them.
The Golden Repository Structure
A standard Dynamics 365 F&O version control repository is organized into a clean folder hierarchy under a designated trunk or branch:
$/ContosoFinance/Trunk/Main/
├── Metadata/ <-- Contains all custom models, extensions, and descriptor files
│ ├── ContosoSuite/ <-- Custom Package (Module)
│ │ ├── ContosoSuite/ <-- Custom Model within the Package
│ │ │ ├── AxClass/ <-- X++ source class XML files
│ │ │ ├── AxTable/ <-- Table definition XML files
│ │ │ ├── AxForm/ <-- Form definition XML files
│ │ │ └── Descriptor/ <-- Model descriptor file (AxModelInfo / ContosoSuite.xml)
│ └── ApplicationSuite/ <-- Extended Microsoft Package (Extensions only)
│ └── ContosoAppSuiteExt/ <-- Custom Model extending standard ApplicationSuite
└── Projects/ <-- Contains Visual Studio Solution (.sln) and Project (.rnrproj) files
├── ContosoSuite.sln
└── ContosoSuite/
└── ContosoSuite.rnrproj
Strict Mapping Rules
To establish a working development environment, the developer must open the Source Control Explorer in Visual Studio and define exactly two distinct workspace folder mappings:
- Metadata Mapping (Absolute Requirement):
- Server Path:
$/ContosoFinance/Trunk/Main/Metadata - Local Path:
C:\AOSService\PackagesLocalDirectory(orK:\AosService\PackagesLocalDirectorydepending on the VM drive configuration) - Why? When you invoke Get Latest Version, Azure DevOps downloads the custom model packages directly into the active AOS package folder. Visual Studio immediately recognizes the models, displays them in Application Explorer, and compiles them into the runtime environment.
- Server Path:
- Projects Mapping:
- Server Path:
$/ContosoFinance/Trunk/Main/Projects - Local Path:
C:\Users\Administrator\Documents\Visual Studio 2019\Projects(orC:\Dynamics365\Projects) - Why? Visual Studio solutions (
.sln) and Finance and Operations projects (.rnrproj) must never be mapped insidePackagesLocalDirectory. Storing project files inside the metadata folder causes compiler errors, clutters model folders, and violates package isolation boundaries.
- Server Path:
[!IMPORTANT] Critical Mapping Rule: Never map the root folder
$/ContosoFinance/Trunk/Maindirectly toPackagesLocalDirectory. Doing so forces theProjects/folder and root configuration files to reside inside the AOS package store, which corrupts package discovery and triggers severe compilation diagnostics.
3. Tracking Metadata: Model Descriptors vs. Element XML Files
Dynamics 365 F&O is an entirely declarative, metadata-driven architecture. Every element—whether a table, class, data entity, or form extension—is stored as an individual, human-readable XML file on disk. Version control must track these source XML files while respecting the distinction between packages, models, and descriptors.
Packages vs. Models on Disk
- Package (Module): An independent deployment and compilation unit. A package compiles into a single .NET assembly (
.dll). Examples includeApplicationPlatform,ApplicationSuite, or a custom package likeContosoCustomizations. - Model: A design-time subdivision of a package. A package can contain one or multiple models. Each model contains its own elements and business logic, but all models inside a single package compile together into that package's single assembly DLL.
Model Descriptor Files
Every model within a package must have a corresponding Model Descriptor file located inside the Descriptor directory: PackagesLocalDirectory\<PackageName>\<ModelName>\Descriptor\<ModelName>.xml.
The model descriptor XML contains critical configuration attributes:
- Model Name and Display Name: Unique identifier of the model.
- Publisher: Authoring organization (e.g., Contoso Corp or ISV Partner).
- Layer: Application layer (e.g.,
isv,var,cus,usr). - Version: Three-part semantic version string (e.g.,
1.0.0.0). - Module References (Dependencies): The list of other packages that this model depends on (e.g.,
ApplicationFoundation,ApplicationSuite,Directory).
<?xml version="1.0" encoding="utf-8"?>
<AxModelInfo xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Name>ContosoSuite</Name>
<Publisher>Contoso Enterprises</Publisher>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<VersionBuild>0</VersionBuild>
<VersionRevision>0</VersionRevision>
<Layer>cus</Layer>
<ModuleReferences>
<string>ApplicationFoundation</string>
<string>ApplicationPlatform</string>
<string>ApplicationSuite</string>
</ModuleReferences>
</AxModelInfo>
[!WARNING] The Missing Descriptor Trap: If a developer creates a new model in Visual Studio and checks in the element files (such as tables and classes) but forgets to check in the
Descriptor/<ModelName>.xmlfile, other developers who get latest will encounter severe compiler errors. Their Visual Studio Application Explorer will not recognize the folder as an active model, and the automated build pipeline will fail with missing assembly reference errors.
4. Exclusion Rules: .tfignore and .gitignore Architecture
A critical responsibility of the F&O developer is ensuring that transient, intermediate, and compiled binary files are never committed to version control. Checking in compiled binaries or user-specific files bloats the repository, causes merge collisions, locks files during team builds, and breaks continuous integration pipelines.
Files and Folders That MUST Be Excluded
- Compiled Binary Outputs (
bin/,*.dll,*.pdb,*.winmd):- Each package contains a
bin/directory where the compiler outputs compiled .NET assemblies and debugging symbol files (.pdb). - These must be generated purely from source by the local build or the Azure DevOps CI pipeline.
- Each package contains a
- Intermediate Reflection and Cross-Reference Data (
XppMetadata/,XppIL/):- The compiler generates
XppMetadata/to hold intermediate parsing trees and reflection indices used during compilation and debugging. - These files change on every compile and must never be committed.
- The compiler generates
- User Project and IDE Cache Settings (
*.rnrproj.user,.vs/,*.suo):- User files contain personal developer preferences, such as the active company (
DAT,USMF), the startup project, startup element, and window layouts. - Committing these files overwrites personal settings across the entire development team.
- User files contain personal developer preferences, such as the active company (
- Standard Microsoft Package Folders:
- Standard packages (
ApplicationPlatform,ApplicationSuite, etc.) must never be checked into version control. Only custom packages or custom extension models extending standard packages may be tracked.
- Standard packages (
Complete .tfignore Specification
A .tfignore file must be placed in the root of the workspace mapping (e.g., at $/ContosoFinance/Trunk/Main/Metadata/.tfignore and $/ContosoFinance/Trunk/Main/Projects/.tfignore):
# ========================================================
# TFVC Ignore Rules for Dynamics 365 Finance and Operations
# ========================================================
# Ignore compiled binaries and debug symbols
\bin\
*.dll
*.pdb
*.ilk
*.winmd
# Ignore intermediate compiler and reflection metadata
\XppMetadata\
\XppIL\
# Ignore temporary resource caches and output directories
\Resources\
\Output\
\obj\
# Ignore Visual Studio user preferences and solution caches
*.rnrproj.user
*.csproj.user
*.vbproj.user
*.suo
*.user
.vs\
# Ignore build runbooks and local test results
TestResults\
*.runbook.xml
*.runbook
For Git-based implementations (such as Unified Developer Experience workspaces), the identical file and directory patterns are placed into a root .gitignore file.
5. Check-in Policies, Work Item Association & Governance
Enterprise Dynamics 365 development mandates strict check-in governance configured within Azure DevOps Team Project settings.
Mandatory Work Item Association
Check-in policies can be configured in TFVC to block any check-in that does not link to an active Azure Boards Work Item (such as a User Story, Bug, or Task). This ensures complete traceability: any code line changed in an X++ class or table extension can be traced directly to a business requirement, functional design document (FDD), or defect ticket.
Check-in Discipline: Atomic Commits
Developers must practice atomic check-ins:
- Atomic Scope: All related elements for a feature—including the model descriptor (if newly created or updated), table extensions, classes, form extensions, and label files—must be checked in together within a single changeset or Git commit.
- Partial Check-in Anti-Pattern: Checking in an X++ class that references a new table field before that table field's XML file is checked in breaks the build for every other developer on the team.
6. Scenario Walk-Through: Onboarding a New Developer VM
Scenario: Setting Up Contoso's Developer Workspace
David, a new senior X++ developer, is assigned a fresh Tier 1 developer VM deployed via LCS. He needs to connect his machine to Contoso's Azure DevOps repository and prepare his environment for active feature development without corrupting standard models.
Step-by-Step Implementation:
- Open Visual Studio as Administrator: David launches Visual Studio with elevated administrative privileges (mandatory for interacting with IIS worker processes and
PackagesLocalDirectory). - Connect to Azure DevOps: Under Team > Manage Connections, David connects to the
https://dev.azure.com/ContosoFinanceorganization and selects theERP-Customizationsteam project. - Configure Workspace Mappings: In Source Control Explorer, David opens the Workspace dropdown and selects Workspaces > Add:
- He sets the workspace type to Local.
- Mapping 1 (Metadata): Sets Server Path to
$/ERP-Customizations/Trunk/Main/Metadataand Local Path toK:\AosService\PackagesLocalDirectory. - Mapping 2 (Projects): Sets Server Path to
$/ERP-Customizations/Trunk/Main/Projectsand Local Path toC:\Dynamics365\Projects.
- Verify
.tfignorePresence: David verifies thatK:\AosService\PackagesLocalDirectory\.tfignoreexists and contains exclusions forbin\,XppMetadata\, and*.rnrproj.user. - Perform Get Latest: David right-clicks the
$/ERP-Customizations/Trunk/Mainroot in Source Control Explorer and clicks Get Latest Version (Recursive). - Execute Full Build & DB Sync: Once downloaded, David opens Visual Studio, navigates to Extensions > Dynamics 365 > Build models..., selects the
ContosoSuitemodel, checks Synchronize database, and initiates the build. The build succeeds, creating localbin/assemblies and synchronizing tables to local SQL Server without any version control pending changes generated for binary artifacts.
7. Real-World Exam Traps: Version Control in F&O
[!WARNING] Exam Trap 1: Checking In the
bin/orXppMetadata/Directories Questions frequently ask which directories must be committed when creating a new model. Exam options that includebin,XppMetadata, or*.rnrproj.userare strictly incorrect. Only source XML files and theDescriptor/<ModelName>.xmlfile should be committed.
[!WARNING] Exam Trap 2: Root Mapping
$/Trunk/MainDirectly toPackagesLocalDirectoryA common question tests workspace mapping paths. Mapping the root branch$/Project/Trunk/Maindirectly toPackagesLocalDirectoryputs theProjectsdirectory inside the AOS package store, violating model architecture and causing compiler errors. TheMetadatasubfolder must be mapped toPackagesLocalDirectory, whileProjectsmust map to a separate directory.
[!WARNING] Exam Trap 3: Omitting the Model Descriptor XML A scenario describes a developer who created a new model with several tables and classes, checked them in, and went on leave. Other developers report that they cannot see the new model in Visual Studio Application Explorer despite getting latest. The root cause is that the author failed to check in the Model Descriptor file (
Descriptor/<ModelName>.xml).
[!WARNING] Exam Trap 4: Tracking Standard Microsoft Platform Packages The exam may present an option recommending to check in the entire
PackagesLocalDirectoryfolder. This is a severe architectural error. Standard packages (ApplicationSuite,ApplicationPlatform) are multi-gigabyte binaries provided by Microsoft; checking them into source control corrupts versioning and will immediately overwhelm repository storage limits.
When configuring a Team Foundation Version Control (TFVC) workspace on a Dynamics 365 Finance and Operations developer VM, what is the required local mapping destination for the repository Metadata folder ($/Project/Trunk/Main/Metadata)?
Which set of files and directories must be explicitly excluded from version control tracking via .tfignore or .gitignore in a Dynamics 365 Finance and Operations development environment?
A developer creates a new custom model in Visual Studio, adds several tables and classes, and checks in the changes. When other developers perform a Get Latest operation, they report that the new model does not appear in Visual Studio Application Explorer and their projects fail to compile. What is the most likely cause of this issue?
How do Local Workspaces differ from Server Workspaces when utilizing Team Foundation Version Control (TFVC) in Visual Studio for Dynamics 365 Finance and Operations development?