GitOps: Git as the Source of Truth for Infrastructure

GitOps: Git as the Source of Truth for Infrastructure

GitOps: Git as the Source of Truth for Infrastructure

GitOps: Git as the Source of Truth for Infrastructure

Every engineering team has lived this scene: a production server has drifted from its documented configuration, nobody knows exactly who changed what, and the fix takes hours of detective work. GitOps exists to make that scene nearly impossible. Instead of people or scripts pushing changes into a cluster by hand, an automated agent inside the cluster continuously pulls the desired state from a Git repository and reconciles reality to match it. Git becomes the single source of truth, and drift becomes something the system corrects rather than something a team discovers at 2 a.m.

That idea sounds simple. In practice, it reshapes how teams review changes, handle secrets, structure repositories, and respond to incidents. This article explains what GitOps actually is, where it came from, how it works under the hood, and what separates teams that succeed with it from teams that quietly abandon it after six months.

What GitOps Actually Means

GitOps is an operational framework that takes the practices developers already use for application code — version control, peer review, automated testing, and continuous delivery — and applies them to infrastructure and application configuration. The desired state of a system is stored declaratively in Git. A software agent running inside the target environment watches that repository and makes the live system match it.

The term was coined by Weaveworks around 2017, describing Git as the single source of truth for declarative infrastructure and applications. Weaveworks itself shut down in early 2024, but the idea outlived the company. Stewardship of the definition moved to the open-source community, where the OpenGitOps project now curates it.

The core distinction from traditional CI/CD is direction. In a conventional pipeline, the CI system builds an artifact and pushes it into production. In GitOps, an agent inside the cluster pulls the desired state and applies it. That inversion matters more than it first appears: it means the deployment credentials never leave the cluster, and the cluster can always tell you whether it matches Git — without anyone running a script.

The Four OpenGitOps Principles

The Four OpenGitOps Principles

The OpenGitOps project distills the framework into four principles. They are worth memorizing because they double as a checklist for evaluating any tool that claims to be “GitOps.”

  • Declarative. The entire desired state of the system is expressed declaratively — you describe what you want, not the sequence of commands to get there.

  • Versioned and immutable. That desired state is stored in a way that enforces immutability and retains a complete version history, which in practice means Git.

  • Pulled automatically. Software agents automatically pull the desired state from the source, rather than relying on external systems pushing changes in.

  • Continuously reconciled. Agents continuously observe the actual state and reconcile it toward the desired state.

Notice what is missing: there is no mention of a specific tool, a specific cloud, or even Kubernetes. GitOps is a set of operating principles, not a product. A team can follow all four principles with a homegrown controller, though in practice most use one of two mature tools.

Why the Pull Model Beats the Push Model

The push-versus-pull distinction is the most misunderstood part of GitOps, and it is where most of the practical benefit lives.

Aspect Push-based deployment Pull-based GitOps
Who initiates changes CI system or engineer In-cluster agent
Cluster credentials Held by external CI Never leave the cluster
Drift detection Manual or periodic scripts Continuous, automatic
Rollback Re-run an old pipeline Revert a commit
Audit trail CI logs, often incomplete Git history, complete
Access control CI system permissions Git repository permissions

With a push model, the CI system needs powerful credentials to reach into production. That makes the CI platform a high-value target: compromise it and you own every cluster it can reach. With a pull model, the agent reaches out to Git, so the blast radius of a compromised CI runner is much smaller.

The second benefit is drift correction. Someone edits a deployment by hand during an incident and forgets to revert it. In a push world, that change lives silently until the next deploy overwrites it — or causes a surprise. In a pull world, the agent notices within seconds and reverts it. Some teams find this alarming at first. It is supposed to be. If a manual change is genuinely needed, it should go through Git like everything else.

The Two Tools That Dominate

Two projects account for the vast majority of real-world GitOps deployments, and both are graduated projects in the Cloud Native Computing Foundation.

Argo CD is a declarative continuous delivery tool that uses a Git repository as the source of truth for application definitions. Its web UI shows the diff between desired and live state, which makes it popular with teams that want visibility for less technical stakeholders. It supports multi-cluster management and a broad set of add-ons.

Flux takes a more composable approach. It is a set of controllers, each responsible for a narrow job — watching a Git repository, syncing Helm releases, managing image updates — that you assemble like building blocks. Flux has no built-in UI by default, which suits teams that prefer to live in the terminal and treat Git as the only interface.

Consideration Argo CD Flux
Interface Web UI plus CLI CLI and API first
Architecture Centralized application controller Composable controllers
Multi-cluster Strong native support Supported via toolkit
Learning curve Gentler for beginners Steeper, more flexible
Best fit Teams wanting visibility Teams wanting minimal footprint

Neither is objectively better. The honest advice: pick based on whether your organization values a visual dashboard or a lean, scriptable toolkit, then commit. Running both in one organization creates exactly the kind of split-brain configuration GitOps is meant to eliminate.

Repository Structure: Where Most Implementations Go Wrong

Ask engineers who have run GitOps for a year what they would do differently, and repository layout comes up almost every time. The temptation is to put everything in one repository. It works fine at ten services and becomes unmanageable at two hundred.

The pattern that holds up is separating concerns by rate of change. Application source code changes constantly. Environment configuration changes weekly. Cluster-wide infrastructure — ingress controllers, certificate managers, monitoring stacks — changes rarely. Mixing all three in one repo means a typo in a deployment manifest can block an infrastructure update.

A common structure separates an application repository (code plus a base manifest) from an environment repository (per-cluster overlays for dev, staging, and production). Tools like Kustomize or Helm then compose the base with environment-specific values. The environment repository becomes the deployment control plane: promoting a release means opening a pull request that changes an image tag, and the review conversation happens in the pull request rather than in a chat channel.

Two practical tips that save real pain. First, give each cluster its own directory from day one, even if you only have one cluster — retrofitting separation later is tedious. Second, keep the reconciliation interval short in staging and slightly longer in production, so drift surfaces quickly where it is cheap to fix.

Secrets, Security, and the Hard Parts

GitOps has an awkward relationship with secrets. The whole point is that everything lives in Git, but you cannot commit a database password in plaintext. This is the single most common reason teams stall.

The workable approaches fall into two families. Sealed secrets encrypt a secret so it can be committed safely and decrypted only by a controller inside the target cluster. External secret stores keep the secret in a dedicated vault and have the cluster fetch it at runtime, with only a reference stored in Git. The second approach is generally preferred for anything sensitive, because it keeps the secret out of Git history entirely — and Git history is forever.

A second hard part is environment promotion. GitOps makes it easy to see what is deployed, but it does not automatically tell you whether a change has been tested. Teams typically gate promotion with CI checks that run before a pull request merges into the production environment repository. Without those gates, GitOps becomes a very well-audited way to ship broken code. (GitOps)

A third is observability of reconciliation itself. If the agent stops working, the cluster silently drifts. Alert on reconciliation failures and on sync age — if the last successful sync was four hours ago, something is wrong.

Common Mistakes and What Actually Works

The pattern across failed GitOps adoptions is remarkably consistent. Teams treat it as a tooling migration rather than an operating model change, install an agent, and expect culture to follow. It does not.

Mistake one: keeping manual access. If engineers can still `kubectl apply` directly to production, they will, and Git becomes a suggestion rather than a source of truth. Restricting direct write access is uncomfortable but essential. Read access for debugging is fine; write access defeats the model.

Mistake two: giant monolithic repositories. Covered above, but worth repeating because it is the most common structural error.

Mistake three: no rollback rehearsal. Reverting a commit is the GitOps rollback story, and it is a good one — but only if the team has practiced it. Run a rollback drill in staging before you need one at 3 a.m.

Mistake four: ignoring the diff. The most valuable habit GitOps enables is reading the diff between desired and actual state before approving a sync. Teams that skip this step lose most of the safety benefit.

What works, in practice: start with one non-critical service, prove the reconciliation loop, then expand. Write down the promotion process before you automate it. And treat the Git history as a product — clear commit messages, meaningful pull request descriptions, and linked tickets make incident investigation dramatically faster.

GitOps and the Wider Delivery Pipeline

GitOps handles the “last mile” of delivery: getting a known-good state into a running environment. It does not replace continuous integration. Building, testing, scanning, and packaging still happen in CI. The handoff point is the artifact — CI produces an image with an immutable tag, and the environment repository references that tag.

This split clarifies responsibilities. CI answers “is this build good?” GitOps answers “is production running the good build?” Teams that blur the two end up with pipelines that both build and deploy, which reintroduces the push model they were trying to escape.

The model also pairs naturally with policy as code. Admission controllers can enforce rules — no `latest` tags, resource limits required, approved registries only — so that a pull request merging into the environment repository cannot introduce a policy violation. The review happens at the pull request, the enforcement happens at the cluster, and the two reinforce each other.

Conclusion

GitOps is less a product category than a discipline: declare what you want, store it in Git, let an agent pull it, and reconcile continuously. The tools — Argo CD, Flux, and the growing collection of related projects — are mature enough that the technical side is rarely the obstacle. What separates success from failure is operational honesty: closing manual write paths, structuring repositories by rate of change, solving secrets properly, and rehearsing rollbacks before you need them.

The payoff is a system where the question “what is running in production?” has a precise, auditable, versioned answer. That is a modest-sounding benefit. In practice, it changes how confidently a team can ship.

Frequently Asked Questions

What is the difference between GitOps and DevOps?

DevOps is a broad cultural and organizational movement about collaboration between development and operations. GitOps is a specific operational pattern within that movement. It applies DevOps ideas — version control, code review, automation — to infrastructure and deployment, using Git as the single source of truth and an in-cluster agent to reconcile state.

Does GitOps require Kubernetes?

No, though the two are closely associated because the dominant GitOps tools were built for Kubernetes. The four OpenGitOps principles are platform-agnostic. In practice, GitOps is most mature in container environments, and support for virtual machines and other infrastructure is less developed. (What is GitOps?)

Is GitOps only for infrastructure, or also for applications?

Both. Most teams manage application deployments and cluster infrastructure in the same GitOps workflow, often in separate repositories. Application manifests, Helm charts, and cluster add-ons can all be reconciled by the same agent.

How do you handle secrets in a GitOps workflow?

Never commit plaintext secrets. Two common approaches are sealed secrets, which encrypt values so they can be stored safely in Git and decrypted only inside the cluster, and external secret stores, which keep the value in a vault and store only a reference in Git. The second is generally preferred for sensitive data because it keeps secrets out of Git history entirely.

What happens if someone changes the cluster manually?

The reconciliation loop detects the difference between the desired state in Git and the live state, then reverts the manual change. This is a feature, not a bug — it prevents undocumented drift. If a manual change is genuinely needed, it should be made in Git and reviewed like any other change.

Which tool should a team choose, Argo CD or Flux?

Choose Argo CD if your organization values a visual dashboard and multi-cluster management out of the box. Choose Flux if you prefer a composable, CLI-first toolkit with a minimal footprint. Both are mature and widely adopted. The more important decision is committing to one and standardizing on it, since running both creates configuration fragmentation.

on this page