Fork repositories #9
Why
To be open-source ready, users must fork any repo they can read into their own namespace, hack on it, and open merge requests back. Core collaboration primitive — blocker for external contributors.
What
Add "Fork" action on the repository page. Forking creates a new repo under the actor's namespace that:
- Copies all git refs (branches + tags) from the source bare repo.
- Records a fork relationship (parent repo id) so the UI can show "forked from
owner/name". - Defaults visibility to source visibility (public source → public fork); never expose a private source through a fork.
- Is owned/writable by the forking user.
Scope
- Model:
parent_repo_id(nullable FK) on the repository table + Flyway migration. - Storage: server-side clone of the bare repo (local object copy, not full re-fetch over the network).
- UI: Fork button on repo header; fork picker if user already has a fork; "forked from …" link on forked repos.
- MR integration: merge requests can target the parent repo from a fork branch (cross-repo MR). May be split into a follow-up.
- MCP/API:
forkRepository(owner, name)endpoint mirroringcreateRepository. - Docs:
docs/users/(fork workflow),docs/admins/(any new storage/config),docs/maintainers/(fork relationship + storage design).
Out of scope
- Fork syncing / "update from upstream" — separate issue.
- Fork network graph visualization.
Acceptance
- [ ] User forks a public repo → new repo in their namespace with all refs.
- [ ] Fork page shows "forked from
owner/name". - [ ] Private source cannot be forked to a public repo by a non-authorized user.
- [ ] Failing test first, green after implementation.
- [ ] Docs updated in the same PR.