Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXCVIII · Git Hosting FailureGitHostingFail

Local bare repository fallback — the last resort

Advanced⏱ ~24 mingit

What you'll learn

  • Bootstrap a local bare repository with git init --bare as the last-resort fallback
  • Push the canonical state into the local bare repo from a clone that has it
  • Serve the bare repo over SSH or local filesystem for engineer pushes during a complete outage
  • Recognise the limits of the local fallback: single-region, no web UI, no pull-request workflow
  • Distinguish the local-bare-recovery pattern from the mirror pattern (read-only) and the self-hosted fallback (full forge)

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.

The local bare repository is the last-resort fallback when the canonical remote and the mirror are both unreachable. It is not a forge replacement - there is no web UI, no pull-request workflow, no CI integration - but it is a place to land commits when every other endpoint is down. The bare repository is bootstrapped on a host the team controls, populated from a clone that has the canonical state, and served over SSH or the local filesystem so engineers can push to it.

# Bootstrap the local bare repo
git init --bare /srv/git/infra.git

# Push the canonical state from a clone that has it
cd ~/infra
git remote add local file:///srv/git/infra.git
git push --all local
git push --tags local

The bare repo is a plain Git directory. There is no daemon required for local filesystem access; engineers push via file:///srv/git/infra.git or via SSH if the repo is on a remote host.

flowchart LR
    A["canonical remote\nunreachable"] --> B["clone with canonical state"]
    B --> C["git push --all local\ngit push --tags local"]
    C --> D["bare repo on /srv/git/infra.git"]
    D --> E["engineer pushes to bare repo\nvia file:// or SSH"]
    D --> F["CI runs against bare repo\nvia file:// or SSH"]
    G["canonical recovers"] --> H["push bare repo state back to canonical"]

When the local bare is the right primitive

The local bare is the right primitive in two scenarios. First, the canonical and the mirror are both unreachable - a multi-region outage has taken down the forge and the mirror region, and the local bare is the only place to push. Second, the team needs to land commits during a planned outage - a maintenance window has the canonical in read-only mode and the local bare is the staging ground.

In both cases, the bare repo is the staging area. The canonical is the long-term home; the bare repo is the intermediate landing site until the canonical recovers.

# Bootstrap a bare repo from scratch (no clone)
git init --bare /srv/git/infra.git

# Bootstrap with state from an existing clone
git clone --bare ~/infra /srv/git/infra.git

git clone --bare is the alternative to git init --bare when a clone already exists; both produce a bare directory with the objects, refs, and HEAD. --bare from a clone copies the local state; git init --bare starts empty.

Serving the bare repo

The bare repo is reachable over three transports:

  1. Local filesystem (file:///srv/git/infra.git). The simplest transport; works only when the engineer or CI runner is on the same host.
  2. SSH (user@host:/srv/git/infra.git). The standard transport for cross-host access; the engineer authenticates with an SSH key.
  3. Smart HTTP (requires git-http-backend or a tool like Gitea, covered in Part XCVIII-05). The bare repo itself does not serve HTTP; a webserver with CGI or a dedicated tool is required.

For the last-resort fallback, SSH is the right transport. The team’s SSH keys are already provisioned; the bare repo lives on a bastion host; engineers push over SSH from any host that can reach the bastion.

# Push to the bare repo over SSH
git remote add local user@bastion.internal:/srv/git/infra.git
git push --all local
git push --tags local

The remote name local is convention; the role is determined by the URL pattern. A production script identifies the local bare by URL hostname or path, not by name.

The limits of the local fallback

The local bare is the last resort precisely because it lacks everything a forge provides:

  • No web UI. Engineers cannot browse the repository, open pull requests, or review diffs in a browser. The fallback is CLI-only.
  • No pull-request workflow. The bare repo accepts pushes but does not enforce reviews. Engineers push directly to main if they need to.
  • No CI integration. The bare repo has no webhook, no status checks, no merge queue. CI must be configured separately to poll or fetch from the bare repo.
  • Single-region. The bare repo lives on one host. A regional outage of the host takes the bare repo with it.
  • No audit trail beyond Git. The bare repo’s audit trail is the Git history itself; there is no PR-level record of who approved what.

These limits are why the local bare is the last resort, not the first. A team that relies on the local bare for normal operation is a team that has lost the production discipline of the pull-request workflow.

From local bare back to canonical

The recovery sequence when the canonical recovers:

  1. Engineers stop pushing to the bare repo. A status broadcast announces the canonical is back.
  2. The on-call engineer pushes the bare repo’s state to the canonical. git push --all canonical and git push --tags canonical from a clone that has the bare repo’s state.
  3. CI runs against the canonical again. The CDN flip (Part XCVIII-03) is reversed; the canonical URL is back as origin.
  4. The bare repo is decommissioned. A status broadcast confirms the bare repo is no longer the canonical landing site.

The push-back step is the highest-risk moment. A bare repo that has been pushed to directly to main may have commits that conflict with the canonical’s main. The push-back has to be a merge or a force-push, depending on the discipline the team followed during the outage.

# Push-back from bare repo to canonical
cd ~/infra
git remote add bare file:///srv/git/infra.git
git fetch bare
git merge --no-ff bare/main
git push origin main

The --no-ff merge preserves the bare-repo commits as a distinct merge commit; the canonical’s history shows the recovery.

Production discipline

  1. The local bare is the last resort, not the first. The mirror (Part XCVIII-03) and the multi-remote failover (Part XCVIII-02) come first.
  2. Bootstrap from a clone with git clone --bare, not from git init --bare followed by a manual copy. The clone preserves the refs and the config.
  3. Serve over SSH, not the local filesystem. SSH gives cross-host access; the local filesystem is single-host.
  4. Push the bare repo’s state back to the canonical as soon as the canonical recovers. The bare repo is the staging ground, not the canonical.
  5. Rehearse the bare-repo recovery quarterly. The drill catches the push-back step’s risks.

Cross-course references

  • Git, CI/CD & GitOps — Part XCVIII-02 (Multi-Remote Failover) is the engineer-side counterpart this lesson’s bare repo complements.
  • Git, CI/CD & GitOps — Part XCVIII-05 (Self-Hosted Git as Fallback) is the next step up from the local bare: a full forge with a web UI.
  • Linux for Production Sysadmins — Part XXXVII (ServiceHardening) covers the SSH hardening this lesson’s bare repo serves through.

Quiz

Knowledge check · 4 questions

  1. Q1. The canonical remote and the team's mirror are both unreachable. The team needs a place to land commits. What is the right primitive?

  2. Q2. A local bare repository created with `git init --bare` provides a full forge replacement, including a web UI, pull-request workflow, and CI integration.

  3. Q3. Explain why the local bare repository is described as 'the staging ground, not the canonical', and what the team must do when the canonical remote recovers.

  4. Q4. Diagnose the recovery gap and recommend the push-back sequence.

    A team has used a local bare repository on a bastion host as the last-resort fallback during a multi-region outage. Engineers pushed directly to `main` on the bare repo during the outage because there was no time for a pull-request workflow. The canonical recovers after eight hours. The bare repo's `main` has 14 commits ahead of the canonical's `main`. The team's audit trail must show who pushed what during the outage.

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