RSS

GitOps workflows: How they work, what you need, and how to start

GitOps Kubernetes CI/CD Drift

What you’ll learn: How a GitOps workflow moves changes from Git to real environments, the key components that make it reliable, which tools are most commonly used, and how to apply the same pattern to infrastructure workflows with Terrateam.

A GitOps workflow is the moment you stop treating production like a place you poke with manual processes and start treating it like a system with a single source of truth – where a Git repository holds the desired state and automation keeps the actual state honest.

When it works, you feel it right away, because the deployment process gets less theatrical, the software delivery path gets shorter, configuration drift turns from a mystery into an alert you can action, and rollback capabilities look like what they always should have looked like in software development, which is reverting code changes and letting the system correct itself.

This is not a story hyping Kubernetes, although a Kubernetes cluster is where many teams first meet the reconciliation loop in a way they cannot ignore. It’s a story about version control turning into an operating model, about continuous integration and continuous deployment growing up into something closer to infrastructure management, where infrastructure configurations and application configuration become first class, where audit log quality is not an afterthought, and where DevOps teams stop asking who clicked what at 2 AM because the commit history already knows.

The rest of this guide stays practical.

You’ll get:

You’ll also get a bridge into infrastructure as code (IaC), where GitOps relies on the same primitives even when the target environment is not a cluster but a cloud environment full of long-lived resources.

First, to understand why the rest of the model works, let’s pin down what a GitOps workflow actually is, because it is easy to confuse the term with a particular tool or a particular CI/CD pipeline template.

What is a GitOps workflow?

A GitOps workflow is a way of running the software development lifecycle where the declarative configuration for your system state lives in a Git repository, changes arrive as pull requests or merge requests, code reviews gate what gets merged, and automation takes what is in Git and applies it to the deployed infrastructure while continuously comparing the system’s desired state to the live infrastructure and correcting drift.

That last part is the center of gravity. GitOps is not only about a deployment process that happens after merge, it’s also about the ongoing loop that keeps the actual state aligned with the desired state, which is why teams talk about reconciliation and why the model feels so at home in containerized environments where controllers already exist to converge cluster resources toward an intent.

It also matters to say out loud what GitOps is not.

GitOps is a workflow and an operating model, not a single product you buy. The pattern is composed of version control, automation, and guardrails that you can implement with different stacks, and the details will vary depending on whether you are managing infrastructure in Kubernetes, provisioning infrastructure with Terraform, or shipping application code that depends on both.

Once the definition is grounded, the next question becomes almost boring in the best way, which is what you actually need to make the workflow real.

What are the key components of a GitOps workflow?

If the previous section made Git sound like a control plane, this section makes that concrete by describing the minimum viable set of components that can sustain the model without collapsing into manual intervention.

The first component is the Git repository that holds your infrastructure definitions, configuration files, and any infrastructure and application configurations that represent the desired state, because without a single source of truth you are back to tribal knowledge and imperative approach runbooks.

The second component is continuous integration that turns changes into artifacts and evidence, which usually means it builds a container image, pushes it to a container image repository, runs tests that protect the software development path, and produces metadata that can be referenced by declarative infrastructure or application manifests.

The third component is the continuous deployment side, whether that is a dedicated GitOps controller or a deployment tool integrated into your CI/CD system, because you need an automated executor that can move changes from Git into the target environment in a repeatable way.

The fourth component is monitoring and alerting that closes the loop, not only for application health but also for configuration drift and failed deployments, because GitOps benefits show up when drift becomes visible and when system reliability is defended by feedback rather than hope.

Most teams also add workflow mechanics that are so common they almost feel like part of the definition. Infrastructure as code shows up early because managing infrastructure through code makes defining infrastructure and reviewing infrastructure changes possible, and the pull request becomes the change gate where humans decide whether a change belongs before automation makes it real.

The CI/CD automation then enacts changes after merge, which reduces human error and operational overhead, giving you an audit log that matches the development process rather than fighting it.

A GitOps workflow diagram shows a human path plus a reconciliation loop

With the key components in mind, you can now see the shape of the workflow. A diagram helps because GitOps is two paths at once: the human approval path and the automation reconciliation loop.

The human path is where software development decisions happen, and the automation path is where the system state is enforced.

Developer change
↓
Pull request opened → review, code reviews, approvals
↓
Merge to main in the version control system
↓
Continuous integration builds artifact
and updates declarative configuration in Git
(manifests, config files, infrastructure code references)
↓
GitOps agent or controller detects change in Git repository
↓
Compare desired state in Git to actual state in target environment
↓
Reconcile by applying changes to deployed infrastructure
↓
Continuous loop checks for configuration drift
and corrects live infrastructure back to desired state

There are details you can swap depending on your stack.

Some teams have CI update the configuration files directly, some teams have a separate environment repo that is updated by automation, and some teams use image update automation so that a new container image tag becomes a commit. What stays the same is the mental model that the system’s desired state is declared, the environment is continuously compared, and drift is treated as a bug in the system rather than an inconvenience you ignore.

Kubernetes makes this model obvious because the API already encourages a declarative approach and controllers already reconcile cluster configuration, but the same pattern applies anywhere you can express intent and run a reliable executor.

That contrast, between a pull-based reconciliation loop and the older push-based deployment process, is what separates GitOps workflows from traditional workflows, and it’s worth making explicit.

A GitOps workflow vs. a traditional workflow

Now that the diagram has made the loop visible, the comparison gets simpler because you can describe the shift in one sentence and then spend the rest of your time on why it matters.

Traditional continuous deployment often pushes changes into production from a CI runner or a human-controlled pipeline, which can work fine until credentials sprawl, manual processes creep back in, and the deployed infrastructure becomes a place you mutate directly when something is urgent.

GitOps flips that. Instead of the pipeline reaching into the environment as the primary actor, a GitOps agent or controller lives closer to the environment and pulls the desired state from Git, then performs the deployment process by syncing the live infrastructure to match what is declared.

Operationally, this reduces the blast radius of credentials, as the environment-side component can be scoped and audited. It also changes the story around configuration drift because the loop is built to detect divergence and correct it.

This also changes rollback capabilities in a way that feels almost too obvious once you get used to it. If Git is the source of truth, rolling back looks like reverting a commit or moving a tag, then letting automation reconcile back to the previous desired state. The audit log becomes the commit history, the deployment log becomes the sync history, and the question of who changed production is more about which merge request landed – a healthier question in any software development lifecycle.

Once you accept that pull-based model, the next practical question is which tools teams use to build it, because GitOps is not a product, but the tooling choices can still make or break a GitOps implementation.

What tools are commonly used in a GitOps workflow?

The push versus pull distinction sets the operating model, and tooling is where you turn it into something your team can live with day to day without adding unnecessary friction. At the base is source control, and teams usually land on GitHub, GitLab, or Bitbucket as their version control system, because the workflow depends on pull requests, merge requests, branch protections, and code reviews that enforce review-first changes.

Continuous integration then does the heavy lifting around building, testing, and publishing artifacts, and that might be GitHub Actions, GitLab CI, Jenkins, or a similar runner-driven system, as long as it can produce a container image, publish it to a container image repository, and update the declarative configuration that describes what should run.

For Kubernetes-oriented GitOps CD, Argo CD and Flux are the names you see most often because they both watch Git, detect changes, and sync cluster resources toward the desired state.

Config packaging tools sit beside the controllers because raw YAML becomes unmanageable fast. Helm is common when you want templating and reuse across environments, and Kustomize shows up when you want to keep declarative configuration closer to plain manifests while still supporting overlays for different target environment concerns.

Guardrails matter more than people expect, because GitOps automation amplifies both good and bad decisions. Policy as code, admission controllers, and automated checks in CI/CD pipelines help teams prevent risky infrastructure changes from landing, and observability is how they notice when the system state is unhealthy or when reconciliation has drifted into repeated failure.

Tool choice is not the goal, but it sets the constraints for how you structure repos, how you promote changes, and how you avoid turning Git into a dumping ground of generated noise, which is why the next step is describing a workflow you can actually adopt without inventing new pain.

A step-by-step GitOps workflow you can adopt

With the tooling categories in place, you can build a workflow that matches how people already work in software development, which is the real trick behind adopting GitOps without making it feel like a religion.

Start by defining the desired state explicitly, which means deciding what lives in Git as declarative infrastructure and what is derived, then ensuring your Git repository contains the configuration files that represent reality as you want it, not as it happens to be today.

Repo layout is the next lever. Some teams keep application code and environment configuration in the same repo because the coupling is real and the review experience is simpler, while other teams split into an app repo and an environment repo to keep infrastructure configurations, cluster configuration, and promotion rules separate from product changes.

The split can help when multiple services share a platform team, but it can also create coordination overhead, so the right choice is often the one that reduces the number of places humans have to touch for a single change.

Once the repo shape is chosen, make pull requests into the change gate in a way that is strict enough to prevent manual production edits, but not so strict that people route around it. Branch protections, required reviewers, and required status checks are the basic mechanics, and you will want CI to run tests, build artifacts, and publish a container image so that every merge has a traceable output.

Next, wire automation so that after merge, the desired state is updated in Git in a controlled way, whether that is committing new image tags into manifests, updating Helm values, or writing to an environment directory that represents a target environment. This is where GitOps relies on discipline, because you want changes to be visible as diffs and reviewable as code changes, not hidden inside someone’s runtime actions.

Install the GitOps controller in the environment, scope its permissions so it can manage the cluster resources it needs without becoming a universal key, and configure it to detect, compare, and reconcile. Promotion between environments can then be modeled as controlled movement of commits or controlled updates to environment directories, and many teams prefer directories over branch sprawl because long-lived branches become noisy and hard to reason about, especially when infrastructure provisioning and application configuration have different cadences.

Finally, add monitoring and alerts that tell you when reconciliation fails, when drift is detected, and when a deployed infrastructure change is harming the system, because GitOps automation is only as good as the feedback loop that tells you it is behaving.

This is the happy path, and it is real, but the field also has a collection of failure modes that repeat across teams, which is why best practices are less about ideology and more about preventing predictable mistakes.

GitOps best practices that prevent common failure modes

The workflow above functions well because it assumes review first changes and a consistent executor, and the fastest way to break it is to let exceptions creep in until the exception becomes the real workflow.

Manual intervention in production, even when it feels justified, creates configuration drift and turns Git into a story you tell yourself rather than a source of truth, so one of the most important practices is making manual production edits socially and technically difficult, then treating drift as a signal that something is wrong with your infrastructure code or your automation, not as an annoying detail you tolerate.

Another common failure mode is turning Git into a generator output bucket, where CI commits noisy diffs that bury the actual intent, and reviewers rubber-stamp changes because they cannot see what matters. Keeping the declarative configuration clean, using packaging tools thoughtfully, and separating generated metadata from human-owned definitions is how you preserve the review experience that makes the Gitops workflow safe in the first place.

Repo strategy also shows up here in practice. Splitting product code and config repos can reduce conflict when many teams are shipping into the same platform, but it can also create a coordination bottleneck where infrastructure changes and application code changes have to land in lockstep across repos. When branch sprawl becomes painful, environment directories and promotion commits often feel more natural because they keep history linear and reduce merge conflict games. They also make it easier to answer the audit question, which is what exactly changed between staging and production.

Security and policy checks belong in the workflow, not bolted on later. Whether you use policy as code, static analysis, or admission controls, the goal is that infrastructure changes are evaluated before they reach the live infrastructure, because human error is cheaper in a pull request than in a production incident, and GitOps is supposed to reduce operational overhead, not simply move it around.

All of this is still framed around Kubernetes in many people’s minds, but the underlying principles apply far beyond cluster configuration, especially when the system you are managing is declarative infrastructure in cloud providers rather than cluster resources. That is where GitOps becomes a broader infrastructure management story.

GitOps beyond Kubernetes is still GitOps

If the previous section was about discipline, this one is about scope, because a lot of teams discover that once Git becomes the control plane for deployed infrastructure, it’s hard to justify a different operating model for managing infrastructure that sits outside the cluster.

Infrastructure as code fits naturally here because Terraform-style workflows already encourage defining infrastructure in code, reviewing plans, and applying changes in controlled ways, and GitOps principles line up with that reality.

The mapping is straightforward. Git remains the single source of truth for infrastructure definitions and infrastructure configurations, pull requests remain the change gate where code reviews and policy checks happen, automation remains the executor that runs plans and applies after merge, and Git remains the audit log that explains what happened and why.

There are differences, and pretending otherwise is how teams get surprised. Terraform has state, providers have eventual consistency, and infrastructure provisioning can involve long-lived resources where drift can be caused by humans, by automation outside your control, or by the cloud platform itself.

Reconciliation becomes less about a controller constantly applying and more about running reliable checks, detecting divergence, and orchestrating applies with appropriate approvals, because automatically provisioned changes that are correct in code can still be operationally risky if applied at the wrong time.

The GitOps model becomes less about Kubernetes and more about treating infrastructure changes as part of the software development lifecycle, while a workflow layer that is built for IaC can make the pattern easier to adopt.

Terrateam fits where infrastructure workflows need GitOps discipline

If GitOps beyond Kubernetes is the extension of the model, Terrateam is the part that makes it practical for infrastructure code, because it treats Git as the control plane for managing infrastructure, then builds the workflow mechanics around pull requests so infrastructure provisioning and infrastructure changes happen with the same review and audit properties teams expect from application code.

In practice, Terrateam sits in the path where a merge request becomes an infrastructure change. A developer opens a PR that changes infrastructure definitions, Terrateam runs a plan and posts the result back to the PR so reviewers can see what will change in the deployed infrastructure, policy and guardrails can run as part of the same CI/CD automation story, and then merge triggers an apply in a controlled way, so the executor is predictable and the audit log is tied to version control rather than to whoever had access to run commands locally. Terrateam can also apply from the PR before merge, so failed Terraform applies show up while you’re still in review, and the fix is just another commit.

The result is a GitOps pipeline for infrastructure code that reduces manual intervention, keeps infrastructure configurations reviewable, and gives DevOps teams a repeatable mechanism for orchestrating infrastructure management across environments.

This also closes the loop in the same spirit as the Kubernetes reconciliation model, because once you can treat drift as a bug and infrastructure changes as reviewable diffs, you can build operational patterns that are less about heroics and more about system reliability. That’s the point of GitOps in the first place, and it’s ultimately leading to a development process where cloud providers, infrastructure components, and application configuration are all governed by the same version control system and the same expectations around safety.

And with that, the guide can land where it started, which is the promise that Git can be more than a place you store code, it can be the place you control reality.