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.
What init sets up
Section titled “What init sets up”- The shadow repo: a private copy of your public repo, named
<repo>-shadowunless you choose another name. Your private feature branches live there, and its CI runs on them. - The overlay branch: a branch called
ghostbranchin the shadow repo. It holds the settings file.ghostbranch.ymland 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.
Run init
Section titled “Run init”cd projectghostbranch initRun at a terminal, it asks only what it can’t work out on its own. Press Enter to take the suggestion in brackets:
- “Which public repo should get private branches? (owner/repo)”: filled in from
origin. - “No GitHub login found. Log in with GitHub now?”: only if you haven’t logged in.
- “Create the private repo you/project-shadow to hold your private branches (the shadow repo)?”
- “Install the push guard in this checkout? It refuses pushes of feature work to the public repo.” The default is yes.
- “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.
Answer with flags instead
Section titled “Answer with flags instead”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. |
Adopt a shadow repo that already exists
Section titled “Adopt a shadow repo that already exists”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.
ghostbranch init you/project --adopt --planghostbranch init you/project --adoptThe shadow repo has to be private, and either empty or a mirror of the public repo. init refuses one that holds anything else.
A real setup
Section titled “A real setup”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:
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.
Install the push guard
Section titled “Install the push guard”If you skipped the guard during init, install it in your checkout of the public repo:
ghostbranch guard installIt 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.
Check the setup
Section titled “Check the setup”Run ghostbranch doctor inside the checkout. Now that there’s a pair, it checks all six things:
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.