Pijul, better version control

Pijul is built on a mathematically sound theory of patches. It is fast, composable, and correct by construction.

Why look beyond Git?

Git is very successful, and for good reasons.

But success does not always mean that every design decision was the best, or that things can't be further improved on.

I accept that version control is complex. That's why we need tools. However, I want the tool make the easy things easier and the complex things simpler, instead of just "making things possible"!

With Git, I suffer. Rebasing, unecessary merge conflicts, or the distinction between commits and the changes. They all add friction, and it seems to be imposed by the tool itself, not by the unavoidable nature of version control itself.

I am not alone in thinking that, that is why there are still new version control tools being worked on. I can't say I have looked at all of them, but here are two that I have checked out:

  • Jujutsu seems to focus on simplifying some of the classic Git "gotchas". It was designed to remain git-compatible.
  • Pijul is a different angle: changes are first-class objects. Rather than treating history primarily as a sequence of snapshots, it is designed around patches and the dependencies between them. Pijul was inspired by Darcs, is written in Rust and self-hosted (i.e. version controlled in Pijul).

A different model of change

An interesting feature is composability. Independent changes can be combined without requiring everyone to agree on one privileged linear history. That is quite nice when work naturally happens in parallel.

Why is this interesting?

I am less interested in version control as "a collection of commands" than as "a model for collaborative work". Or course, there are marginal improvements if cleaning up the syntax of commands or streamlining the expression of version control operations into commands (this seems to be what Jujutsu is doing?). However the more fundamental difference with Pijul is conceptual:

  • Is a patch-based theory a better deal?
  • Can we reduce the number of conflicts rather than only provide different or slightly easier commands to resolve them?

Pijul is really looking promising, check out the "Why pijul" and the "See it in action" sections on the Pijul front page, they really hit hard and pinpoint exactly the opportunity!

Of course, there is also a practical question. A better model is only useful if it can coexist with the great ecosystem built around Git. History is full of tools that were "better on paper" but failed to gain much adoption (Betamax anyone?). That makes Pijul's interoperability with Git at least as important as its underlying theory.

Here is a kind of mind map I start with:

Topic \ Tool Git Jujutsu Pijul
Fundamental object Commit/snapshot Change + snapshot Patch/change
History Graph of commits Graph of changes/commits Dependencies between patches
Working copy Special state outside history Always a commit Working tree relative to recorded changes
Branches First-class refs Mostly just names/bookmarks Channels
Merge Merge commits / 3-way merge Merge commits/change graph Apply/compose patches
Rebase Important operation Much less important Largely unnecessary
Conflict Merge state in working tree Conflicts can be recorded in commits Conflicts are part of repository state
Git compatibility Native Excellent No
Mathematical change model No No Yes

A word on Channels

Formally, a channel is simply a pointer to a set of patches or changes.

  • There is always a default main channel in every repository.
  • You can list channels with pijul channel, create a new one with pijul fork <name> or pijul channel new <name>, and switch between them using pijul channel switch <name>.

Key and interesting differences from Git Branches:

  • Commuting Changes: In Pijul, independent changes commute, meaning their order does not matter. Because of this mathematical property, you often do not need to create a separate channel for things you would use a Git branch for.
  • Same Rebase and Merge: A change's identity does not depend on the channel it resides on. Rebase and merge are fundamentally the same operation.
  • Persistent Conflict Resolution: Conflicts happen between changes rather than branches or line numbers. Resolving a conflict on one channel automatically solves that same conflict across all other channels, eliminating the recurrence of solved merge conflicts. (Are you getting interested now? If you've been using git… you probably are!)

Experimenting further

For now, I want to explore to see if it works and feels better. I will try to use Pijul on some personal projects and compare the day-to-day workflow with Git, especially around parallel changes and publishing repositories.