# GitOps Explained — What It Is and Why Teams Adopt It

URL: https://www.devopsness.com/blog/gitops-explained-introduction
Author: Kiril Urbonas
Published: 2026-04-29
Updated: 2026-04-29
Categories: Infrastructure
Tags: GitOps, Kubernetes, ArgoCD, Infrastructure, Tutorial, Beginner

Summary: GitOps in plain words — what it actually is, the workflow it enables, and a hands-on demo using Argo CD on a local Kubernetes cluster.

---
# GitOps Explained: What It Is and Why Teams Adopt It

By the end of this post you'll have a clear definition of GitOps, a working mental model of how it changes deployment workflows, and a hands-on demo where you push a commit and watch a Kubernetes cluster reconcile to match. About 30 minutes.

You'll need: Docker installed, plus `kubectl`, `kind`, and a free GitHub account.

## What GitOps is, in one paragraph

GitOps is a model for managing infrastructure where **a Git repository is the source of truth for the desired state**, and an automated agent continuously reconciles the live system to match. To change something, you commit to the repo. To roll back, you `git revert`. To audit who changed what when, you read the git log.

Three concrete properties fall out of this:

1. **No clicking around.** All cluster state lives in YAML files in a repo, not in a console.
2. **Drift is detected automatically.** If someone changes a Deployment manually, the agent notices and reverts (or alerts) — Git is supposed to be the truth.
3. **Rollbacks are trivial.** `git revert` rolls back the change; the agent picks it up and reverts the cluster.

That's GitOps. The rest is implementation.

## Why teams adopt it

A few problems GitOps solves:

- **Drift between Git and cluster.** Engineers `kubectl edit` during an incident to fix something. Next CI deploy reverts their change — sometimes during the next incident.
- **No audit trail.** "Who changed this Deployment last and why?" requires cross-referencing CI logs, kubectl audit, and Git. None alone is enough.
- **Painful rollbacks.** Rolling back means running an old version of CI, which sometimes doesn't work because the CI tooling moved on.

GitOps gives you: cluster state always matches Git, every change is a Git commit (audit trail by default), rollback is `git revert + sync`. The trade is operational discipline (no more click-fixes) and an extra moving piece (the agent).

## The two big GitOps tools

Both watch a Git repo and reconcile a Kubernetes cluster:

- **Argo CD** — UI-driven, easier for newcomers, the more popular choice
- **Flux** — CLI-first, lighter, deeper integration with Kubernetes API

We'll use Argo CD. The model is identical for Flux.

## Step 1: Spin up a local cluster

```bash
kind create cluster --name gitops-tutorial
kubectl get nodes  # should show one Ready node
```

## Step 2: Install Argo CD

```bash
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
```

This drops Argo CD's deployments and services into the `argocd` namespace. Wait ~60 seconds for everything to start:

```bash
kubectl get pods -n argocd
```

You should see ~7 pods, all `Running` once they're ready.

## Step 3: Access the Argo CD UI

```bash
kubectl port-forward -n argocd svc/argocd-server 8080:443
```

In another terminal, get the initial admin password:

```bash
kubectl get secret -n argocd argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d; echo
```

Open https://localhost:8080 (accept the self-signed cert warning), log in as `admin` with that password.

You should see Argo CD's dashboard with no applications yet.

## Step 4: Create a Git repo for cluster state

We need a Git repo Argo CD can watch. Create a public repo on GitHub called `gitops-demo` (no README, no gitignore — keep it empty). Then locally:

```bash
mkdir gitops-demo && cd gitops-demo
git init
git branch -M main
git remote add origin https://github.com/<your-username>/gitops-demo.git
```

Create `app.yaml`:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
        - name: app
          image: nginx:1.27-alpine
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: hello
  namespace: default
spec:
  selector:
    app: hello
  ports:
    - port: 80
```

Commit and push:

```bash
git add app.yaml
git commit -m "initial nginx deployment"
git push -u origin main
```

## Step 5: Tell Argo CD about the repo

In the Argo CD UI:

1. Click "+ NEW APP"
2. Application Name: `hello`
3. Project: `default`
4. Sync Policy: `Automatic` (check both prune and self-heal)
5. Repository URL: your GitHub URL (e.g. `https://github.com/yourname/gitops-demo`)
6. Path: `.` (the repo root)
7. Cluster: in-cluster
8. Namespace: `default`
9. Click "CREATE"

Argo CD reads the repo, sees the Deployment + Service, applies them to the cluster. Within ~30 seconds:

```bash
kubectl get pods -l app=hello
```

You should see two `hello-...` pods running. Argo CD did this — you didn't `kubectl apply` anything.

## Step 6: Make a change via Git

Edit `app.yaml` locally — change `replicas: 2` to `replicas: 5`. Commit and push:

```bash
git commit -am "scale to 5 replicas"
git push
```

Within ~3 minutes (Argo's default polling interval; you can also click "REFRESH" in the UI), Argo CD picks up the change and applies it. Check:

```bash
kubectl get pods -l app=hello
```

You should now see five pods. The cluster reconciled to match the Git state — automatically. No `kubectl apply` from you.

## Step 7: Watch self-heal in action

Try to bypass GitOps:

```bash
kubectl scale deployment/hello --replicas=1
kubectl get pods -l app=hello   # 1 pod (briefly)
```

Wait ~10 seconds and check again:

```bash
kubectl get pods -l app=hello
```

Five pods. Argo CD detected the drift (cluster says 1, Git says 5) and reverted. That's the self-heal mechanism — it's the GitOps promise made operational.

## Step 8: Roll back

Decide that 5 replicas was too many:

```bash
git revert HEAD --no-edit
git push
```

Argo CD picks up the revert, scales back to 2.

That's the complete GitOps loop: edit, commit, push, watch the cluster converge. Same flow whether you're tweaking replicas or rolling out a new image tag.

## Step 9: Clean up

```bash
kind delete cluster --name gitops-tutorial
```

## When GitOps fits, when it doesn't

GitOps shines when:

- You have multiple services (~5+) on Kubernetes
- Multiple people deploy to the cluster
- Audit trail and rollback matter
- "Who changed what" is a recurring question

GitOps adds friction when:

- You have one service, one deployer
- You're still iterating on architecture daily
- Your cluster is short-lived dev/CI

For most production K8s teams above a small size, the friction is worth it.

## Common mistakes

**Trying to GitOps everything.** Cluster bootstrap (Argo CD itself, CNI, etc.) doesn't fit cleanly — that's the chicken-and-egg problem. Use Terraform for the cluster shell, GitOps for what runs inside.

**Keeping secrets in Git.** Don't. Use sealed-secrets, External Secrets Operator, or Vault Agent — anything that keeps actual secret material out of the repo.

**Auto-syncing everything to prod.** A bug in the repo becomes a prod outage automatically. Production apps benefit from manual sync (PR auto-merges in Git, but a human clicks "Sync" to actually deploy).

**Skipping the self-heal verification.** "GitOps revert worked" should be tested before you trust it in an incident.

## What to read next

You've seen the model. The next levels:

- [GitOps with Argo CD: automating Kubernetes deployments](/blog/gitops-argocd-automating-kubernetes-deployments) — what changes after running this for two years across 40+ services
- [Kubernetes 101: pods, deployments, and services](/blog/kubernetes-101-pods-deployments-services) — the K8s fundamentals GitOps builds on
- [Terraform tutorial: your first IaC project](/blog/terraform-tutorial-first-iac-project) — for the cluster-bootstrap layer beneath GitOps

GitOps isn't magic. It's a disciplined version of "Git is the truth," automated by a tool that watches and reconciles. Once a team is on it, the operational mode it enables — clean audits, easy rollbacks, no console-clicks — is hard to give up.

