1node.si
← Registry

cd-azure-devops-git-deploy

cleared

Designs Azure Pipelines CD that syncs build artifacts into a dedicated Git deployment repository, commits, and pushes so a server-side Git hook runs deploy. Covers build-stage ZIPs (ExtractFiles@1), Linux (rsync) and Windows (robocopy /MIR) agents, CmdLine tasks, and required variables. Use when implementing Azure DevOps CD, git push deploy, post-receive hooks, or mirroring artifacts into a deploy repo.

files.jsonSKILL.md
---
name: cd-azure-devops-git-deploy
description: >-
  Designs Azure Pipelines CD that syncs build artifacts into a dedicated Git
  deployment repository, commits, and pushes so a server-side Git hook runs
  deploy. Covers build-stage ZIPs (ExtractFiles@1), Linux (rsync) and Windows
  (robocopy /MIR) agents, CmdLine tasks, and required variables. Use when
  implementing Azure DevOps CD, git push deploy, post-receive hooks, or
  mirroring artifacts into a deploy repo.
---

# Azure DevOps CD: Git push deploy

## Pattern

1. **Build** publishes a deploy artifact (often a **ZIP** produced on the build stage).
2. **Release or deploy job** **downloads** the artifact when it is not in the same job, then **extracts** the ZIP into a folder under `$(System.ArtifactsDirectory)` (e.g. **`ExtractFiles@1`** → `.../Project/`). See [reference.md](reference.md).
3. **Clone** the **deployment Git repo** into a working folder.
4. **Mirror** extracted files into that folder **without touching `.git`** (rsync on Linux, `robocopy /MIR` on Windows).
5. **`git add` / `git commit` / `git push`** to `$(DeployGitBranch)`.
6. **Server** runs a **post-receive / post-update hook** (or CI on that repo) to roll out the new tree.

Treat `$(DeploymentGitUrl)` as a **secret** when it embeds credentials. Prefer **HTTPS + PAT** or **SSH key** task over plain URLs in logs.

## Required pipeline inputs

Define (variables, variable group, or runtime parameters) at least:

| Input | Role |
|--------|------|
| `DeploymentGitUrl` | Clone/push URL for the deployment repository |
| `DeployGitBranch` | Branch to push (e.g. `main`, `production`) |
| `gitFriendlyUserName` / `gitUserEmail` | Identity for the deploy commit |
| Artifact layout | After extract: loose files under `$(System.ArtifactsDirectory)/<ArtifactFolder>` (example: `Project`) |

Adjust ZIP name, **ExtractFiles** `archiveFilePatterns`, and **PublishPipelineArtifact** / **DownloadPipelineArtifact** paths so they agree.

## Linux agent (rsync)

1. **Extract** (when the build delivers a ZIP): **ExtractFiles@1** into `$(System.ArtifactsDirectory)/<ArtifactFolder>` (see reference).
2. Typical **CmdLine@2** sequence after that:
   - **Global git identity** (once per job): `git config --global user.name` / `user.email`.
   - **Clone** deployment repo into `deployment/` (empty dir, then `git clone $(DeploymentGitUrl) .`).
   - **Sync**: `rsync ... '$(System.ArtifactsDirectory)/<ArtifactFolder>/' ./` with `workingDirectory: deployment`.
   - **Commit + push** from `deployment`: `git add .`, `git commit -m "Version: $(Build.BuildNumber)."`, `git push -u origin $(DeployGitBranch)`.

Use `bash` on Microsoft-hosted Ubuntu images; ensure `rsync` is installed (usually present).

## Windows agent (robocopy mirror)

Use **ExtractFiles@1** the same way when the build artifact is a ZIP, then mirror the extracted folder.

`rsync` is not native on Windows. Use **`robocopy`** to mirror the artifact tree into the clone root, excluding Git metadata.

- Run from **PowerShell** so `$LASTEXITCODE` is reliable after `robocopy` (e.g. **PowerShell@2** or `pwsh` with `workingDirectory` set to `deployment`).
- **Robocopy success**: exit codes **0–7** mean success; **8+** mean failure. Normalize for the pipeline:

```powershell
robocopy "$(System.ArtifactsDirectory)\<ArtifactFolder>" . /MIR /XD .git /NJH /NJS /NFL /NDL
if ($LASTEXITCODE -lt 8) { $global:LASTEXITCODE = 0 }
```

- **`/MIR`**: mirror (add/update/delete in destination to match source). Equivalent in spirit to `rsync --delete`.
- **`/XD .git`**: exclude the `.git` directory.
- **Exclude dot-git files** (e.g. `.gitignore`, `.gitattributes`): add `/XF .gitignore .gitattributes` or additional `/XF` entries. Wildcards for `/XF` vary by OS build; prefer explicit names if a pattern fails.

Map `<ArtifactFolder>` to the same logical folder as on Linux (example: `Project`).

## Operational notes

- **Empty commits**: if nothing changed, `git commit` fails; handle with `git diff --quiet && git diff --cached --quiet || git commit ...` or `git status --porcelain` guard.
- **Non-fast-forward**: if the deployment branch advances elsewhere, add `git pull --rebase origin $(DeployGitBranch)` before push, or document a **force** policy (avoid unless the hook repo is single-writer).
- **Shallow clone**: `git clone --depth 1` speeds up large deploy repos when full history is not needed.
- **Logging**: reduce `robocopy` noise with `/NJH /NJS /NFL /NDL` if logs are too large.

**Compose with** a build skill (e.g. **`ado-dotnet-build-publish`**) for compile/publish + artifact upload, then **ExtractFiles** + git steps in the deploy stage.

## Full YAML examples

See [reference.md](reference.md) for **CmdLine@2** Linux and Windows-oriented examples aligned with this flow.