Once upon a time
A long time ago, I wrote an article about all the trouble involved in handling several Git providers.
This reflection led me to imagine my own tool, [Ansicolt], which was initially a basic proof of concept: a simple justfile/bash wrapper on top of gh, glab, and git.
I was already aware of tools like gita for managing multiple repositories, but they did not fully cover my needs.
So, what exactly was missing?
The Specs
What did I want?
At first, the requirements were quite simple:
- Handle several Git providers.
- Handle several accounts and identities.
- Work with both HTTPS and SSH.
- Clone and create repositories without having to remember provider-specific commands.
- Manage group of repositories from one place.
- Keep using the standard
gitcommand for normal Git operations. - Add some abstraction around provider APIs without trying to replace Git itself.
Over time, the scope naturally became a little larger, with things such as workspaces, repository synchronization, mirroring, releases, and self-hosted providers.
The Tools Out There
Provider CLIs: gh, glab, and tea
The obvious tools are the provider-specific CLIs. ghfor Github, glab for Gitlab and tea for Gitea and Forgejo. Those tools are very powerful and cover most provider-specific operations.
The hassle start when working with several providers, you have to remember which command , which arguments belongs to which ecosystem. You may end up switching between them. while still using git itself for repository operations.
Each tool is good at what it does, but your workflow becomes fragmented. Add to equation that those tools have there limitations, and you have a good reason to search for a new tool.
The Independent Projects
Of course, I am not the first one to face the problem of managing repositories spread across different providers.
There are several independent projects trying to add another abstraction layer on top of Git and provider APIs.
Hyperforge takes a declarative approach to multi-forge repository management.
It can manage repositories across GitHub, GitLab, and Codeberg, with the idea of having an origin and eventually mirrors on other forges.
Coco goes further than repository management.
It provides a Git terminal workstation with AI-assisted commits, reviews, and changelogs, but it also abstracts some forge operations.
It detects the remote provider and can use gh for GitHub, glab for GitLab, or APIs for some other forges.
Gitfleet tries to provide a provider-neutral CLI for GitHub and GitLab.
Instead of remembering which command belongs to gh or glab, the idea is to expose a common vocabulary for repositories, issues, pipelines, releases, and other provider operations.
RepoBee was designed for teachers and teaching assistants managing a large number of student repositories. It supports GitHub, GitLab, and Gitea.
Still, the underlying problem is familiar: performing the same operations across tens or hundreds of repositories without having to manage each one manually.
ghq focuses more on organizing local repositories. It maps clones into paths such as ~/ghq/github.com/user/project.
mani lets you declare a set of repositories and work across them. It can synchronize a declared repository collection and execute commands across all projects.
gita — not to be confused with Gitea, which is a Git hosting platform — focuses on local multi-repository orchestration. If I remember correctly, it is written in Python. It helps manage several local repositories, but it does not try to abstract the forge itself.
Those projects have different goals, but they illustrate the same thing: as soon as you start working with several Git providers and a large number of repositories, git alone no longer covers the whole workflow.
So at least I know one thing:
I am not the only one struggling with this problem.
To Summarize
So what should we use? The original tools such as git, gh, glab, and tea? One of the already existing independent projects? Or yet another custom tool?
The different projects do not solve exactly the same problem.
A very simplified view could look like this:
1 Local repos Forge APIs Identity/Auth
2 │ │ │
3ghq / mani / gita ────● │ │
4 │
5gh / glab / tea ●──────────────────● ●
6 │
7git-profile │ │ ●
8 │
9Gitfleet │──────────────────● ●
10 │
11Hyperforge ●──────────────────●──────────────────●
12 │
13Colt ●──────────────────●──────────────────●
14 + lifecycle / mirroring / self-hosting / Sync
This is obviously not a complete feature comparison. It is more a way to visualize where each project puts its abstraction layer:
Some tools focus on local repositories.
Some focus on provider APIs.
Some focus on identities and authentication.
Some try to cover several of those areas at once.
Which brings me back to my own Colt.
Finally, My Colt
At this point, the obvious question is: Did I reinvent the wheel?
Probably, at least partially. Many of the individual problems I wanted to solve already had their own tools. But I did not find a single one that matched exactly the workflow I wanted.
So sometimes, it is worth reinventing your own wheel, and this is where Colt eventually found its place.
There is also the learning path to consider.
This project took me from understanding and managing Git repositories to actually building a CLI tool in Go. It was a very practical way to learn the language and to create my first command-line application using Cobra.
In that sense, even if parts of the wheel already existed, rebuilding them myself was part of the point.
Basic Usage of Colt
Before going further, let’s have a quick look at how Colt is actually used.
On Linux or macOS, Colt can be installed with:
1curl -fsSL https://raw.githubusercontent.com/MozeBaltyk/Colt/main/install.sh | bash
It can also be built directly from source:
1CGO_ENABLED=0 go build -o colt ./cmd/colt
Configure a Provider:
1colt auth login github personal \
2 --namespace my-user \
3 --git-name "My Name" \
4 --git-email me@example.com \
5 --default
Check the configured providers with:
1colt auth status
The important point is that each provider configuration can have its own Git identity, authentication, namespace, and transport (without changing my global Git configuration).
So I can have something like:
1personal -> GitHub -> personal identity
2work -> GitLab -> company identity
3internal -> Forgejo -> internal identity
Create a new repository:
1colt init my-project
Colt creates the remote repository, clones it locally, initializes it, and pushes the initial commit.
If I want to explicitly choose a provider:
1colt init my-project --provider work
I can also create a repository locally without creating anything on a forge:
1colt init my-project --local
After that, normal Git operations remain normal Git operations:
1git add .
2git commit -m "Initial implementation"
3git push
Colt does not try to replace those commands.
List and Clone Repositories:
Repositories available on a provider can be listed with:
1colt list
Or across all configured providers:
1colt list --all
A repository can then be cloned with:
1colt clone my-project
or from a specific provider:
1colt clone my-project --provider work
This is one of the basic ideas behind Colt.
Instead of remembering:
1Which forge is this?
2Which CLI should I use?
3Which account?
4Which identity?
5HTTPS or SSH?
I select the provider configuration and let Colt handle that context.
HTTPS or SSH
A provider can use either HTTPS or SSH.
For example:
1colt auth login github personal \
2 --namespace my-user \
3 --git-name "My Name" \
4 --git-email me@example.com \
5 --transport ssh
Colt does not manage SSH private keys itself.
With SSH, it relies on the existing SSH agent and configuration.
With HTTPS, authentication is handled through the configured credential mechanism without placing tokens in repository URLs.
Working With Several Providers
This becomes more useful once several providers are configured.
For example:
1colt list --provider personal
2colt list --provider work
3colt list --provider internal
Creating repositories works the same way:
1colt init website --provider personal
2colt init backend --provider work
3colt init experiment --provider internal
The command stays mostly the same.
Only the provider context changes.
That was one of the main things I wanted from the beginning.
Workspaces
Colt can also declare several repositories as a workspace. The general idea is that for Github a Workspace equal an organisation for Gitlab a workspace equal a repository group.
For example:
1workspace:
2 repositories:
3 - provider: personal
4 namespace: my-user
5
6 - provider: work
7 namespace: my-team
The current state can then be inspected with:
1colt status
And missing repositories can be cloned with:
1colt sync
There is also a dry-run mode:
1colt sync --dry-run
From simply being a provider-neutral CLI, Colt start to manage the lifecycle of a collection of repositories.
Releases
A release can also be created through Colt:
1colt release v1.0.0
Colt creates the local Git tag, pushes it, and then creates the corresponding release through the provider API.
Again, the idea is to keep the same command regardless of whether the repository is hosted on GitHub, GitLab, Gitea, or Forgejo.







