Skip to main content
RunBook Academy

Git, CI/CD & GitOpsCIII · Infrastructure Repository Anti-PatternsAntiPatterns

Direct production pushes — bypassing the merge gate

Intermediate⏱ ~25 mingit

What you'll learn

  • Identify the four ways an engineer can push to the default branch without a pull request
  • Explain why direct pushes break the audit chain that GitOps and CI depend on
  • Distinguish emergency-bypass procedures from routine direct pushes and document the difference
  • Configure branch protection, signed commits, and CI checks so that direct pushes are rejected

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

A direct push to the default branch is the infrastructure equivalent of an unlogged root login. The change lands. The cluster reconciles to it. Production runs the new code. The only thing missing is the chain of evidence that explains why.

Four shapes the violation takes

The anti-pattern is rarely an explicit policy violation. It is almost always one of four working habits:

  • Force-push with --no-verify. A push that bypasses pre-push hooks and overwrites the remote default branch.
  • git push origin HEAD:main. A direct push to the protected branch the forge should refuse but does not.
  • Merge via the API without a PR. A platform that allows merge commits or file edits through its API, bypassing the pull-request workflow.
  • “Hotfix” branch with auto-merge. A long-lived branch with branch protection requiring one approval but no CODEOWNERS rule and no required CI checks.
flowchart LR
    A["force-push --no-verify"] --> D["direct push to main"]
    B["git push origin HEAD:main"] --> D
    C["merge via API"] --> D
    E["hotfix branch auto-merge"] --> D
    D --> F["no PR"]
    D --> G["no review"]
    D --> H["no CI"]
    D --> I["no signed commit"]

All four produce the same outcome.

Why the audit chain breaks

The audit chain that GitOps, CI, and incident reconstruction rely on is built from four links:

  • A pull request. Where the change is described and where reviewers are assigned.
  • A CI run. Where the change is built, tested, scanned, and signed.
  • A merge event. Where the change is integrated under branch protection, after required status checks and owner approvals.
  • A signed commit. Binding the change to the engineer’s identity.

A direct push removes all four. The commit is on the default branch, but the PR is empty, the CI run is missing, the merge was a git push instead of a forge-mediated event, and the signature is whatever the engineer’s local Git config produced.

The cost six months later

An incident reconstruction needs four answers:

  • Who authored the change? The commit author field is present, but the PR author and the merge author may differ.
  • What did the change do? The diff is present, but the intent lives in the PR description and conversation.
  • Why was the change approved? The approval lives in the PR review thread, with rationale and resolved comments.
  • Was the change tested? The CI run log, the test report, the security scan, and the signed artifact all live in the CI system keyed by the PR.

A direct push leaves the diff and the author. The rest of the audit chain is empty.

What the alternative looks like

The discipline has three parts:

  • Branch protection rejects direct pushes. The default branch has “Do not allow direct pushes” enforced. The forge returns a 403 on git push origin HEAD:main and points the engineer at the pull-request workflow.
  • Required status checks must pass before merge. CI runs plan, lint, scan, and test jobs. The merge button is disabled until each required check is green.
  • CODEOWNERS + required reviewers. A list of owners for every path, with branch protection requiring their approval.

The hotfix path is not a direct push. It is a documented procedure that opens a pull request with a label, requests the platform team’s review, and runs through the same CI gates.

Production discipline

  1. The default branch refuses direct pushes. Branch protection is configured to reject them with a 403 and a message pointing at the pull-request workflow.
  2. The hotfix path is a pull request with an expedited review rotation. Not a direct push.
  3. Required status checks gate every merge. Plan, lint, scan, test - each is required; none is advisory.
  4. Commits are signed. Signed commits are the only way to tie a commit to an identity without trusting local Git config.

Cross-course references

  • This course, Part XXXII (BranchProtection) covers the direct-push restriction and required reviewers.
  • This course, Part XXXIII (Signing) covers commit and tag signing, key custody, and verification.
  • This course, Part XXX (PullRequests) covers the pull-request workflow that direct pushes bypass.
  • This course, Part LXXXVII (IncidentGitOps) covers break-glass procedures reconciled back into the repository.

Quiz

Knowledge check · 4 questions

  1. Q1. An engineer force-pushes a hotfix to the default branch to unblock production. The change is correct and the incident is closed. What has been lost?

  2. Q2. Branch protection that requires two approvals before merge is not sufficient to prevent direct pushes to the default branch.

  3. Q3. Name the four links in the audit chain that a direct push breaks, and identify the link that is the most expensive to reconstruct after the fact.

  4. Q4. Diagnose an incident reconstruction failure caused by a direct push, and recommend the discipline that prevents it.

    Six months after a credential-rotation incident, the security team needs to reconstruct why the IAM policy was changed. The commit is on main, the author is known, but the change was pushed directly to main with --no-verify during a hotfix. There is no pull request, no CI run, and no merge event in the audit log. The team needs to know who approved the change, which CI tests ran, and what the rationale was.

Passing score: 75%. Answers are checked in this browser.