This is sort of a revival and elaboration of some of Bram’s ideas from Codeville, an earlier effort that dates back to the early 2000s Cambrian explosion of DVCS.
Codeville also used a weave for storage and merge, a concept that originated with SCCS (and thence into Teamware and BitKeeper).
Codeville predates the introduction of CRDTs by almost a decade, and at least on the face of it the two concepts seem like a natural fit.
It was always kind of difficult to argue that weaves produced unambiguously better merge results (and more limited conflicts) than the more heuristically driven approaches of git, Mercurial, et al, because the edit histories required to produce test cases were difficult (at least for me) to reason about.
I like that Bram hasn’t let go of the problem, and is still trying out new ideas in the space.
In 2007 Bram said to me that my Causal Tree algorithm is a variant of weave. Which is broadly correct. In these 20 years, the family of weave-class algos grew quite big. In my 2020 article, I devoted the intro to making their family portrait https://arxiv.org/abs/2002.09511 Could have been a separate article.
The whole point of using a proper CRDT is that it's easy to reason about what it does. It took me a while to figure out the details of how to build one.
This seems like an excellent idea. I'm sure a lot of us have been idly wondering why CRDTs aren't used for VCS for some time, so it's really cool to see someone take a stab at it! We really do need an improvement over git; the question is how to overcome network effects.
Is it a good thing to have merges that never fail? Often a merge failure indicates a semantic conflict, not just "two changes in the same place". You want to be aware of and forced to manually deal with such cases.
I assume the proposed system addresses it somehow but I don't see it in my quick read of this.
Probably depends on what is in the merge. Lately I've been collaborating a ton on PRDs and software specs in markdown (now that agents have gotten pretty good at turning it into usable code) and using git had been pretty painful. Especially when working with a domain expert whose not as technical, git is proving to almost be more of a barrier than an aid.
For this kind of work (which I suspect will only get more common), a CRDT-based VCS makes a lot of sense.
Yes and no. Most often conflicts could have been handled automatically with better tools. For example I have a script that makes a copy of the whole folder and tries to merge each commit using all of git’s different merge stategies, and all sub stategies, and presents which ones can merge without any conflicts. It has been mind opening. Why git doesn’t have this built-in I don’t understand.
Git also writes (non-logs) to the .git folder for operations that you would assume should have been r/o, but that’s another problem (that affects things later on).
> Conflicts are informative, not blocking. ... Conflicts are surfaced for review when concurrent edits happen “too near” each other, but they never block the merge itself.
This thing is really short. https://github.com/bramcohen/manyana/blob/main/manyana.py is 473 lines of dependency-free Python (that file only imports difflib, itertools and inspect) and of that ~240 lines are implementation and the rest are tests.
The joke is there in the name. It is wrong (on purpose): it should be "Mañana". That term means "tomorrow" in your Spanish class, but it can mean "later/future/morning" or even "later this afternoon".
In English, you might think of "procrastination" or "we'll get to it."
In Portuguese, you would say "proxima semana", literally "next week", but it means "we'll get to it" (won't get to it).
Interesting idea. While conflicts can be improved, I personally don't see it as a critical challenge with VCS.
What I do think is the critical challenge (particularly with Git) is scalability.
Size of repository & rate of change of repositories are starting to push limits of git, and I think this needs revisited across the server, client & wire protocols.
What exactly, I don't know. :). But I do know that in my current role (mid-size well-known tech company) is hitting these limits today.
My issue with git is handling non-text files, which is a common issue with game development. git-lfs is okay but it has some tricky quirks, and you end up with lots of bloat, and you can't merge. I don't really have an answer to how to improve it, but it would be nice if there was some innovation in that area too.
I think something like this needs to be born out of analysis of gradations of scales of teams using version control systems.
- What kind of problems do 1 person, 10 person, 100 person, 1k (etc) teams really run into with managing merge conflicts?
- What do teams of 1, 10, 100, 1k, etc care the most about?
- How does the modern "agent explosion" potentially affect this?
For example, my experience working in the 1-100 regime tells me that, for the most part, the kind of merge conflict being presented here is resolved by assigning subtrees of code to specific teams. For the large part, merge conflicts don't happen, because teams coordinate (in sprints) to make orthogonal changes, and long-running stale branches are discouraged.
However, if we start to mix in agents, a 100 person team could quickly jump into a 1000 person team, esp if each person is using subagents making micro commits.
It's an interesting idea definitely, but without real-world data, it kind of feels like this is just delivering a solution without a clear problem to assign it to. Like, yes merge-conflicts are a bummer, but they happen infrequently enough that it doesn't break your heart.
Also, we need personas! Sally the developer, Mark the UX designer, Taylor the manager. Also, we need to build a community, with the help of evangelists!
> How does the modern "agent explosion" potentially affect this?
This changes everything. Agents don't really care what versioning software is used. They can probably figure out whatever you are using. But they'll likely assume it's something standard (i.e. Git) so the easiest is to not get too adventurous. Also, the reasons to use something else mostly boil down to user friendliness and new merge strategies. However, lately I just tell codex to pull and deal with merge conflicts. It's not something I have to do manually anymore. That removes a key reason for me to be experimenting with alternative version control systems. It's not that big of a problem anymore.
Git was actually designed for massive teams (the Linux kernel) but you have to be a bit disciplined using it in a way that many users in smaller teams just aren't. With agentic coding tools, you can just codify what you want to happen in guardrails and skills. Including how to deal with version control and what process to follow.
Where more advanced merge strategies could be helpful is the type of large scale refactoring that are now much easier with agentic coding tools. But doing that in repositories with lots of developers working on other changes is not something that should happen very often. And certainly not without a lot of planning and coordination probably.
starts with “based on the fundamentally sound approach of using CRDTs for version control”. How on earth is crdt a sound base for a version control system? This makes no sense fundamentally, you need to reach a consistent state that is what you intended not what some crdt decided and jj shows you can do that also without blocking on merges but with first level conflicts that need to be resolved. ai and language aware merge drivers are helping so much here i really wonder if the world these “replace version control” projects were made for still exists at all.
In case the name doesn't jump out at you, this is Bram Cohen, inventory of Bittorrent. And Chia proof-of-storage (probably better descriptions available) cryptocurrency. https://en.wikipedia.org/wiki/Bram_Cohen
It's not the same as capturing it, but I would also note that there are a wide wide variety of ways to get 3-way merges / 3 way diffs from git too. One semi-recent submission (2022 discussing a 2017) discussed diff3 and has some excellent comments (https://news.ycombinator.com/item?id=31075608), including a fantastic incredibly wide ranging round up of merge tools (https://www.eseth.org/2020/mergetools.html).
The thing about how merges are presented seems orthogonal to how to represent history. I also hate the default in git, but that is why I just use p4merge as a merge tool and get a proper 4-pane merge tool (left, right, common base, merged result) which shows everything needed to figure out why there is a conflict and how to resolve it. I don't understand why you need to switch out the VCS to fix that issue.
> I don't understand why you need to switch out the VCS to fix that issue.
For some reason, when it comes to this subject, most people don't think about the problem as much as they think they've thought about it.
I recently listened to an episode on a well-liked and respected podcast featuring a guest there to talk about version control systems—including their own new one they were there to promote—and what factors make their industry different from other subfields of software development, and why a new approach to version control was needed. They came across as thoughtful but exasperated with the status quo and brought up issues worthy of consideration while mostly sticking to high-level claims. But after something like a half hour or 45 minutes into the episode, as they were preparing to descend from the high level and get into the nitty gritty of their new VCS, they made an offhand comment contrasting its abilities with Git's, referencing Git's approach/design wrt how it "stores diffs" between revisions of a file. I was bowled over.
For someone to be in that position and not have done even a cursory amount of research before embarking on a months (years) long project to design, implement, and then go on the talk circuit to present their VCS really highlighted that the familiar strain of NIH is still alive, even in the current era where it's become a norm for people to be downright resistant to writing a couple dozen lines of code themselves if there is no existing package to import from NPM/Cargo/PyPI/whatever that purports to solve the problem.
I often find myself using the gitlens in vscode, to do something similar. I'd compare the working tree to the common base. Then I have the left pane with what's already in the base, the right pane is editable with the result in it.
It's nice to have all the LSP features available too while editing.
There isn't. Git plumbing is elastic enough that you could have way different workflows built on top of it and still have repo that is usable by other tools.
Hell, git tools themselves offer a ton of customization, you can have both display and diff command different than the builtin very easily.
Some of Git defaults and command syntax might suck but all of that can be fixed without touching repo format
See vim-mergetool[1]. I use it to manage merge conflicts and it's quite intuitive. I've resolved conflicts that other people didn't even want to touch.
It sounds interesting but the main selling point doesn’t really reasonate:
If you haven’t resolved conflicts then it probably doesn’t compile and of course tests won’t pass, so I don’t see any point in publishing that change? Maybe the commit is useful as a temporary state locally, but that seems of limited use?
Nowadays I’d ask a coding agent to figure out how to rebase a local branch to the latest published version before sending a pull request.
This is a reasonable reaction — pretty sure I felt the same way when I heard about jujutsu's first-class conflicts[0] — but it turns out to be really useful not to be stuck inside an aberrant state while conflicts are in the process of being resolved.
In git if you, say, do some `git rebase -i`, edit some commit, continue the rebase, and hit a conflict, and realize you edited something wrong that caused the conflict, your only option is aborting the entire rebase and starting over and rebuilding all changes you did.
In jj, you just have a descending conflict, and if you edit the past to no longer conflict the conflict disappears; kinda as if you were always in interactive rebase but at all points have the knowledge of what future would look like if you `git rebase --continue`d.
Also really nice for reordering commits which can result in conflicts, but leaves descendants non-conflicting, allowing delaying resolving the conflicts after doing other stuff, or continuing doing some reordering instead of always starting from scratch as with `git rebase -i`.
Nearly every time I see a complaint about git, someone comes through with a command like this. Is there a collection of similar tips that makes git better to use? If not, there should be.
You can think of the semantics (i.e., specification) of any CRDT as a function that inputs the operation history DAG and outputs the resulting user-facing state. However, algorithms and implementations usually have a more programmatic description, like "here is a function `(internal state, new operation) -> new internal state`", both for efficiency (update speed; storing less info than the full history) and because DAGs are hard to reason about. But you do see the function-of-history approach in the paper "Pure Operation-Based Replicated Data Types" [1].
Jujutsu honestly is the future IMO, it already does what you have outlined but solved in a different way with merges, it'll let you merge but outline you have conflicts that need to be resolved for instance.
It's been amazing watching it grow over the last few years.
Or treat the head commit as just a scratch space and the one before it as equivalent to git staged index, and use `jj squash PATH`, `jj squash -i` etc to "stage" things, or directly `jj commit -m "foo" PATHS` (or -i) to make a new commit with just wanted changed. This is what I do.
A suggestion : is there any info to provide in diffs that is faster to parse than "left" and "right" ? Can the system have enough data to print "bob@foo.bar changed this" ?
This is a really interesting and well thought out idea, especially the way it turns conflicts into something informative instead of blocking. The improved conflict display alone makes it much easier to understand what actually happened. I think using CRDTs to guarantee merges always succeed while still keeping useful history feels like a strong direction for version control. Looks like a solid concept!
doesn't the side by side view in github diff solve this?
conflict free merging sounds cool, but doesn't that just mean that that a human review step is replaced by "changes become intervals rather than collections of lines" and "last set of intervals always wins"? seems like it makes sense when the conflicts are resolved instantaneously during live editing but does it still make sense with one shot code merges over long intervals of time? today's systems are "get the patch right" and then "get the merge right"... can automatic intervalization be trusted?
edit: actually really interesting if you think about it. crdts have been proven with character at a time edits and use of the mouse select tool.... these are inherently intervalized (select) or easy (character at a time). how does it work for larger patches can have loads of small edits?
139 comments
[ 5.1 ms ] story [ 122 ms ] threadCodeville also used a weave for storage and merge, a concept that originated with SCCS (and thence into Teamware and BitKeeper).
Codeville predates the introduction of CRDTs by almost a decade, and at least on the face of it the two concepts seem like a natural fit.
It was always kind of difficult to argue that weaves produced unambiguously better merge results (and more limited conflicts) than the more heuristically driven approaches of git, Mercurial, et al, because the edit histories required to produce test cases were difficult (at least for me) to reason about.
I like that Bram hasn’t let go of the problem, and is still trying out new ideas in the space.
> ... CRDTs for version control, which is long overdue but hasn’t happened yet
Pijul happened and it has hundreds - perhaps thousands - of hours of real expert developer's toil put in it.
Not that Bram is not one of those, but the post reads like you all know what.
I assume the proposed system addresses it somehow but I don't see it in my quick read of this.
For this kind of work (which I suspect will only get more common), a CRDT-based VCS makes a lot of sense.
Git also writes (non-logs) to the .git folder for operations that you would assume should have been r/o, but that’s another problem (that affects things later on).
So conflicts are still surfaced for review.
In English, you might think of "procrastination" or "we'll get to it."
In Portuguese, you would say "proxima semana", literally "next week", but it means "we'll get to it" (won't get to it).
What I do think is the critical challenge (particularly with Git) is scalability.
Size of repository & rate of change of repositories are starting to push limits of git, and I think this needs revisited across the server, client & wire protocols.
What exactly, I don't know. :). But I do know that in my current role (mid-size well-known tech company) is hitting these limits today.
Is it because of a monorepo?
- What kind of problems do 1 person, 10 person, 100 person, 1k (etc) teams really run into with managing merge conflicts?
- What do teams of 1, 10, 100, 1k, etc care the most about?
- How does the modern "agent explosion" potentially affect this?
For example, my experience working in the 1-100 regime tells me that, for the most part, the kind of merge conflict being presented here is resolved by assigning subtrees of code to specific teams. For the large part, merge conflicts don't happen, because teams coordinate (in sprints) to make orthogonal changes, and long-running stale branches are discouraged.
However, if we start to mix in agents, a 100 person team could quickly jump into a 1000 person team, esp if each person is using subagents making micro commits.
It's an interesting idea definitely, but without real-world data, it kind of feels like this is just delivering a solution without a clear problem to assign it to. Like, yes merge-conflicts are a bummer, but they happen infrequently enough that it doesn't break your heart.
> What do teams of 1, 10, 100, 1k, etc care the most about?
Oh god no! That would be about the worst way to do it.
Just make it conceptually sound.
This changes everything. Agents don't really care what versioning software is used. They can probably figure out whatever you are using. But they'll likely assume it's something standard (i.e. Git) so the easiest is to not get too adventurous. Also, the reasons to use something else mostly boil down to user friendliness and new merge strategies. However, lately I just tell codex to pull and deal with merge conflicts. It's not something I have to do manually anymore. That removes a key reason for me to be experimenting with alternative version control systems. It's not that big of a problem anymore.
Git was actually designed for massive teams (the Linux kernel) but you have to be a bit disciplined using it in a way that many users in smaller teams just aren't. With agentic coding tools, you can just codify what you want to happen in guardrails and skills. Including how to deal with version control and what process to follow.
Where more advanced merge strategies could be helpful is the type of large scale refactoring that are now much easier with agentic coding tools. But doing that in repositories with lots of developers working on other changes is not something that should happen very often. And certainly not without a lot of planning and coordination probably.
It's not the same as capturing it, but I would also note that there are a wide wide variety of ways to get 3-way merges / 3 way diffs from git too. One semi-recent submission (2022 discussing a 2017) discussed diff3 and has some excellent comments (https://news.ycombinator.com/item?id=31075608), including a fantastic incredibly wide ranging round up of merge tools (https://www.eseth.org/2020/mergetools.html).
However/alas git 2.35's (2022) fabulous zdiff3 doesn't seems to have any big discussions. Other links welcome but perhaps https://neg4n.dev/blog/understanding-zealous-diff3-style-git...? It works excellently for me; enthusiastically recommended!
For some reason, when it comes to this subject, most people don't think about the problem as much as they think they've thought about it.
I recently listened to an episode on a well-liked and respected podcast featuring a guest there to talk about version control systems—including their own new one they were there to promote—and what factors make their industry different from other subfields of software development, and why a new approach to version control was needed. They came across as thoughtful but exasperated with the status quo and brought up issues worthy of consideration while mostly sticking to high-level claims. But after something like a half hour or 45 minutes into the episode, as they were preparing to descend from the high level and get into the nitty gritty of their new VCS, they made an offhand comment contrasting its abilities with Git's, referencing Git's approach/design wrt how it "stores diffs" between revisions of a file. I was bowled over.
For someone to be in that position and not have done even a cursory amount of research before embarking on a months (years) long project to design, implement, and then go on the talk circuit to present their VCS really highlighted that the familiar strain of NIH is still alive, even in the current era where it's become a norm for people to be downright resistant to writing a couple dozen lines of code themselves if there is no existing package to import from NPM/Cargo/PyPI/whatever that purports to solve the problem.
Perhaps the value of doing it on SCM level is that it can remember what you did. Git has some not-so-nice edge cases.
It's nice to have all the LSP features available too while editing.
This is all good advice, but these days I just ask Claude for solving merge conflicts, and I can't remember it ever going wrong.
Almost all merge conflicts I see in practice are fairly mechanically solved.
Hell, git tools themselves offer a ton of customization, you can have both display and diff command different than the builtin very easily.
Some of Git defaults and command syntax might suck but all of that can be fixed without touching repo format
[1]: https://github.com/samoshkin/vim-mergetool
If you haven’t resolved conflicts then it probably doesn’t compile and of course tests won’t pass, so I don’t see any point in publishing that change? Maybe the commit is useful as a temporary state locally, but that seems of limited use?
Nowadays I’d ask a coding agent to figure out how to rebase a local branch to the latest published version before sending a pull request.
[0]: https://docs.jj-vcs.dev/latest/conflicts/
In jj, you just have a descending conflict, and if you edit the past to no longer conflict the conflict disappears; kinda as if you were always in interactive rebase but at all points have the knowledge of what future would look like if you `git rebase --continue`d.
Also really nice for reordering commits which can result in conflicts, but leaves descendants non-conflicting, allowing delaying resolving the conflicts after doing other stuff, or continuing doing some reordering instead of always starting from scratch as with `git rebase -i`.
Nearly every time I see a complaint about git, someone comes through with a command like this. Is there a collection of similar tips that makes git better to use? If not, there should be.
Well, isn't that what the CRDT does in its own data structure ?
Also keep in mind that syntactic correctness doesn't mean functional correctness.
[1] https://arxiv.org/abs/1710.04469
It's been amazing watching it grow over the last few years.
Or treat the head commit as just a scratch space and the one before it as equivalent to git staged index, and use `jj squash PATH`, `jj squash -i` etc to "stage" things, or directly `jj commit -m "foo" PATHS` (or -i) to make a new commit with just wanted changed. This is what I do.
conflict free merging sounds cool, but doesn't that just mean that that a human review step is replaced by "changes become intervals rather than collections of lines" and "last set of intervals always wins"? seems like it makes sense when the conflicts are resolved instantaneously during live editing but does it still make sense with one shot code merges over long intervals of time? today's systems are "get the patch right" and then "get the merge right"... can automatic intervalization be trusted?
edit: actually really interesting if you think about it. crdts have been proven with character at a time edits and use of the mouse select tool.... these are inherently intervalized (select) or easy (character at a time). how does it work for larger patches can have loads of small edits?
Funny, there was just a post a couple of days ago how this is false.
https://news.ycombinator.com/item?id=47359712