GitOps PR pipelines
Learn how Harness GitOps PR pipelines automate Git-based deployments through pull requests, from trigger to cluster sync.
A Harness GitOps PR pipeline automates the full lifecycle of a Git-based deployment. Instead of applying changes directly to a cluster, the pipeline commits configuration updates to a Git repository, raises a pull request for review, and lets ArgoCD reconcile the desired state once the PR is merged. This keeps Git as the single source of truth while giving you pipeline-level orchestration, approval gates, and audit trails.
What is a PR pipeline?
A PR pipeline connects your CI/CD workflow to GitOps by turning every deployment into a traceable Git change. You can choose between two flow patterns depending on how you want PR reviews and approvals to work.
Standard flow (separate Merge PR step):
Pipeline Trigger
│
▼
Update Release Repo ── commits config changes & raises a PR
│
▼
PR Created in Git
│
▼
Review / Approval ──── manual or automated
│
▼
Merge PR ───────────── pipeline merges the approved PR
│
▼
ArgoCD Detects Change
│
▼
GitOps Sync ────────── forces an immediate sync (optional)
│
▼
Application Updated in ClusterPR-based promotion flow (wait for PR merge):
In the PR-based promotion flow, the pipeline pauses at the Update Release Repo step until the PR is merged through your Git provider's native review process. This removes the need for both a separate Merge PR step and an Approval step in the pipeline, because the PR review itself acts as the approval gate.
Each box in the flow maps to a concrete pipeline step you can configure in the Harness UI.
Prerequisites
Before you create a PR pipeline, make sure the following are in place:
GitOps service with a Release Repo manifest: The service must have at least a Release Repo manifest that points to the config file the pipeline will update (e.g.
values.yaml,config.json). See Create a GitOps service.Harness environment and cluster: An environment linked to a GitOps cluster managed by your GitOps agent. See Create GitOps environments.
Git connector with write access: A Harness Git connector that has permission to create branches and pull requests in your target repository.
ArgoCD application synced to a base state: The GitOps application should already be synced so the pipeline has a known-good starting point.
GitOps pipeline steps
Harness provides purpose-built steps for GitOps pipelines. The table below summarizes every available step, what it does, and which service manifest it depends on.
Commits config changes (image tag, Helm values, etc.) to the release repo and raises a PR. Optionally waits for the PR to be merged externally.
Release Repo manifest
Discovers GitOps applications linked to the service and environment (ApplicationSet workflows only)
Deployment Repo manifest or ApplicationSet references
Updates values files, Helm overrides, or target revision directly on the application
None
Update Release Repo
Fetches config files from the release repo, applies variable changes, commits to a new branch, and creates a PR.
Variables (variables[].name)
string
Yes
Config file key. Dot-separated for nested (a.b), index for lists (items[0].tag). Cannot add or remove list items.
Type (variables[].type)
string
Yes
String, Number, or Secret.
Value (variables[].value)
string
Yes
Value to write. Blank values are ignored - no update is written for that key.
PR Title (prTitle)
string
No (Harness: Updating config overrides)
Title for the created PR.
Wait for PR merge (waitForMerge)
boolean
No (false)
Block pipeline until PR is merged externally via the Git provider. Requires ng-manager v1.146.0, next-gen-ui v1.134.0, delegate 891xx+.
Allow Empty Commit (allowEmptyCommit)
boolean
No (false)
Commit even when no file changes are detected. Requires delegate 84600+.
Succeed if no files changed (allowNoFilesChanged)
boolean
No (false)
Pass the step when all values already match the release repo. No branch, commit, or PR is created; PR URL output is empty. A downstream Merge PR step also passes when PR URL is empty.
Ignore missing files (ignoreMissingFiles)
boolean
No (false)
Skip the step instead of failing when the target config file does not exist in the repo.
Don't Propagate Pipeline Variables (skipPipelineVariables)
boolean
No (false)
Write only step-level variables. Excludes service and environment variable overrides from the release repo file.
Disable Git Restraint (disableGitRestraint)
boolean
No (false)
Remove the Git lock so multiple pipelines can write to the same repo concurrently.
Ignore missing values (ignoreMissingValues)
boolean
No (false)
Skip a variable update when its resolved value is null or empty.

Status checks in pull requests
The Update Release Repo step sends status updates to the pull request it creates, showing which pipeline created the PR and the deployment stage status directly in your Git provider.
When enabled, two status checks appear on the PR:
Manifest update trigger — Posted immediately when the PR is created. Shows the pipeline name and links to pipeline step execution.
Stage execution status — Posted when the stage completes. Shows whether the stage passed or failed and links to pipeline stage execution.

These checks help you track which pipeline execution is responsible for a given manifest change and whether the deployment stage succeeded.
Requirements:
Feature flag
CDS_GITOPS_SEND_STATUS_TO_GIT_DISABLEDmust be off (contact Harness Support to disable).Delegate version 26.08.89900 or later.
SCM connector must use a supported provider (see table below).
Enable status checks:
Add sendGitStatus configuration at the stage level with enabled: true:

SCM provider support:
The following table summarizes SCM provider support for manifest update triggers and stage execution status reporting:
GitHub
✅
✅
GitLab
✅
✅
Bitbucket Cloud
✅
✅
Bitbucket Server
✅
✅
Harness Code Repository
✅
✅
Azure DevOps (Azure Repos)
❌
✅
Does not support the initial manifest update trigger status. Only posts stage execution status on completion.
Merge PR
Merges the PR created by Update Release Repo.
Merge Strategy Type (mergeStrategy)
enum
No (merge)
merge: preserves full commit history. squash: combines all PR commits into one commit on the target branch.
Delete Source Branch (deleteSourceBranch)
boolean
No (false)
Delete the PR source branch after merge completes.
Disable Git Restraint (disableGitRestraint)
boolean
No (false)
Remove the Git lock so multiple pipelines can write to the same repo concurrently.

Fetch Linked Apps
Discovers all GitOps applications generated by the ApplicationSet linked to the pipeline's service and environment. When this step runs before a GitOps Sync step, the Sync step automatically uses the discovered applications - no manual selection needed.
Not needed for standalone applications (no ApplicationSets). Select applications directly in the GitOps Sync step by name, regex, or labels instead.
Deployment Repository is being deprecated
The Deployment Repository manifest on GitOps services is being deprecated and will stop working on October 4, 2026. If your GitOps service still uses a Deployment Repository, migrate it to Application Set references before then so that Fetch Linked Apps and PR pipelines keep working. Go to Migrate Deployment Repo to Application Set references to update your service.
Filter applications per configured service/env (filterByServiceEnvCluster)
boolean
No (false)
false (recommended): fetch apps matching both service definition and linked cluster. true: fetch all apps in the cluster for the environment, ignoring service config.
filterByServiceEnvCluster: true with a large number of applications can cause the step to time out. Leave it false unless you have a specific need.
The step output includes app name, agent ID, and URLs. Reference them in subsequent steps using Harness expressions from the output tab.

GitOps Sync
Triggers a sync for one or more Argo CD applications - this is the step that applies changes to your cluster. Place approval gates and policy checks before it; place verification and notifications after it.
If a Fetch Linked Apps step ran earlier in the stage, the Sync step automatically uses the discovered applications and no selection is needed.
Application selection (use one):
Application Name (applicationsList)
list<object>
No
Explicit {agentId, applicationName} pairs. Auto-populated when Fetch Linked Apps ran earlier in the stage.
Application Regex (applicationRegex)
string
No
Go regex matching up to 1000 app names. Not JEXL. Test at regex101.com with Golang flavor.
Application Labels (applicationLabels)
list<string>
No
Key:Value label selectors. Partial matches also consider service and environment names.
To pass label values from pipeline variables:
JSON list:
<+json.list("$", <+pipeline.variables.labels>)>- format variable as["cluster"]or["cluster", "list"]Split:
<+pipeline.variables.labels.split(",")>- format variable asclusterorcluster,list
Sync behaviour:
Prune (prune)
boolean
No (false)
Delete cluster resources absent from Git.
Dry Run (dryRun)
boolean
No (false)
Preview sync without applying changes.
Apply Only (applyOnly)
boolean
No (false)
Skip pre/post-sync hooks and sync waves.
Force Apply (forceApply)
boolean
No (false)
Delete and recreate resources instead of patching.
Show Resource Progress (showResourceProgress)
boolean
No (false)
Stream per-resource sync status to step logs.
Health and timeout:
Wait until healthy (waitTillHealthy)
boolean
No (false)
Hold step until all synced apps reach Healthy.
Fail If Step Times Out (failOnTimeout)
boolean
No (false)
When waitTillHealthy: true, fail the step if Healthy is not reached before timeout.
Degraded State Timeout (degradedStateTimeout)
duration string
No ("0")
Max time app may stay in Degraded before step fails (e.g. "30s", "5m"). "0" disables early-exit. Only evaluated when waitTillHealthy: true.
degradedStateTimeout can fire during transient degraded states such as rolling updates where pods are briefly unavailable. Set conservatively or leave at "0".
Argo Rollouts:
Auto-promote rollout (autoPromoteRolloutBehavior)
enum
No
Action on an Argo Rollout after sync: promote-full, resume, retry, abort, restart. Omit if not using Argo Rollouts.
Resource filter (resourcesFilter) - available only when selecting by application name, not by regex or labels:
Group (group)
string
No
Kubernetes API group (e.g. apps).
Kind (kind)
string
No
Resource kind (e.g. Deployment).
Name (name)
string
No
Resource name pattern.
Namespace (namespace)
string
No
Namespace pattern.
Label (label)
string
No
Label selector.
Sync options (syncOptions):
Skip schema validation (skipSchemaValidation)
boolean
No (false)
Skip Kubernetes schema validation before applying.
Auto-create namespace (autoCreateNamespace)
boolean
No (false)
Create the destination namespace if it does not exist.
Prune resources at last (pruneResourcesAtLast)
boolean
No (false)
Defer pruning until all other resources are applied.
Apply out-of-sync only (applyOutOfSyncOnly)
boolean
No (false)
Only apply resources that differ from cluster state.
Replace resources (replaceResources)
boolean
No (false)
Use kubectl replace instead of apply.
Server-side apply (serverSideApply)
boolean
No (false)
Use Kubernetes server-side apply.
Respect ignore differences (respectIgnoreDifferences)
boolean
No (false)
Honor the app's ignoreDifferences config during sync.
Prune propagation policy (prunePropagationPolicy)
enum
No (foreground)
How pruned resources are deleted: foreground, background, orphan.
Retry strategy (retryStrategy):
Limit (limit)
integer (≥ 0)
No
Max retry attempts.
Base backoff (baseBackoffDuration)
duration string
No
Initial wait before first retry (e.g. 5s).
Backoff factor (increaseBackoffByFactor)
integer (≥ 0)
No
Multiply backoff by this factor on each retry.
Max backoff (maxBackoffDuration)
duration string
No
Backoff ceiling (e.g. 3m).

Update GitOps App
Updates an Argo CD application's target revision, Helm overrides, or Kustomize overrides directly - without modifying files in Git. Common use case: pin the app to a new immutable Git tag, then follow with a GitOps Sync step.
Agent (agentId)
string
Yes
Harness GitOps agent identifier.
Application (applicationName)
string
Yes
Argo CD application name.
Target Revision (targetRevision)
string
No
Branch, tag, or commit SHA.
Helm overrides (helm)
object
No
Helm parameters, file parameters, and values files. Merged with existing app params; step-level overrides take precedence.
Kustomize overrides (kustomize)
object
No
Kustomize image overrides.
For multi-source applications, select your app in the Application field - all sources appear and can be updated individually.

GitOps Rollback
Rolls one or more Argo CD applications back to a previous deployment revision. This is the Harness equivalent of argocd app rollback.
Go to Rollback GitOps applications for the full guide including how revisions work, the UI rollback flow, and edge cases.
Top-level parameters:
Applications (applicationsList)
list<object>
Yes
One entry per application to roll back.
Revisions to roll back (revisionsToRollback)
integer
No (1)
Steps N syncs back for any app with no historyId or per-app revisionsToRollback.
Prune (prune)
boolean
No (false)
Prune resources absent from the rolled-back revision.
Wait until healthy (waitTillHealthy)
boolean
No (false)
Hold step until all rolled-back apps reach Healthy.
Fail if step times out (failOnTimeout)
boolean
No (false)
When waitTillHealthy: true, fail if Healthy not reached before timeout.
Per-application target (applicationsList[*]):
Agent (agentId)
string
Yes
Harness GitOps agent identifier.
Application name (applicationName)
string
Yes
Argo CD application name.
History ID (historyId)
integer
No
Exact history entry ID. Validated at runtime - missing ID is a pre-flight error. Highest precedence.
Revisions to roll back (revisionsToRollback)
integer
No
Per-app offset. Overrides step-level. Ignored when historyId is set.
Target resolution: per-app historyId > per-app revisionsToRollback > step-level revisionsToRollback > default 1
GitOps Get App Details
Fetches live application status as a JSON payload that subsequent steps can reference via Harness expressions.
Hard Refresh (hardRefresh)
boolean
No (false)
Force a fresh status check from the cluster instead of using cached state.
Application Names (applicationsList)
list<object>
No
Explicit {agentId, applicationName} pairs.
Application Regex (applicationRegex)
string
No
Go regex to match app names. Max 1000 apps. Invalid regex causes the step to fail.
Example response:

Revert PR
Creates a new PR that reverts the commit from a previous Update Release Repo step. Use in failure strategies or rollback scenarios. Follow with a Merge PR step to merge the revert automatically.
Commit ID (commitId)
string
Yes
Commit to revert. Typically the commitId output expression from Update Release Repo.
PR Title (prTitle)
string
No
Custom title for the revert PR.
Disable Git Restraint (disableGitRestraint)
boolean
No (false)
Remove the Git lock so multiple pipelines can write to the same repo concurrently.
GitOps Rollout
Controls Argo Rollouts progressive delivery within your pipeline. Use this step to pause, resume, or abort a rollout. For full details, see Managing Rollouts in Harness Pipelines.
Deployment strategies
These four strategies cover the most common ways teams use Harness GitOps pipelines. Each strategy includes a complete pipeline YAML you can adapt directly - the YAML comments carry the key behavioral notes per step.
Strategy 1: Sequential environment promotion with pipeline approval gates
Every deployment produces a tracked PR in Git and passes through an explicit pipeline approval before reaching the next environment. This gives teams a controlled promotion ladder where each stage advances only after a human sign-off, and every promotion is traceable as a merged PR.
When to use:
Regulated environments where every change to production requires a recorded approval.
Teams that want Git history to serve as the deployment audit trail.
Pipelines that promote the same artifact across dev, staging, and prod in a single run.
Key configuration:
mergeStrategy: squashon Merge PR keeps the release branch clean.waitTillHealthy: trueon each GitOps Sync blocks stage advancement until the cluster is healthy.failOnTimeout: truecombined with a 30-minute step timeout causes the pipeline to fail fast rather than hang.
Failure handling: Each stage's rollbackSteps contain a Revert PR step (using the commit ID from Update Release Repo) followed by a second Merge PR. The rollback merges the revert PR automatically and a final GitOps Sync restores the previous cluster state.
Strategy 2: PR-review gated promotion (Git provider as approval gate)
Each environment promotion creates a PR and blocks the pipeline until that PR is merged through the Git provider. The PR review in GitHub or GitLab replaces the Harness approval step. This means the deployment record, the review, and the approval are all a single Git event - which satisfies compliance requirements that treat PR merges as change approvals.
When to use:
Teams whose change management process already runs through PR reviews and want to avoid duplicate gates.
Organizations where the Git provider's audit log (who approved, when, on which commit) is the required approval record.
Multi-environment pipelines where each environment has its own branch and reviewer group configured in the Git provider.
Key configuration:
waitForMerge: trueon Update Release Repo - the step blocks until the Git provider reports the PR merged.No Merge PR step needed. The pipeline resumes only after an external merge.
skipPipelineVariables: falseensures environment-level variable overrides (set on the Harness environment) are written into the release repo file alongside the step-level variables, without any extra configuration per pipeline.
Failure handling: Because the pipeline cannot auto-merge a revert PR (there is no Merge PR step in this flow), add a Revert PR step on the rollback path with waitForMerge: true as well - reviewers must also approve the revert, which preserves the change-control record on rollback.
PR-based promotion workflows
The Wait for PR merge option on the Update Release Repo step transforms a standard PR pipeline into a promotion workflow. Instead of the pipeline controlling the merge, the PR review and approval in your Git provider acts as the deployment gate. This approach aligns with the GitOps philosophy of using Git as the single source of truth for both configuration and approvals.
How it works
The Update Release Repo step creates a branch, commits the config changes, and opens a PR in your Git provider.
The pipeline pauses and waits for the PR to be merged. Harness polls the Git provider to detect the merge.
Reviewers are notified through your Git provider's native notification system (for example, GitHub PR notifications, GitLab merge request emails).
Reviewers review, approve, and merge the PR through the Git provider's UI or CLI.
Once the PR is merged, the pipeline resumes and moves to the next step (typically GitOps Sync).
When to use this pattern
Use PR-based promotion workflows when:
Your team already reviews and approves changes through PRs. This avoids duplicate approval gates in both Git and the Harness pipeline.
You want multi-environment promotions gated by PR reviews. For example, a pipeline that promotes to staging, waits for staging PR approval, then promotes to production with a separate PR review.
You want to align with Argo CD promotion patterns. This approach mirrors the promotion workflow model used by tools like gitops-promoter, where PR merges drive environment promotions.
Multi-environment promotion example
A typical multi-environment promotion pipeline uses the Wait for PR merge option at each stage boundary:
Each stage raises a PR for its target environment, and the pipeline advances only when that PR is merged. This gives reviewers full control over promotion timing while maintaining the audit trail and orchestration benefits of a pipeline.
Git restraint lock and concurrency control
Harness applies a per-token lock (called a Git restraint) on the Update Release Repo, Merge PR, and Revert PR steps to prevent concurrent writes to the same Git repository from hitting GitHub secondary rate limits. When multiple pipelines attempt to run one of these steps using the same Git connector token, Harness queues the steps and runs them one at a time. This serialization ensures that the token does not exceed the Git provider's rate limit threshold for content creation.
How the Git restraint lock works
The lock is applied per token reference, not per pipeline or per project. This means:
If two pipelines in different projects use connectors that reference the same underlying Git token, those pipelines share the same lock.
If a pipeline uses a connector with token A and another pipeline uses a connector with token B, they do not share a lock and can run concurrently.
Only one step can hold the lock at a time. Other steps using the same token wait in a queue (FIFO order) until the lock is released.
The lock is released when the step completes (success or failure) or times out.
When a step is queued behind a lock, it appears as BLOCKED in the execution logs and waits up to its configured timeout before failing with MARK_EXPIRED.
When to disable the Git restraint lock
The disableGitRestraint parameter (available in Update Release Repo, Merge PR, and Revert PR steps) removes the per-token lock and allows multiple pipelines to write to the same repository concurrently. Use this parameter when:
You are using a GitHub App connector instead of a Personal Access Token. GitHub Apps have significantly higher rate limit allocations (per-installation limits that do not share a ceiling with user tokens), so concurrent writes are less likely to hit secondary rate limits.
You have verified that your write volume is low enough that concurrent access will not trigger secondary rate limits on your Git provider.
A leaked lock has blocked your pipelines and you need an immediate workaround while the lock is cleared.
Do not disable the lock if you are using a Personal Access Token (PAT) and have high-frequency pipeline executions. Concurrent writes with a PAT can exhaust the token's secondary rate limit quota and cause all subsequent Git API calls to fail with 429 Too Many Requests errors.
Recommended configuration for high concurrency
If your pipelines frequently queue behind Git locks, Harness recommends the following configuration:
Switch to a GitHub App connector. GitHub Apps have higher rate limits and per-installation quotas that do not interfere with user token limits. Go to GitHub Apps documentation to create an app for your organization.
Set
disableGitRestraint: trueon your Update Release Repo, Merge PR, and Revert PR steps. This removes the Harness-side serialization and allows the GitHub App's higher limits to absorb the concurrency rather than queuing at the Harness layer.Monitor your Git provider's rate limit usage. Use your Git provider's API to check rate limit consumption and adjust your pipeline frequency or connector strategy if limits are consistently exceeded.
Troubleshooting leaked Git restraint locks
In rare cases, a Git restraint lock may not be released when a step completes. This can happen if the lock release event is lost due to Redis stream saturation, pod restarts, or other infrastructure issues. When a lock leaks, all subsequent steps using the same token are blocked indefinitely (up to the lock's 6-month TTL).
Symptoms of a leaked Git restraint lock:
Steps remain in
BLOCKEDstate for hours with no progress.All pipelines using the same Git connector token are affected, regardless of project or organization.
The step times out with
MARK_EXPIREDafter waiting for the full timeout duration.
Immediate workaround:
Set disableGitRestraint: true on the affected steps to bypass the lock. This allows pipelines to proceed while the leaked lock is cleared. Be aware that this increases the risk of hitting secondary rate limits if you are using a Personal Access Token.
Permanent fix:
Contact Harness Support to manually clear the leaked lock from the database. Harness engineering is working on automated lock cleanup mechanisms to prevent this issue in future releases.
Build your first PR pipeline
Follow these steps to create a basic image-promotion pipeline:
Create a pipeline: In your Harness project, go to Pipelines > Create Pipeline. Name it and select Start.
Add a Deploy stage: Select Add Stage, select Deploy, and choose Kubernetes as the deployment type.

Add Deploy stage Select your service: Choose the service you configured with a Release Repository in its GitOps Repository Sources.

Select service Configure the environment: Select your target environment (or set it as a runtime input so you can choose at execution time). Select Continue.

Configure environment Configure the Update Release Repo step: In the Execution tab, Harness adds the default steps automatically. Open the Update Release Repo step and add variables for the values you want to change (for example,
image.tag=v2.0.0).Choose your merge strategy: You have two options:
Use a separate Merge PR step (default): Leave the Update Release Repo step as-is and keep the Merge PR step that Harness adds by default. Add an Approval step between them if you need a pipeline-level approval gate.
Use Wait for PR merge: Enable Wait for PR merge on the Update Release Repo step and remove the Merge PR step. The PR is reviewed and merged through your Git provider, and the pipeline resumes automatically.
(Optional) Add a GitOps Sync step to force an immediate sync instead of waiting for ArgoCD's polling interval.
Save and run: Select Save, then Run. Select your environment and cluster when prompted and observe the pipeline execution.
Failure strategy and rollback
When a deployment goes wrong, use the Revert PR step to undo the configuration change:
Add a Revert PR step to your stage's failure strategy. Configure it with the
commitIdoutput from the Update Release Repo step:Add a Merge PR step after the Revert PR step to merge the revert automatically.
Optionally add a GitOps Sync step to force the application back to its previous state immediately.
For a complete working example with failure strategy, see the PR Pipeline with Failure Strategy sample repository.
Sample configurations
These GitHub repositories provide complete working pipeline YAML samples. Use them as a starting point after you understand the pipeline flow above. They are not required reading for beginners.
Basic PR Pipeline: Minimal pipeline with Update Release Repo, Merge PR, and sync.
PR Pipeline with Failure Strategy: Adds failure handling with Revert PR and automated rollback.
PR Pipeline with Notifications: Configures Slack or email notifications on pipeline events.
PR Pipeline with CV Integration: Includes Continuous Verification steps to monitor deployment health.
See also
ApplicationSets and PR Pipelines: Use PR pipelines to dynamically create applications through ApplicationSets.
Create a GitOps Service: Configure the service manifests that PR pipeline steps depend on.
Managing Argo Rollouts in Harness Pipelines: Progressive delivery with canary and blue-green strategies.
Last updated
Was this helpful?
