Git won. That is undisputed. But “won” doesn’t mean “perfect” - and in recent years more and more tools have appeared that address exactly the corners that Git has been hitting for decades: confusing staging areas, merge conflicts that block your entire workflow, a history that feels like it’s carved in instead of being designed.
Most of these tools take the same approach as Git: decentralized, every client has a complete copy of the history. Pogo does the opposite. It is a centralized version control system - a server is the only source of truth, clients work against it. At first it sounds like a step back to SVN times. But it’s not quite, because Pogo brings modern concepts with it: modifiable changes instead of rigid commits, conflicts that don’t block your workflow, and a branching model completely without naming requirements.
Let’s take a look at what’s behind the idea and whether the centralized approach might be worth it for you.
Centralized instead of decentralized: A conscious step backwards?
With Git, every developer has the complete history locally. That’s powerful, but it also brings with it overhead: you have to pull, push, take care of remotes and, if in doubt, juggle several “truths” that only come together through a merge.
Pogo turns that around. There is exactly one server that holds your data - your single source of truth. The client is deliberately kept simple: a CLI that talks to the server, plus a slim web UI for browsing the repositories. You deploy the server yourself, for example with Docker:
docker pull ghcr.io/pogo-vcs/pogo:alpine
Behind it is a PostgreSQL database, the configuration is carried out entirely via environment variables such as DATABASE_URL or PUBLIC_ADDRESS. No ceremony, no additional software – a container, a database, done.
The trade-off is obvious: without a connection to the server, you can’t push or sync history. For an open source project with hundreds of contributors around the globe, this is a show-stopper. For a team that is already online all the time and has never cared about offline capability, it’s just… one less thing to worry about. You don’t need to manage remotes, synchronize forks, or ask yourself “who has the current main now”. There is only one place where the truth lies.
Changes statt Commits: Mutable History
The second big break with Git habits: Pogo doesn’t know commits, only changes. The difference is more than semantics. A Git commit is immutable (apart from --amend) - once committed, it remains as it is. A pogo change, on the other hand, is a living container for your work that you can overwrite as often as you like until you say, “This change is finished.”
The workflow is that you first describe what you want to do and then code it:
# Repository initialisieren und mit dem Server verbinden
cd my-project
pogo init --name my-project --server your-server.com:8080
# Bevor du irgendetwas programmierst: beschreiben, was du vorhast
pogo describe --message "feat: add initial project structure"
# Jetzt normal arbeiten
echo "# My Project" > README.md
mkdir src
echo "console.log('Hello, Pogo!');" > src/index.js
# Änderungen zum Server schicken
pogo push
What happens here: pogo push keeps overwriting the same change until you explicitly call pogo new to start a new one. There is no git add, no staging area, no “oops, I forgot to add the file”. You describe your intention (ideally as a conventional commit message), work, push - and can sharpen the description at any time if your plan changes during work:
pogo describe --message "feat: add initial project structure and config loader"
There is one restriction: Once a change has children or is referenced by a bookmark, you can no longer overwrite it. From then on it is fixed - just like a Git commit that has already been pushed. This makes sense: Once others build on your work, the ground beneath their feet can no longer shift.
No named branches, just bookmarks
In Git, a branch is a moving pointer with a name that you need to remember (and maintain): feature/login, hotfix/payment-bug, release/2.1. Pogo completely dispenses with this concept.
Instead: Each change can have any number of child changes. If you create two children of the same change, you actually have two branches - just without a name. Each change automatically gets a unique, randomly generated ID (Base32 encoded, deliberately without confusing characters such as l, 1, I or 0, O):
pogo log
● KPHRpdJnwyPcLH4a
│ hi, pogo
○ DKJbFrEkyhLpnCm3
│ merge
○─┤ RJcALPmeLceea4hL
│ │ hello, pogo
│ ╰─○ wEpaCJnAELNrDFyk
│ │ hi, world
╰─○─╯ hfEJKLREKxhDfK4b
hello, world
If you want to merge two branches, simply create a new change with several parents - the merge is done. There is no separate “merge commit” type like in Git, it is simply a change with more than one predecessor.
There are bookmarks so that you don’t have to constantly juggle cryptic IDs. A bookmark is a named pointer to a specific change - basically what a branch name would be in Git, only deliberately decoupled from the history:
pogo bookmark set main
main is not a reserved word, but a convention: Pogo treats a bookmark named main in a similar way to how Git treats the default branch. For releases, simply set additional bookmarks like v1.0.0. The result: You get the clarity of named branches without having to commit to a naming scheme before you even know whether the branch will live long.
First-Class Conflicts: Conflicts are not a show-stopper
This is probably Pogo’s most unusual feature. In Git - and in almost every VCS actually - a merge conflict is a hard brake. You cannot continue working, committing, or pushing until the conflict is resolved. It is precisely this compulsion that causes stress: conflicts are often resolved hastily, in the middle of the day, just to finally get ahead.
Pogo treats conflicts as first-class citizens. You can push a change with unresolved conflicts, others can access it, join in the discussion or even work on resolving it yourself. The conflict doesn’t block anything - it is simply a state that a change can assume, such as “done” or “in progress”.
Text conflicts look as usual:
<<<<<<<<< change1
hello, pogo
=========
hi, world
>>>>>>>>> change2
The difference with Git: These markers don’t end up in your working directory while you frantically search for the right version, but in a separate merge change that you can edit at your leisure - now, later, or ask someone else to do it. In the ‘pogo log’, a 💥 symbol marks every change with open conflicts so that nothing goes silently.
There is also a pragmatic solution for binary files: Instead of an impossible merge attempt, you get both files, renamed and clearly marked which change they come from. You then decide manually which one stays.
Important caveat: Pogo only detects textual and binary conflicts - not semantic ones. If two changes independently change a function signature and the code merges cleanly but crashes at runtime, Pogo won’t notice anything. That remains the task of your tests.
Getting started with Pogo
Enough theory – this is how you actually get started.
Install client
The easiest way is to use Homebrew (macOS/Linux):
brew install pogo-vcs/tap/pogo
Alternatively via npm if you are in a node ecosystem anyway:
npm install -g @pogo-vcs/pogo
For Windows there is Pogo via Scoop:
scoop bucket add pogo-vcs https://github.com/pogo-vcs/scoop-bucket.git
scoop install pogo
Set up server
Fastest with Docker. You also need a PostgreSQL database:
docker pull ghcr.io/pogo-vcs/pogo:alpine
When you start it for the first time, the server automatically creates a root user including a personal access token and issues it once on the console - remember it immediately, because it will no longer be displayed afterwards. Also, don’t forget to install a reverse proxy with an SSL certificate if you want the server to be publicly accessible.
Erstes Repository
# Repository initialisieren und mit dem Server verbinden
cd my-project
pogo init --name my-project --server your-server.com:8080
# Mit dem Personal Access Token einloggen, wenn du danach gefragt wirst
pogo whoami
# Beschreiben, was du vorhast
pogo describe --message "feat: initial project setup"
# Arbeiten wie gewohnt
echo "# My Project" > README.md
# Änderungen an den Server schicken
pogo push
# Aktuellen Stand als "main" markieren
pogo bookmark set main
So you go through the entire cycle once: initialize, describe, work, push, mark. You can get an overview of your history at any time with ‘pogo log’.
Pro Tips/Warnings
Warning: Pogo is a young project. The community is small, the documentation is still growing, and you’ll probably come across rough edges that Git has long since smoothed over. This is an exciting experiment for a side project or an internal tool - for your most important production repo, I would currently wait until the project has settled down a bit.
Important: Pogo does not speak Git format and is not Git compatible. The change is a conscious cut, not a gentle transition on the side. You can’t just run
pogoalongside your existing.gitdirectory and migrate gradually - you choose a repository.
Tip: If you develop in Go, it’s worth taking a second look: Pogo repositories can be imported directly as Go modules, without any additional configuration or tools. For Go monorepos or internal libraries this can save quite a bit of boilerplate.
Warning: Remember the reverse proxy when setting up the server. Pogo automatically detects whether HTTPS is available and otherwise falls back to HTTP - but “fallback” here explicitly means: unencrypted. Without TLS in front of it, your personal access token ends up on the line in plain text.
Conclusion
Pogo is not a Git killer and doesn’t want to be. It’s an alternative for teams that never really needed the distributed nature of Git, but still suffered from its rough edges - the staging area, the blocking merge conflicts, the naming requirement for branches. With mutable changes, first-class conflicts and bookmarks instead of rigid branches, Pogo does things differently without becoming complicated.
The price for this is centralization: no offline work without a server, no fork-and-pull model like open source projects on GitHub, no Git interop for a smooth transition. For a small team with its own server and constant connection, this can be a feature instead of a bug: one truth, no synchronization issues, a CLI without baggage.
Whether Pogo will prevail in the long term remains to be seen - the project is still too young for that. But the idea of treating conflict as a normal state rather than as a show-stopper is worth looking into, whether you end up with Pogo or just get inspiration from it for your own Git workflow.
![[EN] Pogo: The VCS that consciously goes back to the central server](/images/pogo-vcs-BlogHeader.jpeg)