Microsoft AZ-400: Source Control and Repository Management — Study Guide
Part of the Microsoft DevOps Engineer Expert AZ-400 — Study Guide. Practice with verified answers in the Microsoft exam hub, or take timed practice tests on ExamRoll.io.
Overview
Modern DevOps practices hinge on predictable, collaborative source control and disciplined repository management. Azure Repos and GitHub provide complementary capabilities for version control, policy enforcement, collaboration, and security. Mastery of branching strategies, pull request workflows, permissions, hooks, large-file handling, migration patterns, security scanning, and versioning is essential for resilient delivery pipelines and auditability. The goal is not only to store code but to create an enforceable, automated system of controls that scales team throughput without sacrificing quality.
Source Control Foundations in Azure Repos and GitHub
Azure Repos supports Git and Team Foundation Version Control (TFVC). Git is distributed, enables local commits, easy branching, and decentralized workflows. TFVC is centralized with server-side versioning, locked check-outs (optional), and is well-suited to legacy solutions with very large binary assets or teams trained on centralized workflows. New development should default to Git; TFVC remains viable when incremental change control and central permissions are paramount and migration cost is prohibitive.
Choose a branching strategy deliberately:
- Trunk-based development favors a single long-lived main branch with very short-lived feature branches and continuous integration. This accelerates flow, reduces merge debt, and is ideal for high-cadence teams with strong test automation.
- GitFlow uses long-lived develop and main (release) branches, with feature, release, and hotfix branches. It suits products with formal release trains and backporting needs but adds coordination overhead.
- GitHub Flow is a simplified model with a single main branch, short-lived topic branches, continuous deployment, and frequent releases. It’s effective for services that ship continuously.
Monorepo versus multi-repo is primarily an organizational and tooling choice:
- Monorepo consolidates many components in one repository, easing atomic cross-service changes, unified refactoring, and shared tooling. It can strain Git operations as history grows. Mitigation techniques include sparse checkout, partial clone, and CI path filters to scope builds and tests.
- Multi-repo isolates ownership, history, and permission boundaries, easing independent versioning and retention. It can increase cross-repo coordination and dependency drift; submodules or dependency managers and release orchestration are critical.
Ownership and change routing benefit from code ownership declarations. GitHub’s CODEOWNERS file maps paths to mandatory reviewers automatically. In Azure Repos, use path-based required reviewers in branch policies (and CODEOWNERS where enabled) to route reviews to component teams. Complement ownership with branch naming conventions, clear commit messages (e.g., Conventional Commits), and repository templates for consistency.
Governance: Policies, Permissions, and Pull Requests
Branch policies in Azure Repos codify quality gates:
- Required reviewers enforce a minimum reviewer count and can include specific individuals/groups or path-based auto-reviewers. Require comment resolution to ensure substantive feedback is addressed before merge.
- Build validation requires one or more CI pipelines to pass before merge. Use path filters to avoid unnecessary builds and set automatic triggering on new updates. Integrate external checks via status policies for security scans or performance tests.
- Merge strategies can be constrained: Merge (no fast-forward) records the merge history; Squash condenses changes to a single commit, keeping history linear; Rebase and fast-forward rewrites the topic branch on main for a straight line of history; Rebase and merge replays commits and preserves separate commits without a merge commit. Align strategy with audit needs and downstream tooling.
- Additional checks include required linked work items, minimum successful votes, and blocking if there are active comments or pending reviewers.
Pull requests orchestrate the integration conversation:
- Draft PRs signal work-in-progress and block completion until marked ready. Encourage early feedback without triggering policies prematurely.
- Auto-complete merges automatically once all policies pass, reducing coordination latency and increasing flow.
- Bypass policies exists for emergency situations or automation accounts. Lock this down with the “Bypass policies when completing pull requests” permission and audit through approvals and change management.
- PR templates standardize context: testing evidence, risk notes, deployment steps, and roll-back plan. In Azure Repos, place pull_request_template.md at the repo root or in .azuredevops/. Provide checklists for security, performance, and documentation.
Permissions and protected branches are your last line of defense:
- Use Azure DevOps RBAC groups (Project Administrators, Contributors, Readers) and fine-grained repo permissions (Create branch, Create tag, Contribute, Force push, Manage permissions, Bypass policies). Prefer allow/deny on groups rather than individuals.
- Protect main and release branches by denying Force push and Delete, limiting Contribute to PR merges only, and enabling branch policies that require builds and reviews. Consider “Lock” to temporarily freeze changes.
- Use branch-level permissions to restrict who can create or complete PRs against sensitive branches, and separate duties between developers and release managers.
Automation, Hooks, Large Files, and Security
Git hooks harden quality at the edges:
- Pre-commit hooks locally enforce linting, formatting, secret checks, and unit tests before a developer records a commit. Keep them fast and deterministic.
- Pre-push hooks block pushing code that fails integration tests or policy checks. Provide team-wide hook scripts via tooling (e.g., Husky for JavaScript) and document opt-in.
- Server-side hooks in managed services differ: GitHub supports server webhooks and required status checks; Azure DevOps Services does not allow custom server-side hooks but supports branch policies, build validations, service hooks, and status checks from external systems. In Azure DevOps Server (on-prem), server hooks are possible.
Large File Storage (Git LFS) stores large binaries outside the Git object database, keeping the repo performant:
- Track patterns with git lfs track “*.psd” or specific binary file types. Commit the .gitattributes so all contributors apply LFS consistently.
- Migrate history by running git lfs migrate import with path filters to rewrite large binaries to pointers. Coordinate with the team and pause pushes; force-push cautiously and update clones.
- Manage bandwidth by avoiding unnecessary smudging. Use GIT_LFS_SKIP_SMUDGE=1 and run git lfs fetch/pull selectively. Cache LFS in CI and consider artifact repositories for binaries that don’t need to live in Git.
Security assurance should be shift-left and policy-based:
- GitHub Advanced Security (GHAS) brings secret scanning (including push protection), code scanning with CodeQL, and dependency review to catch exposed credentials, code vulnerabilities, and supply-chain risks. Enforce as required checks on PRs. For Azure Repos, use Advanced Security for Azure DevOps to achieve similar secret scanning, SAST via CodeQL, and dependency insights.
- Secret scanning should be configured to block pushes with high-confidence secrets and alert security responders. Support custom detectors for organization-specific patterns.
- CodeQL code scanning should run on pull_request and schedule triggers, uploading SARIF results as status checks. Tune query packs to reduce noise and enforce coverage on critical paths.
- Dependency review surfaces version changes and known advisories during PR review; use this for remediation SLAs and license governance.
Migration, Versioning, and Release Management
Migrating from TFVC to Git requires strategy and tooling aligned to risk tolerance:
- For full-fidelity migration with deep history and work item linking, use git-tfs to clone TFVC paths to Git, preserving changesets and mapping users. Partition by application or branch to keep Git repos tractable. Clean large binaries with LFS during or after migration.
- For lightweight migration of current state, use the Azure DevOps Import tool to seed a new Git repo from TFVC (or another Git host), optionally limiting history. This reduces duration and risk but sacrifices deep historical granularity.
- Preserve traceability by migrating tags/labels, mapping TFVC branches to Git branches, and retaining a read-only TFVC mirror for audit. Validate with a pilot, freeze source during cutover, and run a verification matrix (builds, tests, and deployment).
Adopt semantic versioning for clarity and automation:
- Use SemVer 2.0.0: MAJOR.MINOR.PATCH with optional pre-release (e.g., -rc.1) and build metadata (+build.45). Tag releases with annotated tags (git tag -a v1.4.2 -m “Release 1.4.2”) and sign tags for audit.
- Automate version bumps in CI/CD:
- Drive version from commits with Conventional Commits and a release tool (e.g., GitVersion or semantic-release) to compute the next version based on commit types and scopes.
- Update build numbers and package versions automatically; fail the build if version drift or tag conflicts occur.
- Align versioning with branching:
- Trunk-based: main always releasable; create release tags from main; use short-lived release branches only for stabilization.
- GitFlow: release/* branches carry a frozen minor version; hotfix/* branch from main for urgent patches; merge back to both develop and main and tag at merge completion.
- GitHub Flow: tag main on deployment; use pre-release tags for canaries.
Integrate release automation with repository policies: require green builds with release pipelines, block merges without updated changelogs generated from commits, and require signed commits/tags in regulated environments.
Practical Problem Scenario
Starbucks must consolidate multiple legacy applications managed in TFVC into Azure Repos Git while establishing uniform governance, security scanning, and scalable workflows for both services and mobile apps.
- Choose branching and repository topology
- Action: Adopt trunk-based development with a monorepo for shared libraries and a few focused service repos for independently released services. Enable sparse checkout for the monorepo in developer onboarding scripts.
- Why: Trunk-based reduces merge debt and accelerates integration; monorepo centralizes shared code and enables atomic refactors, while sparse checkout avoids full history and working tree overhead for teams touching only subsets.
- Migrate TFVC projects to Git with history preservation where it adds value
- Action: Use git-tfs to migrate the main web and mobile codebases with full history, mapping large asset paths to Git LFS during migration. For small utilities, use the Azure DevOps Import tool to bring over current state only.
- Why: git-tfs preserves critical traceability for flagship apps; selective use of the Import tool accelerates low-risk migrations and reduces project duration.
- Establish protected branches and branch policies
- Action: Protect main and release/* with deny Force push/Delete; require two reviewers, resolve all comments, link a work item, and pass build validation with path filters. Constrain merges to Squash for service repos and Rebase and fast-forward for the monorepo to keep linear history. Disable “Bypass policies” except for a small release-engineering group.
- Why: Policy-as-code hardens quality gates and auditability. Merge strategies reflect team preferences: Squash simplifies revert and cherry-pick for services; linear history in the monorepo speeds blame and bisect operations.
- Standardize pull request practice
- Action: Add pull_request_template.md under .azuredevops/ with sections for risk, test evidence, performance impact, and rollback. Encourage Draft PRs early; enable Auto-complete on all PRs. Configure path-based required reviewers to emulate code ownership, and add CODEOWNERS for GitHub-hosted repos.
- Why: Templates raise the floor for review quality; Draft PRs promote early collaboration; Auto-complete removes idle time; ownership routing puts the right reviewers on the right diffs.
- Implement hooks and CI gates
- Action: Distribute pre-commit/pre-push hooks via repo tooling to enforce linting, secrets checks, and unit tests; keep execution fast. Use Azure Pipelines build validation as the canonical enforcement and add status checks from security scanners. Avoid custom server-side hooks; use service hooks to notify external systems.
- Why: Local hooks catch issues early without blocking collaboration; server-side enforcement in Azure DevOps is best achieved with branch policies and status checks for reliability and audit.
- Manage large assets with Git LFS
- Action: Track binary patterns (images, design assets, test media) with git lfs track; migrate legacy binaries with git lfs migrate import. Configure CI to set GIT_LFS_SKIP_SMUDGE=1 and selectively fetch to reduce bandwidth; cache LFS artifacts on build agents.
- Why: Keeps repos fast and avoids excessive network usage while maintaining reproducible builds.
- Integrate Advanced Security
- Action: Enable GitHub Advanced Security on GitHub repos and Advanced Security for Azure DevOps on Azure Repos. Turn on secret scanning with push protection, run CodeQL on PRs and nightly, and enable dependency review checks. Block PR completion on high-severity findings.
- Why: Shifts security left, preventing credential leaks and exploitable patterns from entering main, with actionable insights during review.
- Automate semantic versioning and tagging
- Action: Use GitVersion in Azure Pipelines to compute SemVer from branch and commit history; sign and push annotated tags on release pipelines; generate release notes from Conventional Commits. Use release/* branches only for stabilization; hotfix from tagged main.
- Why: Deterministic, automated versions improve traceability and deployment reproducibility, and signed tags support compliance.
This sequence lowers migration risk, enforces consistent quality and security, and streamlines delivery—precisely aligning repository management with scalable DevOps operations.
All domains · CI →
Practice these questions → · Timed practice on ExamRoll.io →
Pass the whole exam — not just this question
You found this answer. Get every verified question and explanation in one place, and save hours of prep. Free to start.
Pass your exam →