GitOps mode writes the assembled haproxy.cfg to a git repository instead of posting to the Dataplane API. It is the right destination when configuration changes need to go through code review, when HAProxy is deployed by a pipeline rather than managed by hand, or when policy requires an auditable trail.
How it works
The canvas and draft are identical to live mode. What changes is the final step: instead of a Dataplane transaction, HAProxy UI assembles the canonical config into haproxy.cfg text, writes it, commits it, and pushes.
canonical draft → assemble.ts → haproxy.cfg text → write → commit → push
Reading works in the other direction: the current haproxy.cfg is parsed back into the canonical model, so the graph reflects what is actually in the repository.
Git operations
All git work is routed through Rust (git2), never through the webview:
Operation | Notes | Safety |
|---|---|---|
| Initial clone into the working path | — |
| Stage, commit and push the assembled config | Normal push |
| Fetch and fast-forward | Fails rather than merge on divergence |
| Replay local commits on top of the remote | Use when behind |
| Rewrite the branch |
|
| Drives the sync-state badge | Read-only |
| Config file I/O | Scoped to the configured working path |
Sync state
A background watcher polls git status and reports one of four states, so you always know whether your tree is still rebased on the remote:
State | Meaning | Action |
|---|---|---|
| Working tree matches the remote | — |
| Uncommitted or unpushed local edits | Apply to push |
| The remote has moved ahead | Pull or rebase before pushing |
| Local and remote have both moved | Rebase. Force-push only with the explicit confirmation, and only when you are certain the remote commits are disposable. |
The badge refetches every 60 seconds.
Authentication
SSH — keys are used via
ssh-agentfrom the Rust side. No private key material is read into the webview.HTTPS — credentials follow the same keychain path as Dataplane API tokens.
Instance configuration
A GitOps instance adds four fields on top of the standard instance fields: repository URL, branch, auth scheme, and the working path (clone destination on disk).
Round-trip fidelity
The parse and assemble halves are inverses, so a config that goes out through GitOps and comes back through the graph is byte-stable. This is tested directly — see Spec coverage gate.
The property that makes GitOps mode safe on a real config is that unmodelled directives survive. Sections the app does not understand — custom userlist, resolvers, peers, Lua loads — are preserved verbatim. A GitOps apply will not delete configuration the team wrote by hand just because there is no widget for it.
Practical notes
GitOps mode does not reload HAProxy. Something has to consume the commit — your pipeline, an Ansible run, a sidecar. If you want the Dataplane apply path as well, use both: GitOps for the audit trail, live apply for the running instance.
Commit and push are separate from the diff and validation steps, which still run. An invalid config fails locally before a commit is created.