GitDot: Subgroups for Any Git Platform, Using Only Repository Names
If you keep one package per repository, you soon have a lot of repositories. MWD (Microwise Development) #1: One Repo, One Package explains why we work that way. GitDot is the tool we built for the problem it creates.
GitDot was an experiment. Its web app was shut down in October 2026, and its old documentation site and app address now point here. What lasts is the idea behind it, a naming convention that needs no tool and works anywhere.
The problem: a flat list of repositories
When you build many packages, you have two options.
- Monorepo. Every package lives in one repository. Folders give you structure for free, but all packages share one log, so per-package history needs path filters, and CI has to work out which part of the tree changed.
- Multi-repo. Each package gets its own repository, with its own history and its own releases. The separation is clean, but you now have dozens or hundreds of repositories.
For us, the second option is the better fit, but the Git hosts don’t help with the structure. On GitHub, an organization is a single flat list of repositories, with no nesting. GitLab has subgroups, but that only helps if you’re on GitLab and are happy to model everything as groups. Plenty of teams keep their code on GitHub for its visibility in open source.
The idea: put the hierarchy in the name
GitDot needs no feature from the platform. It reads the structure from the repository name, treating each dot as a folder separator.
Say an organization has these repositories:
my-org/
├── core.auth.service
├── core.auth.oauth
├── core.auth.jwt
├── api.gateway
├── api.users
└── api.orders
GitDot shows them like this:
my-org/
├── core/
│ └── auth/
│ ├── service
│ ├── oauth
│ └── jwt
└── api/
├── gateway
├── users
└── orders
Nothing is moved or migrated. The repositories stay exactly where they are on the host, and GitDot hosted nothing itself. It was a read-and-display layer on top of the platform you already use. Since the hierarchy is part of each name, it also appears in every clone URL and every reference to the repository.
We use this naming for our own repositories. MWD #1 shows our glpkg.* repositories as GitLab lists them and as GitDot shows them, and git-nested can draw a workspace as a tree using the same dotted names.
How it worked
While it ran, the GitDot web app connected to a GitHub or GitLab account (private repositories included), fetched the repositories of an organization or group, and showed them as a tree split on the dots. That’s all there was to the app. The real work is in the names.
To get the hierarchy, rename your repositories to dot notation:
- GitHub: repository Settings → change the name (for example
auth-service→auth.service). GitHub redirects the old web and Git URLs to the new name, as long as you don’t create a new repository with the old name. Still update anything that points to the old name. - GitLab: change the name under Settings → General, and the path under Settings → General → Advanced → Change path. GitLab sets up redirects from the old path.
GitHub, GitLab and Gitea all allow dots in repository names, so the naming works on any of them.
Naming conventions
The syntax is <domain>.<subdomain>.<name>, for example auth.service, auth.oauth.google or api.v2.users. What matters is picking a grouping and sticking to it. Three patterns work well:
# by domain # by layer # by feature
billing.service core.database checkout.cart
billing.webhook core.cache checkout.payment
users.service api.gateway search.indexer
users.profile web.dashboard search.query
A few rules we follow:
- Lowercase, concise names. Prefer singular nouns where they read naturally.
- Dots for hierarchy, hyphens inside a segment.
auth-serviceis one name.auth.serviceisserviceinsideauth. - Four levels at most. Deeper trees get harder to navigate than the flat list you started with.
- One pattern per organization. Mixing domain-first and layer-first names breaks the tree into two half-trees.
For versions, either put the version in the name (api.v1.users, api.v2.users) or keep one repository and use tags (api.users tagged v1.0.0, v2.0.0) and keep the names clean.
Migrating existing repositories is a rename:
| Before | After |
|---|---|
auth-service | auth.service |
user-api-v2 | api.v2.users |
frontend-dashboard | web.dashboard |
On GitLab you can combine both approaches. Use native subgroups for the top level, and dot notation inside a subgroup for finer structure.
Where GitDot stands
GitDot was an experiment we built, used and shared. The web app was shut down in October 2026. We’ve kept the source, but there are no plans to bring the app back or to build the extras we once had in mind (batch renames, group moves, a CLI, editor integrations).
The part that lasts is the naming convention. It needs no tool at all. If your repositories are named area.sub.name, the structure is in the names, and any tool, script or person reading the list can recover the tree with split("."). Our own git-nested reads the same dotted names. GitDot was just one way to see that structure.
If you use the convention, or you’ve solved the same problem differently, we’d like to hear about it in our feedback discussions.