Skip to content
GhostbranchdocsGitHub

Set up a repo

Run ghostbranch init once for each public repo, to create or adopt its private shadow repo and guard your checkout.

Each machine you work from needs it too: on a second machine, you adopt the shadow repo the first one made. Run it in a clone of the public repo, so Ghostbranch can read the repo’s name from origin and guard that checkout.

  • The shadow repo: a private copy of your public repo, named <repo>-shadow unless you choose another name. Your private feature branches live there, and its CI runs on them.
  • The overlay branch: a branch called ghostbranch in the shadow repo. It holds the settings file .ghostbranch.yml and becomes the shadow repo’s default branch. Nothing on it is ever published.
  • The push guard, if you want it: a git hook in your checkout that refuses to push feature work to the public repo by mistake.

init never writes to the public repo. If it stops partway, run it again and it carries on from where it stopped.

Terminal window
cd project
ghostbranch init

Run at a terminal, it asks only what it can’t work out on its own. Press Enter to take the suggestion in brackets:

  1. “Which public repo should get private branches? (owner/repo)”: filled in from origin.
  2. “No GitHub login found. Log in with GitHub now?”: only if you haven’t logged in.
  3. “Create the private repo you/project-shadow to hold your private branches (the shadow repo)?”
  4. “Install the push guard in this checkout? It refuses pushes of feature work to the public repo.” The default is yes.
  5. “Turn on scheduled sync? A workflow in the shadow repo then syncs it every 6 hours (about 120 Actions minutes a month).” The default is no.

For a repo that belongs to an organization, question 3 asks where the shadow repo should live instead: in the organization, so teammates can use it; in your own account, so only you can; or under another name, or an existing repo to adopt.

Then it shows exactly what it will change and asks “Make these changes now?”. Once you say yes, it sets up the pair, installs the guard, runs ghostbranch doctor, and ends with the commands for your first feature.

Each question has a flag, and --yes takes the defaults for the rest. With --json, --non-interactive or --yes, init never asks anything, which is how scripts and agents run it.

Flag What it answers
<owner/repo> The public repo, as the first argument.
--shadow <owner/name> The shadow repo’s name, if not <owner/repo>-shadow.
--adopt Take over a shadow repo that already exists, instead of creating one.
--guard, --no-guard Install the push guard in this checkout, or don’t.
--sync, --no-sync Turn on scheduled sync, or leave it off.
--plan Show what would change, and change nothing.

Use --adopt when the shadow repo is already there:

  • You set up this repo on another machine. Adopting only registers the pair on this one and checks the shadow repo.
  • Your token may not create repos. Create an empty private repo on GitHub yourself, give the token access to it, then adopt it.
Terminal window
ghostbranch init you/project --adopt --plan
ghostbranch init you/project --adopt

The shadow repo has to be private, and either empty or a mirror of the public repo. init refuses one that holds anything else.

This is a real init --adopt run, with the names changed. The shadow repo had been created by hand first. init mirrored the public main into it, created the overlay branch and made it the default, and audited the CI. The repo had no workflows yet, so the audit found nothing to fix. These are its two warnings, with its progress and result lines left out:

Terminal
ghostbranch init you/project --adopt
setup progress and the result left out
warning: you/project is private; Ghostbranch is meant for public repos
warning: you/project-shadow is private, so its Actions minutes are billed
  • PUBLIC_NOT_PUBLIC: the “public” repo was still private, as it was before its launch. Ghostbranch is meant for public repos, so check you named the right one. It still works on a private repo.
  • ACTIONS_MINUTES_BILLED: GitHub bills the Actions minutes of a private repo to its owner, and the shadow repo is always private. Nothing needs doing. Scheduled sync adds to the bill, which is why it’s off unless you turn it on.

Its last step suggested the push guard. That step is yours to run, never an agent’s.

If you skipped the guard during init, install it in your checkout of the public repo:

Terminal window
ghostbranch guard install

It adds a pre-push hook. When you git push feature work to the public repo by mistake, the hook refuses, and nothing is sent. An existing pre-push hook keeps running after it. ghostbranch guard status says whether it’s installed, and ghostbranch guard install --plan shows what it would change.

Run ghostbranch doctor inside the checkout. Now that there’s a pair, it checks all six things:

Terminal
ghostbranch doctor
✓ tools git 2.51.0; ghostbranch v0.0.0-20261012143300-b5fd1e633402, commit b5fd1e633402
✓ token the app token from login works, as you; can publish to you/project: true; it has every permission the commands need
! pair you/project (public) and you/project-shadow (private) are reachable, and the overlay and its config are valid; you/project is private; Ghostbranch is meant for public repos
✓ guard the push guard is installed in /home/you/project, current, and guards every remote at the public repo
✓ state workspace "default"; the records are readable, none is newer than this binary, and no gate job has been pending for over an hour
✓ ci 0 repo guard(s) the gate rewrites; secret names not checked (no workflow uses one, or the token can't list them); no workflow runs on sync's pushes
update check: off (development build)

The ! on pair is the same private-repo warning as above. With a public repo, every check passes.

The ci line summarizes the CI audit. Run ghostbranch audit for the whole report: what keeps the shadow repo’s CI from matching the public repo’s, such as jobs that skip outside the public repo, or secrets the shadow repo lacks.