Azure DevOps Git Workflow
What you'll learn
~25 min- Configure PAT authentication for Azure DevOps git operations
- Implement the feature-branch-off-dev branching strategy used on the DS platform
- Create pull requests programmatically via the Azure DevOps REST API
Git operations on the DS platform
The DS platform uses Azure DevOps for source control, not GitHub. The branching model, the PR workflow, and the API surface are all different. AI tools default to GitHub patterns — gh pr create, .github/workflows/, origin/main. None of that applies here.
This lesson covers the three things you need: PAT authentication so git commands work through the proxy, the branching strategy your team actually follows, and creating PRs through the ADO REST API so you can automate the parts that are currently manual.
Azure DevOps comes in two forms: Azure DevOps Services (cloud-hosted) and Azure DevOps Server (on-prem). The REST API is identical for both. The only difference is the base URL: dev.azure.com/{org} for Services, {server}/{collection} for Server. Everything in this lesson works with either.
PAT authentication
Personal Access Tokens are the standard authentication method for Azure DevOps git operations over HTTPS. SSH keys work too, but many state networks block outbound SSH (port 22), making PATs the reliable option.
Create your PAT
- Open Azure DevOps in your browser.
- Click your profile icon (top right) > Personal access tokens.
- Click New Token.
- Set scope: Code (Read & Write), Work Items (Read & Write), Build (Read & Execute).
- Set expiration to 90 days (state policy maximum varies — check yours).
- Copy the token immediately. You will not see it again.
Configure git
# Store credentials so you don't re-enter the PAT on every pushgit config --global credential.helper store
# First push/pull will prompt for username and password.# Username: your email or ADO username# Password: paste the PAT (not your AD password)The NTLM fix
State networks often run NTLM proxy authentication. Git’s built-in HTTP handler tries NTLM negotiation, fails silently, and then retries in a loop until it times out. The fix is a single environment variable.
export GIT_HTTP_NO_NTLM=1Add this to your ~/.bashrc or ~/.zshrc. Without it, you will see 60-second hangs on git push and git fetch that eventually fail with fatal: unable to access.
If your git operations work fine today, they will still break intermittently when NTLM negotiation races with PAT auth. Set this variable even if things appear to work. It eliminates an entire class of timeout that is extremely difficult to debug because it succeeds sometimes.
Branching strategy
The DS platform uses a three-tier branching model:
main (production — deployed, protected) └── dev (integration — PR target, protected) ├── feature/add-training-module ├── feature/rbac-superadmin-role └── bugfix/swr-cache-staleRules:
mainis production. Direct commits are blocked by branch policy. Changes reachmainonly through PRs fromdevafter staging verification.devis the integration branch. All feature work targetsdev. Direct commits are blocked — PRs only.- Feature branches are created from
dev, notmain. Naming convention:feature/{ticket-id}-{short-description}orbugfix/{ticket-id}-{short-description}. - Work item linking is required. Every commit message and PR must reference an ADO work item ID.
Creating a feature branch
# Always start from the latest devgit checkout devgit pull origin dev
# Create the feature branchgit checkout -b feature/4521-training-telemetry
# Work, commit, pushgit add .git commit -m "Add App Insights custom events for training module #4521"git push -u origin feature/4521-training-telemetryIncluding #4521 in the commit message automatically links the commit to work item 4521 in Azure DevOps. This is not decoration — the PM and project leads track progress through linked work items. Unlinked commits create gaps in the audit trail.
Creating PRs via the ADO REST API
The Azure DevOps web UI works, but creating PRs through the REST API lets you automate the process from a script or an AI tool. Here is the prompt to generate a PR creation utility.
The prompt
Create a bash script called create-pr.sh that creates a pull request inAzure DevOps using the REST API.
Requirements:1. Accept these arguments: --title "PR title" --description "PR description" --source (default: current branch) --target (default: dev) --work-items (comma-separated work item IDs to link) --reviewers (comma-separated email addresses)
2. Use the Azure DevOps REST API: POST https://dev.azure.com/{org}/{project}/_apis/git/repositories/{repo}/pullrequests?api-version=7.1
3. Authentication: PAT from environment variable AZURE_DEVOPS_PAT (base64-encode as :PAT for the Authorization header)
4. The request body should include: - sourceRefName: refs/heads/{source-branch} - targetRefName: refs/heads/{target-branch} - title, description - Work item links as resourceRef objects - Auto-complete enabled (completionOptions.mergeStrategy: squash)
5. After creating the PR, output: - PR number - PR URL (clickable link to the ADO web UI) - Linked work items
6. Error handling: - Verify the source branch exists on the remote before creating - Check that the PAT is set - Parse API error responses and show the actual messageWhat the script produces
The AI generates a bash script that wraps the ADO REST API. The key API call looks like this:
# Base64-encode the PAT for the Authorization headerAUTH=$(echo -n ":${AZURE_DEVOPS_PAT}" | base64)
curl -s -X POST \ "https://dev.azure.com/${ORG}/${PROJECT}/_apis/git/repositories/${REPO}/pullrequests?api-version=7.1" \ -H "Authorization: Basic ${AUTH}" \ -H "Content-Type: application/json" \ -d '{ "sourceRefName": "refs/heads/feature/4521-training-telemetry", "targetRefName": "refs/heads/dev", "title": "Add App Insights telemetry for training module", "description": "Integrates custom events for module page loads and density view switches. Closes #4521.", "completionOptions": { "mergeStrategy": "squash", "deleteSourceBranch": true }, "workItemRefs": [ { "id": "4521" } ] }'The Azure DevOps REST API is versioned. Using 7.1 targets the current stable API. Older examples online use 6.0 or 5.1 — those still work but lack features like auto-complete merge strategies. Always specify the version explicitly.
See it in action
Work item linking patterns
Azure DevOps tracks work items (user stories, tasks, bugs) and links them to commits and PRs. This linkage is not optional on state projects — auditors review it.
In commit messages:
# Links to work item 4521git commit -m "Add telemetry events for density view switches #4521"
# Links to multiple work itemsgit commit -m "Refactor auth helpers for session timeout #4510 #4512"In PR descriptions:
Closes #4521
Changes:- Added App Insights custom events for module page loads- Added density view switch tracking- Integrated Key Vault for connection string retrievalThe Closes #4521 syntax automatically transitions the work item to “Done” when the PR completes. Other keywords: Fixes, Resolves.
Azure DevOps supports PR description templates stored in .azuredevops/pull_request_template.md. Ask the AI to generate one that includes sections for changes, work items, testing, and security considerations. Every PR gets the same structure, which makes reviews faster.
Branch policies
The DS platform enforces these branch policies on dev and main:
| Policy | dev | main |
|---|---|---|
| Minimum reviewers | 1 | 2 |
| Work item linking | Required | Required |
| Build validation | CI must pass | CI + staging deploy must pass |
| Comment resolution | All resolved | All resolved |
| Merge strategy | Squash | Squash |
These policies are configured in the Azure DevOps project settings, not in code. But knowing they exist changes how you structure your work: one feature per branch, one work item per PR, all comments resolved before merge.
Squash merging collapses all commits in a feature branch into a single commit on dev. This keeps the dev history clean and linear. Your individual commits during development (the messy ones, the “fix typo” ones, the “actually fix it this time” ones) disappear from the integration branch. This is a feature, not a limitation. The PR preserves the full commit history if anyone needs it.
A developer creates a feature branch from main, completes their work, and opens a PR targeting dev. What is wrong with this workflow?
Key takeaways
- PAT authentication with
credential.helper storeis the reliable method for Azure DevOps git over HTTPS. SSH is blocked on many state networks. GIT_HTTP_NO_NTLM=1eliminates the 60-second timeout caused by NTLM proxy negotiation. Set it in your shell profile and forget about it.- Feature branches come from
dev, nevermain. Main is production. Dev is integration. Branching from the wrong base creates merge conflicts and audit gaps. - Work item linking is mandatory. Use
#NNNNin commit messages andCloses #NNNNin PR descriptions. Auditors review this trail. - The ADO REST API (api-version=7.1) lets you create, update, and query PRs programmatically. The authentication pattern is Basic auth with a base64-encoded
:PATstring.
What’s next
In the next lesson, you will package the Next.js platform for deployment to Azure Government: standalone output mode, the static file copy step that trips up every team at least once, and zip deployment to Azure App Service.