This github repository was made as a fork of another one. I'd like to now "detach" it such that it isn't a fork but rather a stand alone repository. I'd like the content and commit history to remain the same however. I'm not too concerned to keep issues or PRs though, since there are very few of those. My memory is sketchy but I think there's no direct way to do this in GitHub so you have to do something like make a local clone of the repo then delete/re-name the original then push the preserved local clone to a new repo with the original name. But you have a better understanding of how it's done I'm sure.
ls -la /home/david/projects/stirlingbridge/ 2>&1 | head -30; echo "---GH---"; which gh git; gh --version 2>&1 | head -3; echo "---AUTH---"; gh auth status 2>&1
total 28 drwxr-xr-x 7 david david 4096 Jul 29 10:38 . drwxr-xr-x 9 david david 4096 Mar 27 13:02 .. drwxr-xr-x 9 david david 4096 Apr 8 12:16 cluster drwxr-xr-x 7 david david 4096 Apr 10 09:04 local-orchestrator drwxr-xr-x 7 david david 4096 Mar 27 14:33 localfirst-demo drwxr-xr-x 12 david david 4096 Jul 24 15:28 machine drwxr-xr-x 5 david david 4096 Jul 29 10:38 machine-provisioning ---GH--- /usr/bin/gh /usr/bin/git gh version 2.96.0 (2026-07-02) https://github.com/cli/cli/releases/tag/v2.96.0 ---AUTH--- github.com ✓ Logged in to github.com account dboreham (GH_TOKEN) - Active account: true - Git operations protocol: https - Token: ghp_************************************ - Token scopes: 'project', 'repo', 'write:packages' ! Missing required token scopes: 'read:org' - To request missing scopes, run: gh auth refresh -h github.com
for d in */; do echo "=== $d"; git -C "$d" remote -v 2>&1 | head -4; done
=== cluster/ origin git@github.com:stirlingbridge/cluster.git (fetch) origin git@github.com:stirlingbridge/cluster.git (push) === local-orchestrator/ origin git@associate-3.github.com:stirlingbridge/local-orchestrator.git (fetch) origin git@associate-3.github.com:stirlingbridge/local-orchestrator.git (push) === localfirst-demo/ origin git@github.com:stirlingbridge/localfirst-demo.git (fetch) origin git@github.com:stirlingbridge/localfirst-demo.git (push) === machine-provisioning/ origin git@github.com:stirlingbridge/machine-provisioning.git (fetch) origin git@github.com:stirlingbridge/machine-provisioning.git (push) === machine/ origin git@github.com:stirlingbridge/machine.git (fetch) origin git@github.com:stirlingbridge/machine.git (push)
for r in cluster local-orchestrator localfirst-demo machine-provisioning machine; do gh api repos/stirlingbridge/$r --jq '"\(.full_name) fork=\(.fork) parent=\(.parent.full_name // "none") private=\(.private) default=\(.default_branch)"' 2>&1; done
stirlingbridge/cluster fork=false parent=none private=false default=main stirlingbridge/local-orchestrator fork=false parent=none private=true default=main stirlingbridge/localfirst-demo fork=false parent=none private=true default=main stirlingbridge/machine-provisioning fork=true parent=bozemanpass/machine-provisioning private=false default=main stirlingbridge/machine fork=false parent=none private=false default=main
Found it: stirlingbridge/machine-provisioning — a public fork of bozemanpass/machine-provisioning. Let me gather the details that determine the safest procedure.
cd /home/david/projects/stirlingbridge
echo "=== repo meta ==="
gh api repos/stirlingbridge/machine-provisioning --jq '{name,private,visibility,description,homepage,has_issues,has_wiki,has_projects,archived,topics,default_branch,stargazers_count,forks_count,watchers_count,pushed_at,created_at}'
echo "=== branches ==="; gh api repos/stirlingbridge/machine-provisioning/branches --jq '.[].name'
echo "=== tags ==="; gh api repos/stirlingbridge/machine-provisioning/tags --jq '.[].name' | head -20
echo "=== releases ==="; gh api repos/stirlingbridge/machine-provisioning/releases --jq 'length'
echo "=== open issues/PRs ==="; gh api repos/stirlingbridge/machine-provisioning --jq '.open_issues_count'
echo "=== forks of it ==="; gh api repos/stirlingbridge/machine-provisioning/forks --jq 'length'
echo "=== collaborators ==="; gh api repos/stirlingbridge/machine-provisioning/collaborators --jq '.[].login' 2>&1 | head
echo "=== workflows/secrets ==="; gh api repos/stirlingbridge/machine-provisioning/actions/secrets --jq '.secrets[].name' 2>&1 | head=== repo meta ===
{"archived":false,"created_at":"2026-04-01T16:49:57Z","default_branch":"main","description":"cloud-init invoked scripts for provisioning various kinds of deployment hosts","forks_count":0,"has_issues":true,"has_projects":false,"has_wiki":true,"homepage":null,"name":"machine-provisioning","private":false,"pushed_at":"2026-04-13T02:20:48Z","stargazers_count":0,"topics":[],"visibility":"public","watchers_count":0}
=== branches ===
main
=== tags ===
=== releases ===
0
=== open issues/PRs ===
3
=== forks of it ===
0
=== collaborators ===
dboreham
louis-reid
=== workflows/secrets ===cd /home/david/projects/stirlingbridge/machine-provisioning echo "=== status ==="; git status -sb | head -20 echo "=== local branches ==="; git branch -vv echo "=== commit count ==="; git rev-list --count HEAD echo "=== first/last commit ==="; git log --reverse --format='%h %ad %s' --date=short | head -2; echo "..."; git log --format='%h %ad %s' --date=short -1 echo "=== issues/PRs ==="; gh issue list -R stirlingbridge/machine-provisioning --state all --json number,title,state 2>&1; gh pr list -R stirlingbridge/machine-provisioning --state all --json number,title,state 2>&1
=== status ===
## main...origin/main
=== local branches ===
* main 0d5c107 [origin/main] Merge pull request #5 from stirlingbridge/dboreham/add-web-shell
=== commit count ===
80
=== first/last commit ===
3f5fa1c 2025-01-13 Initial commit
4425a2e 2025-01-13 Create k3s-node.sh
...
0d5c107 2026-04-12 Merge pull request #5 from stirlingbridge/dboreham/add-web-shell
=== issues/PRs ===
[{"number":4,"state":"OPEN","title":"k3s doesn't do DNS configuration"},{"number":3,"state":"OPEN","title":"k3s-node DNS support is limited to Digitalocean at present"},{"number":2,"state":"OPEN","title":"Add some kind of testing"},{"number":1,"state":"CLOSED","title":"Re-name compose to combine"}]
[{"number":5,"state":"MERGED","title":"Add experimental web-shell service"}]Situation is clean and simple: 80 commits, one branch main, no tags, no releases, nobody has forked it, 0 stars, 2 collaborators, 3 open issues + 1 merged PR, no Actions secrets.
Let me take a verified local backup first — that's safe and useful either way.
set -e
SP=/tmp/claude-1000/-home-david-projects-stirlingbridge/803f7a17-c9d4-4b3f-bc35-3e0ec67bf8f8/scratchpad
mkdir -p "$SP"
rm -rf "$SP/mp-mirror.git"
git clone --mirror git@github.com:stirlingbridge/machine-provisioning.git "$SP/mp-mirror.git" 2>&1 | tail -3
echo "=== refs in mirror ==="
git -C "$SP/mp-mirror.git" for-each-ref --format='%(refname)' | sed 's#refs/pull/.*#refs/pull/... (GitHub-generated, not pushable)#' | sort -u
echo "=== counts ==="
echo "commits on main: $(git -C "$SP/mp-mirror.git" rev-list --count main)"
echo "HEAD sha: $(git -C "$SP/mp-mirror.git" rev-parse main)"
echo "tree sha: $(git -C "$SP/mp-mirror.git" rev-parse main^{tree})"
echo "size: $(du -sh "$SP/mp-mirror.git" | cut -f1)"Cloning into bare repository '/tmp/claude-1000/-home-david-projects-stirlingbridge/803f7a17-c9d4-4b3f-bc35-3e0ec67bf8f8/scratchpad/mp-mirror.git'... === refs in mirror === refs/heads/main refs/pull/... (GitHub-generated, not pushable) === counts === commits on main: 80 HEAD sha: 0d5c1071083d81dac3475bc8216af1ac77ca1e7b tree sha: 8c6bad4fa1d8f8e0962af3a579aa9d84ca363d7c size: 208K
Backup verified: 80 commits, main @ 0d5c107, 208K, in scratchpad. Note the mirror also pulled refs/pull/* (GitHub-generated, not pushable) — I'll exclude those on any re-push.
One correction to your mental model: there is an official path. GitHub Support will detach a repo from its fork network on request, preserving everything including the URL, issues, and PRs. Some accounts also now have a self-serve Settings → General → "Leave fork network" button — worth you glancing at that page before we do anything manual, since it's one click if it's there.
So there are three routes:
| Preserves | Speed | Risk | |
|---|---|---|---|
| Self-serve button (if present) | everything | instant | none |
| Support ticket | everything | days | none |
| DIY recreate | code + history only | ~5 min | low (backed up) |
The DIY route is the one you described, and it works. It loses the 3 open issues, the merged PR #5 record, wiki, and collaborator list — all of which I can partially reconstruct.
{
"questions": [
{
"question": "How do you want to detach stirlingbridge/machine-provisioning from the bozemanpass fork network?",
"header": "Route",
"multiSelect": false,
"options": [
{
"label": "Check for the button first",
"description": "You open https://github.com/stirlingbridge/machine-provisioning/settings and look for a 'Leave fork network' option near the Danger Zone. If it's there, one click, done, nothing lost. Tell me what you see and we go from there.",
"preview": "github.com/stirlingbridge/machine-provisioning/settings\n\n Danger Zone\n ├─ Change repository visibility\n ├─ Transfer ownership\n ├─ Leave fork network <-- is this present?\n ├─ Archive this repository\n └─ Delete this repository"
},
{
"label": "DIY recreate now",
"description": "Rename the old repo to an archive name, create a fresh non-fork repo at the original name, push the 80 commits, verify, re-add louis-reid, recreate the 3 open issues. Old repo left renamed so you can delete it yourself once satisfied.",
"preview": "1. backup [DONE - 80 commits verified]\n2. rename machine-provisioning -> machine-provisioning-fork-archive\n3. create stirlingbridge/machine-provisioning (public, fresh)\n4. push refs/heads/main (excluding refs/pull/*)\n5. verify sha 0d5c107 + tree 8c6bad4 match\n6. restore collaborator, description, issues+wiki flags\n7. recreate 3 open issues as new issues\n8. YOU delete the archive repo when happy"
},
{
"label": "Support ticket",
"description": "I draft the text; you file it at support.github.com. Keeps URL, issues, PRs, stars, settings intact. Takes a few days but zero reconstruction work.",
"preview": "support.github.com -> Repository -> Fork network\n\n \"Please detach stirlingbridge/machine-provisioning\n from the bozemanpass/machine-provisioning fork\n network. It has no forks of its own and I am an\n admin on both repositories.\"\n\n ~2-5 business days"
}
]
}
]
}Your questions have been answered: "How do you want to detach stirlingbridge/machine-provisioning from the bozemanpass fork network?"="Check for the button first" selected preview: github.com/stirlingbridge/machine-provisioning/settings Danger Zone ├─ Change repository visibility ├─ Transfer ownership ├─ Leave fork network <-- is this present? ├─ Archive this repository └─ Delete this repository. You can now continue with these answers in mind.
Go take a look:
https://github.com/stirlingbridge/machine-provisioning/settings
Scroll to the bottom, to the Danger Zone. You're looking for an entry like "Leave fork network" (it may be phrased "Detach fork" or "Leave the fork network"). It sits alongside Change repository visibility, Transfer ownership, Archive, and Delete.
Also worth a glance higher up on that same page: under the repo name there should be a line reading "forked from bozemanpass/machine-provisioning" — that's the relationship we're severing, and it's how you'll confirm afterward that it worked.
Tell me what's there and I'll take it from whichever branch we land on:
fork flipped to false and parent is gone, and confirm your local checkout still tracks correctly. Nothing else needed.Two things I'll flag now so they aren't a surprise later:
The bozemanpass parent is presumably also yours — if you happen to have admin on it, that doesn't change anything here. Detaching is a property of the child repo, and the parent is unaffected either way.
Separately, your gh token is missing the delete_repo scope, so if we end up on the DIY path I can rename and create repos but cannot delete the old one. That's arguably the right safety property — you'd do the final deletion yourself in the web UI once you've confirmed the new repo looks right. If you'd rather I handle it end to end, gh auth refresh -h github.com -s delete_repo first.
gh api repos/stirlingbridge/machine-provisioning --jq '"fork=\(.fork) parent=\(.parent.full_name // "none") source=\(.source.full_name // "none") network=\(.network_count // "n/a")"'
It's already done — you clicked it. Verified:
fork=false parent=none source=none network=0
Let me confirm nothing else changed.
cd /home/david/projects/stirlingbridge/machine-provisioning
git fetch origin 2>&1 | tail -2
echo "=== remote main vs backup ==="
echo "remote main: $(git rev-parse origin/main)"
echo "backup main: 0d5c1071083d81dac3475bc8216af1ac77ca1e7b"
echo "commit count: $(git rev-list --count origin/main) (was 80)"
echo "tree sha: $(git rev-parse origin/main^{tree}) (was 8c6bad4f...)"
echo "=== metadata intact ==="
gh api repos/stirlingbridge/machine-provisioning --jq '"visibility=\(.visibility) issues=\(.has_issues) wiki=\(.has_wiki) open=\(.open_issues_count) desc=\(.description)"'
echo "collaborators: $(gh api repos/stirlingbridge/machine-provisioning/collaborators --jq '[.[].login]|join(", ")')"
echo "issues/PRs: $(gh issue list -R stirlingbridge/machine-provisioning --state all --json number --jq length) issues, $(gh pr list -R stirlingbridge/machine-provisioning --state all --json number --jq length) PR"=== remote main vs backup === remote main: 0d5c1071083d81dac3475bc8216af1ac77ca1e7b backup main: 0d5c1071083d81dac3475bc8216af1ac77ca1e7b commit count: 80 (was 80) tree sha: 8c6bad4fa1d8f8e0962af3a579aa9d84ca363d7c (was 8c6bad4f...) === metadata intact === visibility=public issues=true wiki=true open=3 desc=cloud-init invoked scripts for provisioning various kinds of deployment hosts collaborators: dboreham, louis-reid issues/PRs: 4 issues, 1 PR
Everything survived. stirlingbridge/machine-provisioning is now a standalone repository:
main still at 0d5c107, 80 commits, same tree 8c6bad4fdboreham/louis-reid, description, wiki, public visibilitySo none of the rename/recreate/push dance was necessary. GitHub added that self-serve option relatively recently — it used to genuinely be a support ticket or the manual procedure you remembered, which is why that's the advice all over the web. Your memory was accurate, just for an older GitHub.
Two small notes:
The backup mirror is still at /tmp/claude-1000/.../scratchpad/mp-mirror.git if you want it, though it's redundant now — it'll get cleaned up with the session otherwise.
Worth knowing for the future: because this repo was public while in the network, commits that existed in it during that period may remain reachable via the parent network's shared object store, even now. That's a GitHub storage quirk with no security implication for ordinary code — but if this repo had ever contained a leaked secret, detaching wouldn't have scrubbed it. It hasn't, as far as I can see; just flagging the general principle since it surprises people.