- Web canonical:
/{namespace}/{repository}. - Git HTTP:
/{namespace}/{repository}.git/info/refs,git-upload-pack, andgit-receive-pack. - SSH:
ssh://git@host:port/{namespace}/{repository}.git. - Legacy
/git/{project}[.git],/Repository/..., no-suffix Git remotes, and retained alias addresses are not routed and return not found. - Slugs use ordinal, invariant uppercase normalization for uniqueness. Original casing is retained for display.
- A slug starts with an ASCII letter, contains only ASCII letters, digits,
.,_, or-, has 2-50 characters, and cannot end in.git. - Reserved root slugs are
account,api,assets,git,health,home,identity,legacy,repository,setting,signin-oidc,signout-callback-oidc, andteam.
StableNamespaces performs the following provider-specific backfill before creating final indexes and foreign keys:
- Creates the reserved
legacynamespace and system route claims. - Creates one stable namespace for every Identity user and team.
- Copies existing team names into
DisplayNameand repository names into immutableStorageName. - Assigns each repository to the lexically first
IsOwneruser namespace. Ownerless metadata remains underlegacy. - Creates current repository claims and explicit legacy mappings without moving repository directories.
The migration intentionally fails if a user name, team name, active claim, or reserved route conflicts case-insensitively. Back up the database and repository/cache roots first, then resolve conflicts before retrying. Do not edit the migration to auto-suffix public names.
GitCandy:Namespaces:AliasRetentionDaysdefaults to365.RenameLimitdefaults to3successful user/team slug changes inRenameWindowDays=7rolling days.- Failed, conflicting, and administrator override changes do not consume normal quota.
- Serializable transactions, a namespace version concurrency token, and unique claim keys protect concurrent changes.
- Aliases point directly to stable namespace/repository IDs. Cleanup removes expired claims idempotently; administrators can extend active aliases with an audit reason.
- Repository create/list/detail and code-browser navigation only generate canonical namespace URLs. Legacy and retained alias addresses return not found without redirecting.
- Git HTTP and LFS only accept the canonical
.gitendpoint. RPC bodies remain streamed. - OpenSSH and the built-in listener only accept current namespace/repository paths; legacy and alias paths are rejected before authorization and transport startup.
- Deleting a repository converts its active claims to reserved tombstones before deleting metadata and storage, preventing immediate name reuse.
- SQLite migration and model:
GitCandy.Data.Tests, including three-success/fourth-blocked quota, reserved/occupied failures, expiry idempotence, direct alias resolution, and concurrent final-quota requests. - SQL Server: offline idempotent migration SQL contains all namespace/alias/claim/event tables, composite unique indexes, backfill SQL, and stable-ID foreign keys.
- Web: canonical rendering, canonical link, private-resource authorization, and 404 responses for legacy and alias routes.
- Git HTTP/LFS: real protocol v2 canonical
.gitclone/fetch/push/LFS, authenticated push, 24 MiB pack streaming, and 404 responses for legacy, alias, and no-suffix remotes. - SSH: real current namespace/repository clone/fetch/push with the shared resolver, permission query, path resolver, and transport backend; legacy and alias commands are rejected before transport execution.
The migration does not rename physical repository directories, so repository data remains usable by the previous application. Database rollback is not an online compatibility operation: stop GitCandy, restore the pre-M10 database backup, deploy the previous application package, and verify Web login plus Git HTTP/SSH clone/fetch/push. Do not apply the generated Down migration to a live database after users have renamed namespaces because it discards alias and audit history and restores global repository-name uniqueness.