Moving 14 developers from TFVC to Git with a broken CI build
Northwind's 14 developers are migrating an AX 2012 TFVC repository to Git in Azure DevOps for a cloud Finance and Operations project. Releases ship monthly, with occasional emergency hotfixes. After three sprints the symptoms are: one CI build in four fails with 'the model X was not found', or with merge conflicts in Labels_Northwind.en-US.label.txt, which holds 9,000 entries; two developers regularly overwrite each other's label changes; a hotfix was made directly in the Tier-2 sandbox and never reached source control; and developers wait roughly five hours for the CI build before learning that a check-in broke the build. The team also wants a stable environment for user acceptance testing on a frozen codebase.
1. Design the branch and release strategy, including how the hotfix should have been handled.
Read the worked answer
Use a trunk-based flow rather than long-lived develop branches, because X++ merges are expensive and long-lived branches guarantee a large, conflict-heavy integration event:
main= trunk, always buildable, protected by branch policy (PR + build validation + reviewer).feature/*= short-lived (days, not sprints), one per work item, deleted on merge.release/*= cut frommainwhen the monthly release is frozen; only stabilization fixes go here.hotfix/*= branched from the release tag, fixed, built, deployed, then cherry-picked back to main so the next release does not regress it.
Environment mapping: the UAT environment is deployed from release/* only, never edited. The Tier-2 hotfix edited by hand is exactly the failure mode to design out - nobody edits code in any environment above Dev, and the pipeline is the only deployment path. Recover the sandbox hotfix by diffing that environment's model against the release branch, committing the delta, and then redeploying the sandbox from source to confirm parity.
2. Why do label merges keep conflicting, and what change removes the cause rather than the symptom?
Read the worked answer
A single label file shared by every model is a merge hotspot: Git merges line-by-line, and a file where dozens of developers append entries in arbitrary positions will conflict on nearly every concurrent branch. Resolving conflicts by hand also risks silently dropping a label that code references.
Fix the structure, not the process:
- Give each model its own label file (for example
Labels_NorthwindCore,Labels_NorthwindFreight) so the blast radius of a conflict matches one team's work. - Enforce a naming convention with a model prefix (
FRT_,WHS_), and treat a label as immutable once shipped - changing the text is fine, changing the ID is not. - Discard unused labels via the Best Practice checker rather than by manual pruning.
- Keep the label files text-based and checked in (not generated at build), and forbid editing another model's label file via PR review.
Ordering alone does not fix it: alphabetical or sorted insert still conflicts when two branches touch adjacent lines.
3. What causes the intermittent 'model X was not found' build failure, and how would you cut the five-hour feedback loop?
Read the worked answer
'Model was not found' almost always means the build cannot see a model that the code depends on:
- A model exists only on a developer VM (created locally, or pulled from the asset library) and was never checked in.
- The build definition's model list does not include the model, or the referenced model package was not restored before compilation.
- A branch was created before the model was added, so the dependency is satisfied in
mainbut not in that branch.
Remediation: inventory models on a clean VM against source control, check in all models and their descriptors, and make the pipeline restore the referenced packages before compiling. Add a solution/model dependency check to the PR build.
To shorten feedback: keep a fast PR build (compile plus Best Practice checks on the changed models, X++ unit tests) that gates merges, and run the full build, full test suite and deployable package creation nightly against main. A five-hour build gating every check-in means the team batches changes, which makes the merges worse - the fast/slow split is what breaks that loop.