[HN Gopher] The future of version control
       ___________________________________________________________________
        
       The future of version control
        
       Author : c17r
       Score  : 345 points
       Date   : 2026-03-22 15:16 UTC (7 hours ago)
        
 (HTM) web link (bramcohen.com)
 (TXT) w3m dump (bramcohen.com)
        
       | bos wrote:
       | 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.
        
         | dboreham wrote:
         | Note that CRDT isn't "a thing". The CRDT paper provides a way
         | to think about and analyze eventually consistent replication
         | mechanisms. So CRDTs weren't "introduced", only the "CRDT way
         | of discussing replication". Every concrete mechanism described
         | in the CRDT paper is very old, widely used for decades
         | beforehand.
         | 
         | This means that everything that implements eventual consistency
         | (including Git) is using "a CRDT".
        
           | hrmtst93837 wrote:
           | If you stretch "CRDT" to mean any old eventually consistent
           | thing, almost every Unix tool morphs into one under a loose
           | enough definition. That makes the term much less useful,
           | because practical CRDTs in 2024 usually mean opaque merge
           | semantics, awkward failure modes, and operational complexity
           | that has very little in common with the ancient algorithms
           | people point at when they say "Git is a CRDT too". "Just Git"
           | is doing a lot of work there.
        
           | mweidner wrote:
           | While this is technically correct, folks discussing CRDTs in
           | the context of text editing are typically thinking of a
           | fairly specific family of algorithms, in which each character
           | (or line) is assigned an immutable ID drawn from some
           | abstract total order. That is the sense in which the original
           | post uses the term (without mentioning a specific total
           | order).
        
         | gritzko wrote:
         | 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.
        
         | bramcohen wrote:
         | 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.
        
       | logicprog wrote:
       | 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.
        
         | righthand wrote:
         | Well over half of all people can't tell you the difference
         | between git and Github. The latter being owned by a corporation
         | that needs the network effect to keep existing.
        
         | vishvananda wrote:
         | This is actually a very interesting moment to potentially
         | overcome network effects, because more and more code is going
         | to be written by agents. If a crdt approach is measurably
         | better for merging by agent swarms then there is incentive to
         | make the switch. It also much easier to get an agent to change
         | its workflow than a human. The only tricky part is how much git
         | usage is in the training set so some careful thought would need
         | to be given to create a compatibility layer in the tooling to
         | help agents along.
        
         | NetOpWibby wrote:
         | Overcoming network effects cannot be the goal; otherwise, work
         | will never get done.
         | 
         | The goal should be to build a full spec and then build a code
         | forge and ecosystem around this. If it's truly great, adoption
         | will come. Microsoft doing a terrible job with GitHub is great
         | for new solutions.
        
       | ZoomZoomZoom wrote:
       | The key insight in the third sentence?
       | 
       | > ... 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.
        
         | simonw wrote:
         | I hadn't heard of Pijul. My first search took me to
         | https://github.com/8l/pijul which hasn't been updated in 11
         | years, but it turns out that's misleading and the official repo
         | at https://nest.pijul.com/pijul/pijul had a commit last month.
         | 
         | ... and of course it is, because Pijul uses Pijul for
         | development, not Git and GitHub!
        
           | idoubtit wrote:
           | The canonical website is https://pijul.org. The homepage has
           | a link to the pijul source repository.
        
             | ozten wrote:
             | They should mirror on GitHub for marketing purposes
        
               | nicoty wrote:
               | How would they do that if they don't use git for version
               | control? Does GitHub allow other forms of version control
               | other than git?
        
               | simonw wrote:
               | SQLite does it despite using Fossil - their mirror is at
               | https://github.com/sqlite/sqlite
               | 
               | Git is so established now that it's sensible for
               | alternative VCS to have a mode where they can imitate the
               | Git protocol - or seven without that you can still
               | checkout the latest version of your repo and git push
               | that on a periodic basis.
        
           | codethief wrote:
           | > I hadn't heard of Pijul
           | 
           | I'm surprised! Pijul has been discussed here on HN many, many
           | times. My impression is that many people here were hoping
           | that Pijul might eventually become a serious Git contender
           | but these days people seem to be more excited about Jujutsu,
           | likely because migration is much easier.
        
             | simonw wrote:
             | Looks like it makes the homepage only once or twice a year
             | (using points>50 as a proxy for that), had more buzz around
             | five years ago: https://hn.algolia.com/?dateRange=all&page=
             | 0&prefix=false&qu...
        
             | jedberg wrote:
             | I too am here all the time and have never heard of it. But
             | it looks interesting.
        
         | vova_hn2 wrote:
         | I have a weird hobby: about once a year I go to the theory page
         | [0] in pijul manual and see if they have fixed the TeX
         | formatting yet.
         | 
         | You would think that if a better, more sound model of storing
         | patches is _your whole selling point_ , you would want to make
         | as easy as possible for people who are interested in the
         | project to actually understand it. It is really _weird_ not to
         | care about the first impression that your manual makes on a
         | curious reader.
         | 
         | Currently, I'm about 6 years into the experiment.
         | 
         | Approximately 2 years in (about 4 years ago), I've actually
         | went to the Pijul Nest and reported [1] the issue. I got an
         | explanation on fixing this issue locally, but weirly enough,
         | the fix _still wasn 't actually implemented on the public
         | version_.
         | 
         | I'll report back in about a year with an update on the
         | experiment.
         | 
         | [0] https://pijul.org/manual/theory.html
         | 
         | [1] https://nest.pijul.com/pijul/manual/discussions/46
        
           | AceJohnny2 wrote:
           | > _It is really weird not to care about the first impression
           | that your manual makes on a curious reader._
           | 
           | On the contrary, I think this is an all-too-familiar pitfall
           | for the, er... technically minded.
           | 
           | "I've implemented it in the code. My work here is done. The
           | rest is window dressing."
        
         | rbsmith wrote:
         | Do you use Pijul?
         | 
         | From time to time, I do a 'pijul pull -a' into the pijul source
         | tree, and I get a conflict (no local work on my part). Is there
         | a way to do a tracking update pull? I didn't see one, so I toss
         | the repo and reclone. What works for you in tracking what's
         | going on there?
        
       | radarsat1 wrote:
       | 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.
        
         | mikey-k wrote:
         | This
        
         | recursivecaveat wrote:
         | It says that merges that involve overlap get flagged to the
         | user. I don't think that's much more than a defaults difference
         | to git really. You could have a version of git that just warns
         | on conflict and blindly concats the sides.
        
         | hungryhobbit wrote:
         | They address this; it's not that they don't fail, in
         | practice...
         | 
         | the key insight is that changes should be flagged as
         | conflicting when they touch each other, giving you informative
         | conflict presentation on top of a system which never actually
         | fails.
        
           | bigfishrunning wrote:
           | Isn't that how the current systems work though? Git inserts
           | conflict markers in the file, and then emacs (or whatever
           | editor) highlights them
           | 
           | The big red block seems the same as "flagged", unless I'm
           | misunderstanding something
        
         | rectang wrote:
         | I agree. Nevertheless I wonder if this approach can help with
         | certain other places where Git sometimes struggles, such as
         | whether or not two commits which have identical diffs but
         | different parents should be considered equivalent.
         | 
         | In the general case, such commits cannot be considered the same
         | -- consider a commit which flips a boolean that one branch had
         | flipped in another file. But there are common cases where the
         | commits should be considered equivalent, such as many rebased
         | branches. Can the CRDT approach help with e.g. deciding that
         | `git branch -d BRANCH` should succeed when a rebased version of
         | BRANCH has been merged?
        
         | gojomo wrote:
         | Should you be counting on confusion of an underpowered text-
         | merge to catch such problems?
         | 
         | It'll fire on merge issues that aren't code problems under a
         | smarter merge, while also missing all the things that merge OK
         | but introduce deeper issues.
         | 
         | Post-merge syntax checks are better for that purpose.
         | 
         | And imminently: agent-based sanity-checks of preserved intent -
         | operating on a logically-whole result file, without merge-tool
         | cruft. Perhaps at higher intensity when line-overlaps - or even
         | more-meaningful hints of cross-purposes - are present.
        
           | skydhash wrote:
           | > It'll fire on merge issues that aren't code problems under
           | a smarter merge, while also missing all the things that merge
           | OK but introduce deeper issues.
           | 
           | That has not been my experience at all. The changes you
           | introduced is your responsibility. If you synchronizes your
           | working tree to the source of truth, you need to evaluate
           | your patch again whether it introduces conflict or not. In
           | this case a conflict is a nice signal to know where someone
           | has interacted with files you've touched and possibly change
           | their semantics. The pros are substantial, and it's quite
           | easy to resolve conflicts that's only due to syntastic
           | changes (whitespace, formatting, equivalent statement,...)
        
             | gojomo wrote:
             | If you're relying on a serialized 'source of truth',
             | against which everyone must independently ensure their
             | changes sanely apply in isolation, the. you've already
             | resigned yourself to a single-threaded process that's
             | slower than what improved merges aim to enable.
             | 
             | Sure, that works - like having one (rare, expensive) savant
             | engineer apply & review everything in a linear canonical
             | order. But that's not as competitive & scalable as flows
             | more tolerant of many independent coders/agents.
        
               | yammosk wrote:
               | And yet after all these year of git supporting no source
               | of truth we still fall back on it. As long as you have an
               | authoritative version and authoritative release then you
               | have one source of truth. Linus imagined everyone
               | contributing with no central authority and yet we look to
               | GitHub and Gitlab to centralize our code. Git is already
               | decentralized and generally we find it impractical.
        
               | skydhash wrote:
               | Decentralization in this case means one can secede easily
               | from the central authority. So anyone working on a
               | project can easily split away from the main group at any
               | time. But every project have a clear governance where the
               | main direction is set and the canonical version of the
               | thing being under version control is stored.
               | 
               | That canonical version is altered following a process and
               | almost every project agrees that changes should be
               | proposed against it. Even with independent agents, there
               | should be a way to ensure consensus and decides the final
               | version. And that problem is a very hard one.
        
             | IshKebab wrote:
             | He's not saying you shouldn't have conflicts; just that
             | it's better to have syntax-aware conflict detection. For
             | example if two people add a new function to the end of the
             | same file, Git will always say that's a conflict. A syntax-
             | aware system could say that they don't conflict.
        
         | jwilliams wrote:
         | Indeed. And plenty of successful merges end up with code that
         | won't compile.
         | 
         | FWIW I've struggled to get AI tools to handle merge conflicts
         | well ( _especially rebase_ ) for the same underlying reason.
        
           | layer8 wrote:
           | Code not compiling is still the good case, because you'll
           | notice before deployment. The dangerous cases are when it
           | does compile.
        
             | jwilliams wrote:
             | Very true.
             | 
             | I realized recently that I've subconsciously routed-around
             | merge conflicts as much as possible. My process has just
             | subtly altered to make them less likely. To the point of
             | which seeing a 3-way merge feels jarring. It's really only
             | taking on AI tools that bought this to my attention.
        
             | Gibbon1 wrote:
             | I've seen merged code where the memory barriers were
             | misplaced.
        
           | skydhash wrote:
           | I'm surprised to see that some people sync their working tree
           | and does not evaluate their patch again (testing and
           | reviewing the assumptions they have made for their changes).
        
         | conradludgate wrote:
         | My understanding of the way this is presented is that merges
         | don't _block_ the workflow. In git, a merge conflict is a
         | failure to merge, but in this idea a merge conflict is still
         | present but the merge still succeeds. You can commit with
         | conflicts unresolved. This allows you to defer conflict
         | resolution to later. I believe jj does this as well?
         | 
         | Technically you could include conflict markers in your commits
         | but I don't think people like that very much
        
           | rightbyte wrote:
           | > You can commit with conflicts unresolved.
           | 
           | True but it is not valid syntax. Like, you mean with the
           | conflict lines?
        
             | ericpauley wrote:
             | Yeah this seems silly. You can do the same thing in git
             | (add and commit with the conflict still there)! Why you
             | would want to is a real mystery.
        
               | fweimer wrote:
               | It allows review of the way the merge conflict has been
               | resolved (assuming those changes a tracked and presented
               | in a useful way). This can be quite helpful when
               | backporting select fixes to older branches.
        
             | furyofantares wrote:
             | The conflict lines shown in the article are not present in
             | the file, they are a display of what has already been
             | merged. The merge had changes that were too near each other
             | and so the algorithm determined that someone needs to
             | review it, and the conflict lines are the result of
             | displaying the relevant history due to that determination.
             | 
             | In the example in the article, the inserted line from the
             | right change is floating because the function it was in
             | from the left has been deleted. That's the state of the
             | file, it has the line that has been inserted and it does
             | not have the lines that were deleted, it contains both
             | conflicting changes.
             | 
             | So in that example you indeed must resolve it if you want
             | your program to compile, because the changes together
             | produce something that does not function. But there is no
             | state about the conflict being stored in the file.
        
             | Someone wrote:
             | In this model, conflicts do not exist, so there are no
             | conflict markers (the UI may show markers, but they get
             | generated from what they call "the weave")
             | 
             | Because of that, I think it is worse than "but it is not
             | valid syntax"; it's "but it may not be valid syntax". A
             | merge may create a result that compiles but that neither of
             | the parties involved intended to write.
        
       | simonw wrote:
       | 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.
        
         | zahlman wrote:
         | It's really impressive what can be done in a few hundred lines
         | of well-thought-out Python without resorting to brutal hacks.
         | People complain about left-pad incidents etc. in the JS world
         | but I honestly feel like the Python ecosystem could do with
         | more, smaller packages on balance. They just have to be put
         | forward by responsible people who aren't trying to make a point
         | or inflate artificial metrics.
        
           | josephg wrote:
           | I bet you can make a small, beautiful implementation of this
           | algorithm in most languages. Most algorithms - even ones that
           | take generations of researchers to figure out - end up tiny
           | in practice if you put the work in to understand them
           | properly and program them in a beautiful way. Transformers
           | are the same. Genius idea. But a very small amount of code to
           | implement.
           | 
           | This is an implementation of FugueMax (Weidner and Kleppmann)
           | done using a bunch of tricks from Yjs (Jahns). There's
           | generations of ideas here, by lots of incredibly smart
           | people. And it turns out you can code the whole thing up in
           | 250 lines of readable typescript. Again with no dependencies.
           | 
           | https://github.com/josephg/crdt-from-
           | scratch/blob/master/crd...
        
         | sayrer wrote:
         | The joke is there in the name. It is wrong (on purpose): it
         | should be "Manana". 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).
        
       | mikey-k wrote:
       | 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.
        
         | layer8 wrote:
         | One solution is to decompose your code into modules with stable
         | interfaces and reference them as versioned dependencies.
        
         | procaryote wrote:
         | What kind of scalability issues have you had with git?
         | 
         | Is it because of a monorepo?
        
       | lifeformed wrote:
       | 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.
        
         | miloignis wrote:
         | I really think something like Xet is a better idea to augment
         | Git than LFS, though it seems to pretty much only be used by
         | HuggingFace for ML model storage, and I think their git plugin
         | was deprecated? Too bad if it ends up only serving the
         | HuggingFace niche.
        
         | rectang wrote:
         | Has there ever been a consideration for the git file format to
         | allow storage of binary blobs uncompressed?
         | 
         | When I was screwing around with the Git file format, tricks I
         | would use to save space like hard-linking or memory-mapping
         | couldn't work, because data is always stored compressed after a
         | header.
         | 
         | A general copy-on-write approach to save checkout space is
         | presumably impossible, but I wonder what other people have
         | traveled down similar paths have concluded.
        
         | zahlman wrote:
         | What strategies would you like to use to diff the binaries? Or
         | else how are you going to avoid bloat?
         | 
         | Is it actually okay to try to merge changes to binaries? If two
         | people modify, say, different regions of an image file (even in
         | PNG or another lossless compression format), the sum of the
         | visual changes isn't necessarily equal to the sum of the byte-
         | level changes.
        
         | jayd16 wrote:
         | Totally agree. After trying to flesh out Unreal's git plugin,
         | it really shows how far from ideal git really is.
         | 
         | Partial checkouts are awkward at best, LFS locks are somehow
         | still buggy and the CLI doesn't support batched updates.
         | Checking the status of a remote branch vs your local (to
         | prevent conflicts) is at best a naive polling.
         | 
         | Better rebase would be a nice to have but there's still so much
         | left to improve for trunk based dev.
        
         | gregschoeninger wrote:
         | We're working on this project to help with the non-text file
         | and large file problem: https://github.com/Oxen-AI/Oxen
         | 
         | Started with the machine learning use case for datasets and
         | model weights but seeing a lot of traction in gaming as well.
         | 
         | Always open for feedback and ideas to improve if you want to
         | take it for a spin!
        
         | samuelstros wrote:
         | Improving on "git not handling non-text files" is a semantic
         | understanding aka parse step in between the file write.
         | 
         | Take a docx, write the file, parse it into entities e.g.
         | paragraph, table, etc. and track changes on those entities
         | instead of the binary blob. You can apply the same logic to
         | files used in game development.
         | 
         | The hard part is making this fast enough. But I am working on
         | this with lix [0].
         | 
         | [0] https://github.com/opral/lix
        
       | gnarlouse wrote:
       | 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.
        
         | CuriouslyC wrote:
         | Team scale doesn't tend to impact this that much, since as
         | teams grow they naturally specialize in parts of the codebase.
         | Shared libs can be hotspots, I've heard horror stories at large
         | orgs about this sort of thing, though usually those shared libs
         | have strong gatekeeping that makes the problem more one of
         | functionality living where it shouldn't to avoid gatekeeping
         | than a shared lib blowing up due to bad change set merges.
        
         | tasuki wrote:
         | > 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?
         | 
         | Oh god no! That would be about the worst way to do it.
         | 
         | Just make it conceptually sound.
        
           | gnarlouse wrote:
           | Probably, but just introducing CRDTs also feels like the
           | wrong way to approach the problem! :)
        
         | jillesvangurp wrote:
         | > 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.
        
       | jFriedensreich wrote:
       | 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.
        
         | miloignis wrote:
         | The rest of the article shows exactly how a CRDT is a sound
         | base for a version control system, with "conflicts" and all.
        
           | skydhash wrote:
           | But the presentation does not show how it resolves conflicts.
           | For the first example, Git has the 3 way-merge that shows the
           | same kind of info. And a conflict is not only to show that
           | two people have worked on a file. More often than not, it
           | highlight a semantic changes that happened differently in two
           | instances and it's a nice signal to pay attention to this
           | area. But a lot of people takes merge conflicts as some kind
           | of nuisance that prevents them from doing their job (more
           | often due to the opinion that their version is the only good
           | one).
        
           | jFriedensreich wrote:
           | where?
        
         | nozzlegear wrote:
         | > _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._
         | 
         | I really wonder what kinds of magical AI you're using, because
         | in my experience, Claude Code chokes and chokes hard on complex
         | rebases/merge conflicts to the point that I couldn't trust it
         | anymore.
        
       | jauntywundrkind wrote:
       | 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).
       | 
       | 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!
        
       | ulrikrasmussen wrote:
       | 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.
        
         | crote wrote:
         | Seconding the use of p4merge for easy-to-use three-pane
         | merging. Just like most other issues with Git, if your merges
         | are painful it's probably due to terrible native UX design -
         | not due to anything _conceptually_ wrong with Git.
        
           | TacticalCoder wrote:
           | Thirding it except I do it from Emacs. Three side-by-side
           | pane with left / common ancestor / right and then below the
           | merge result. By default it's not like that but then it's
           | Emacs so anything is doable. I hacked some elisp code a great
           | many years ago and I've been using it ever since.
           | 
           | No matter the tool, merges should _always_ be presented like
           | that. It 's the only presentation that makes sense.
        
             | MarsIronPI wrote:
             | What tool do you use? Does Magit support it natively?
        
               | skydhash wrote:
               | I think you need to enable 3 way merge by default in
               | git's configuration, and both smerge (minor mode for
               | solving conflicts) and ediff (major mode that encompass
               | diff and patch) will pick it up. In the case of the
               | latter you will have 4 panes, one for version A, another
               | for version B, a third for the result C, and the last is
               | the common ancestor of A and B.
               | 
               | Addendum: I've since long disabled it. A and B changes
               | are enough for me, especially as I rebase instead of
               | merging.
        
             | jwr wrote:
             | Isn't that what ediff does?
        
           | roryokane wrote:
           | Did you know that VS Code added support for the same four-
           | pane view as p4merge years ago? I used p4merge as my merge
           | tool for a long time, but I switched to VS Code when I
           | discovered that, as VS Code's syntax highlighting and text
           | editing features are much better than p4merge's.
           | 
           | I also use the merge tool of JetBrains IDEs such as IntelliJ
           | IDEA (https://www.jetbrains.com/help/idea/resolve-
           | conflicts.html#r...) when working in those IDEs. It uses a
           | three-pane view, not a four-pane view, but there is a menu
           | that allows you to easily open a comparison between any two
           | of the four versions of the file in a new window, so I find
           | it similarly efficient.
        
             | stbtrax wrote:
             | how do you set that up? the default git tool version seems
             | to be 3 pane
        
               | ramchip wrote:
               | Looks like it's "Show Base" under the top-level "..."
               | menu when working on a merge conflict
               | 
               | https://github.com/microsoft/vscode/issues/155277#issueco
               | mme...
        
         | roryokane wrote:
         | Even if you don't use p4merge, you can set Git's
         | merge.conflictStyle config to "diff3" or "zdiff3" (https://git-
         | scm.com/docs/git-config#Documentation/git-config...). If you do
         | that, Git's conflict markers show the base version as well:
         | <<<<<<< left       ||||||| base       def calculate(x):
         | a = x * 2           b = a + 1           return b       =======
         | def calculate(x):           a = x * 2
         | logger.debug(f"a={a}")           b = a + 1           return b
         | >>>>>>> right
         | 
         | With this configuration, a developer reading the raw conflict
         | markers could infer the same information provided by Manyana's
         | conflict markers: that the right side added the logging line.
        
           | ktm5j wrote:
           | I'm on my phone right now so I'm not going to dig too hard
           | for this, but you can also configure a "merge tool" (or
           | something like that) so you can use Meld or Kompare to make
           | the process easier. This has helped me in a pinch to work out
           | some confusing merge conflicts.
        
             | newsoftheday wrote:
             | I started using Meld years ago and continue to find people
             | who've never heard of it. It's a pretty good tool.
        
           | psychoslave wrote:
           | That still have an issue with the vocabulary. Things like
           | "theirs/our" is still out of touch but it's already better
           | than a loose spatial analogy on some representation of the
           | DAG.
           | 
           | Something like base, that is "common base", looks far more
           | apt to my mind. In the same vein, endogenous/exogenous would
           | be far more precise, or at least aligned with the concern at
           | stake. Maybe "local/alien" might be a less pompous vocabulary
           | to convey the same idea.
        
             | kungito wrote:
             | After 15 years i still cant remember which is which. I get
             | annoyed every time. Maybe I should invest 15 minutes
             | finally to remember properly
        
               | IgorPartola wrote:
               | Let's see if I get this wrong after 25 years of git:
               | 
               | ours means what is in my local codebase.
               | 
               | theirs means what is being merged into my local codebase.
               | 
               | I find it best to avoid merge conflicts than to try to
               | resolve them. Strategies that keep branches short lived
               | and frequently merging main into them helps a lot.
        
               | marcellus23 wrote:
               | That's kind of the simplest case, though, where "theirs"
               | and "ours" makes obvious sense.
               | 
               | What if I'm rebasing a branch onto another? Is "ours" the
               | branch being rebased, or the other one? Or if I'm
               | applying a stash?
        
               | IgorPartola wrote:
               | > What if I'm rebasing a branch onto another?
               | 
               | Just checkout the branch you are merging/rebasing into
               | before doing it.
               | 
               | > Or if I'm applying a stash?
               | 
               | The stash is in that case effectively a remote branch you
               | are merging into your local codebase. ours is your local,
               | theirs is the stash.
        
               | sheept wrote:
               | "Ours" and "theirs" make sense in most cases (since
               | "ours" refers to the HEAD you're merging into).
               | 
               | Rebases are the sole exception (in typical use) because
               | ours/theirs is reversed, since you're merging HEAD into
               | the other branch. Personally, I prefer merge commits over
               | rebases if possible; they make PRs harder for others to
               | review by breaking the "see changes since last review"
               | feature. Git generally works better without rebases and
               | squash commits.
        
               | sebmellen wrote:
               | Wow, interesting to see such a diametrically opposed
               | view. We've banned merge commits internally and our
               | entire workflow is rebase driven. Generally, I find that
               | rebases are far better at keeping Git history clean and
               | clearly allowing you to see the diff between the base
               | you're merging into and the changes you've made.
        
               | em-bee wrote:
               | a better (more confusing) example:
               | 
               | i have a branch and i want to merge that branch into
               | main.
               | 
               | is ours the branch and main theirs? or is ours main, and
               | the branch theirs?
        
               | IgorPartola wrote:
               | I always checkout the branch I am merging something into.
               | I was vaguely aware I could have main checked out but
               | merge foo into bar but have never once done that.
        
               | Sharlin wrote:
               | git checkout mybranch       git rebase main
               | 
               | A conflict happens. Now "ours" is _main_ and  "theirs" is
               | _mybranch_ , even though from your perspective you're
               | still on mybranch. Git isn't, however.
        
               | IgorPartola wrote:
               | Ah that's fair. This is why I would do a `git merge main`
               | instead of a rebase here.
        
               | ljm wrote:
               | I have met more than one person who would doggedly
               | tolerate rebase, not even using rerere, instead of doing
               | a simple 'git merge --no-ff' to one-shot it, not
               | understanding that rebase touches every commit in the
               | diff between main and not simply the latest change on
               | HEAD.
               | 
               | Not a problem if you are a purist on linear history.
        
               | clktmr wrote:
               | The thing is, you'll typically switch to master to merge
               | your own branch. This makes your own branch 'theirs',
               | which is where the confusion comes from.
        
               | IgorPartola wrote:
               | Not me. I typically merge main onto a feature branch
               | where all the conflicts are resolved in a sane way. Then
               | I checkout main and merge the feature branch into it with
               | no conflicts.
               | 
               | As a bonus I can then also merge the feature branch into
               | main as a squash commit, ditching the history of a
               | feature branch for one large commit that implements the
               | feature. There is no point in having half implemented
               | and/or buggy commits from the feature branch clogging up
               | my main history. Nobody should ever need to revert main
               | to that state and if I really really need to look at that
               | particular code commit I can still find it in the feature
               | branch history.
        
               | throwaway7783 wrote:
               | Yep. This is the only model that has worked well for me
               | for more than a decade.
        
               | KPGv2 wrote:
               | > ours means what is in my local codebase
               | 
               | Since it's always one person doing a merge, why isn't it
               | "mine" instead of "ours"? There aren't five of us at my
               | computer collaboratively merging in a PR. There is one
               | person doing it.
               | 
               | "Ours" makes it sound like some branch everyone who's
               | working on the repo already has access to, not the active
               | branch on _my_ machine.
        
               | afiori wrote:
               | iirc ours is always the commit the merge is starting
               | from. the issue is that with a merge your current commit
               | is the merging commit while with a rebase it is reversed.
               | 
               | I suspect that this could be because the rebase command
               | is implemented as a serie of merges/cherry-picks from the
               | target branch.
        
               | Sharlin wrote:
               | git checkout mybranch       git rebase main
               | 
               | Now git takes main and starts cloning (cherry-picking, as
               | you said) commits from mybranch on top of it. From git's
               | viewpoint it's working on top of main, so if a conflict
               | occurs, main is "ours" and mybranch is "theirs". But from
               | your viewpoint you're still on mybranch, and indeed are
               | left on mybranch when the rebase is complete. (It's a
               | _different_ mybranch, of course; once the rebase is
               | completed, git moves mybranch to point to the new
               | (detached) HEAD.) Which makes  "ours" and "theirs"
               | exactly the opposite of what the user expects.
        
               | XorNot wrote:
               | Man do I hate this behavior because it would be really
               | some by just using the branch names rather then "ours"
               | and "theirs"
        
               | orthoxerox wrote:
               | I had to make an alias for rebasing, because I kept doing
               | the opposite:                   git checkout master
               | #check out the branch to apply commits to         git
               | rebase mybranch #Apply all commits from mybranch
               | 
               | Now I just write                   rebase-current-branch
               | 
               | and it does what I want: fetches origin/master and
               | rebases my working branch on top of it.
               | 
               | But "ours"/"theirs" still keeps tripping me up.
        
               | cerved wrote:
               | Tip, you may want to use origin/HEAD over origin/master
        
               | awesome_dude wrote:
               | This is one of my pain points, and one time I googled and
               | got the real answer (which is why it's such a pain
               | point).
               | 
               | That answer is "It depends on the context"
               | 
               | > The reason the "ours" and "theirs" notions get swapped
               | around during rebase is that rebase works by doing a
               | series of cherry-picks, into an anonymous branch
               | (detached HEAD mode). The target branch is the anonymous
               | branch, and the merge-from branch is your original (pre-
               | rebase) branch: so "--ours" means the anonymous one
               | rebase is building while "--theirs" means "our branch
               | being rebased".[0]
               | 
               | [0] https://stackoverflow.com/questions/25576415/what-is-
               | the-pre...
        
               | flutetornado wrote:
               | I ended up creating a personal vim plugin for merges one
               | night because of a frustrating merge experience and never
               | being able to remember what is what. It presents just two
               | diff panes at top to reduce the cognitive load and a
               | navigation list in a third split below to switch between
               | diffs or final buffer (local/remote, base/local,
               | base/remote and final). The list has branch names next to
               | local/remote so you always know what is what. And most of
               | the time the local/remote diff is what I am interested in
               | so that's what it shows first.
        
               | mamcx wrote:
               | Seriously!
               | 
               | Why not show the names of the branch + short Id (and when
               | is not direct name, at least "this is from NAME")
        
               | sheept wrote:
               | doesn't it? Next to the conflict markers, it'll display
               | HEAD, the ref name, or the short commit hash.
        
               | cerved wrote:
               | It does
        
               | KPGv2 wrote:
               | I'll be honest, as a fairly skilled and experienced
               | programmer who isn't a git expert, I know what HEAD
               | means, but when I'm rebasing I really have no idea. It
               | all seems to work out in the end because my collaborative
               | work is simple and usually 2-3 people only, so I'm never
               | rebasing against a ton of commits I lack context for
               | (because 90% of them are _my_ commits since I 'm usually
               | dealing with PRs to my open source projects rather than
               | someone else's).
               | 
               | HEAD is "the thing we're editing now" but that's not
               | terribly useful when rebasing since you're repeatedly
               | editing a fake history.
        
             | wakawaka28 wrote:
             | >Maybe "local/alien" might be a less pompous vocabulary to
             | convey the same idea.
             | 
             | That is more alien and just as contrived. If you merge
             | branches that you made, they're both local and "ours". You
             | just have to remember that "ours" is the branch you are on,
             | and "theirs" is the other one. I have no idea what happens
             | in an octopus merge but anyway, the option exists to show
             | commit titles along with markers to help you keep it
             | straight.
        
           | IshKebab wrote:
           | This is better but it still doesn't really help when the
           | conflict is 1000 lines and one side changed one character and
           | the other deleted the whole thing. That isn't theoretical -
           | it happens quite regularly.
           | 
           | What you really need is the ability to diff the base and
           | "ours" or "theirs". I've found most different UIs can't do
           | this. VSCode can, but it's difficult to get to.
           | 
           | I haven't tried p4merge though - if it can do that I'm sold!
        
         | cxr wrote:
         | > 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.
        
           | hn_throwaway_99 wrote:
           | > 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.
           | 
           | It seems like you have taken offense to the phrase "stores
           | diffs", but I'm not sure why. I understand how commit
           | snapshots and packfiles work, and the way delta compression
           | works in packfiles might lead me to calling it "storing
           | diffs" in a colloquial setting.
        
         | galaxyLogic wrote:
         | Can it merge ordinary directories (in addition to git-
         | bracnehs)?
        
         | killerstorm wrote:
         | Yeah, also JetBrains IDEs like IntelliJ have very nice merge
         | UI.
         | 
         | 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.
        
       | lemonwaterlime wrote:
       | 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.
       | 
       | [1]: https://github.com/samoshkin/vim-mergetool
        
         | mentalgear wrote:
         | Looks like vscode diff view .
        
       | skybrian wrote:
       | 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.
        
         | dcre wrote:
         | 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.
         | 
         | [0]: https://docs.jj-vcs.dev/latest/conflicts/
        
         | dzaima wrote:
         | 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`.
        
       | WCSTombs wrote:
       | For the conflicts, note that in Git you can do
       | git config --global merge.conflictstyle diff3
       | 
       | to get something like what is shown in the article.
        
       | mentalgear wrote:
       | > [CRDT] This means merges don't need to find a common ancestor
       | or traverse the DAG. Two states go in, one state comes out, and
       | it's always correct.
       | 
       | 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.
        
         | Retr0id wrote:
         | Yes.
         | 
         | There are many ways to instantiate a CRDT, and a trivial one
         | would be "last write wins" over the whole source tree state.
         | LWW is obviously not what you'd want for source version
         | control. It is "correct" per its own definition, but it is not
         | useful.
         | 
         | Anyone saying "CRDTs solve this" without elaborating on the
         | specifics of their CRDT is not saying very much at all.
        
         | mweidner wrote:
         | 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].
         | 
         | [1] https://arxiv.org/abs/1710.04469
        
       | alunchbox wrote:
       | 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.
        
         | aduwah wrote:
         | The only reason I have not defaulted to jj already is the
         | inability to be messy with it. Easy to make mistakes without
         | "git add"
        
           | dzaima wrote:
           | But you do have the op log, giving you a full copy of the log
           | (incl. the contents of the workspace) at every operation, so
           | you can get out of such mistakes with some finagling.
           | 
           | You can choose to have a workflow where you're never directly
           | editing any commit to "gain back autonomy" of the working
           | copy; and if you really want to, with some scripting, you can
           | even emulate a staging area with a specially-formatted commit
           | below the working copy commit.
        
           | llyama wrote:
           | You can be messy. The lack of an explicit staging area
           | doesn't restrict that. `jj commit` gives the same mental
           | model for "I want to commit 2 files from the 5 I've changed".
        
       | phtrivier wrote:
       | 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" ?
        
       | lasgawe wrote:
       | 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!
        
       | a-dub wrote:
       | 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?
        
       | socalgal2 wrote:
       | > [CRDT] This means merges don't need to find a common ancestor
       | or traverse the DAG. Two states go in, one state comes out, and
       | it's always correct.
       | 
       | Funny, there was just a post a couple of days ago how this is
       | false.
       | 
       | https://news.ycombinator.com/item?id=47359712
        
       | monster_truck wrote:
       | Not this again
        
       | codemog wrote:
       | Nobody should have these types of problems in the age of AI
       | agents. This kind of clean up and grunt work is perfect for AI
       | agents. We don't need new abstractions.
        
         | twsted wrote:
         | Version control systems are more important than ever with AI.
        
       | BlueHotDog2 wrote:
       | This is cool and i keep thinking about CRDTs as a baseline for
       | version control, but CRDTs has some major issues, mainly the fact
       | that most of them are strict and "magic" in the way they actually
       | converge(like the joke: CRDTs always converge, but to what). i
       | didn't read if he's using some special CRDT that might solve for
       | that, but i think that for agentic work especially this is very
       | interesting
        
       | bob1029 wrote:
       | I think there are still strong advantages to the centralized
       | locking style of collaboration. The challenge is that it seems to
       | work best in a setting where everyone is in the same physical
       | location while they are working. You can break a lock in 30
       | seconds with your voice. Locking across time zones and date lines
       | is a nonstarter by comparison.
        
         | fn-mote wrote:
         | It seems like in a reasonable sized org you should not be
         | merging so often that "centralized locking ... across time
         | zones" should be an issue.
         | 
         | Are people really merging that often? What is being merged? Doc
         | fixes?
        
       | sibeliuss wrote:
       | Why must everyone preprocess their blog posts with ChatGPT? It is
       | such a disservice to ones ideas.
        
       | newsoftheday wrote:
       | OK, I'll stick with git.
        
       | nkmnz wrote:
       | I don't quite understand how CRDTs should help with merges. The
       | difficult thing about merges is not that two changes touch the
       | same part of the code; the difficult thing is that two changes
       | can touch different parts of the code and still break each other
       | - right?
        
         | AceJohnny2 wrote:
         | Eh. It's a matter of visible pain vs invisible pain.
         | 
         | Developers are quite familiar with Merge Conflicts and the
         | confusing UI that git (and SVN before it, in my experience)
         | gives you about them. The "ours vs theirs" nomenclature which
         | doesn't help, etc. This is something that VCSs can improve on,
         | QED this post.
         | 
         | Vs the scenario you're describing (what I call Logical
         | Conflicts), where two changes touching different parts of the
         | code (so it doesn't emerge as a Merge Conflict) but still
         | breaking each other. Like one change adding a function call in
         | one file but another change changing the API in a different
         | file.
         | 
         | These are painful in a different way, and not something that a
         | simple text-based version control (which is all of the big
         | ones) can even see.
         | 
         | Indeed, CRDTs do not help with Logical Conflicts.
        
       | gavinhoward wrote:
       | Bram Cohen is awesome, but this feels a little bare. I've put
       | much more thought into version control ([1]), including the use
       | of CRDTs (search for "# History Model" and read through the
       | "Implementing CRDTs" section).
       | 
       | [1]: https://gavinhoward.com/uploads/designs/yore.md
        
         | AceJohnny2 wrote:
         | That's worth making a separate post! (and I recommend rendering
         | it to HTML)
         | 
         | But "bare" is part of the value of Cohen's post, I think. When
         | you want to publicize a paradigm shift, it helps to make it in
         | small, digestible chunks.
        
         | 63stack wrote:
         | Is this the Bram Cohen who made bittorrent? There is
         | surprisingly little information on this page.
        
           | vessenes wrote:
           | Yes
        
       | MattCruikshank wrote:
       | For anyone who thinks diff / merge should be better - try Beyond
       | Compare from Scooter Software.
        
       | steveharing1 wrote:
       | Git is my first priority until or unless i see anything more
       | robust than this one.
        
       | barrkel wrote:
       | I don't really get the upside of focus on CRDTs.
       | 
       | The semantic problem with conflicts exists either way. You get a
       | consistent outcome and a slightly better description of the
       | conflict, but in a way that possibly interleaves changes, which I
       | don't think is an improvement at all.
       | 
       | I am completely rebase-pilled. I believe merge commits should be
       | avoided at all costs, every commit should be a fast forward
       | commit, and a unit of work that can be rolled back in isolation.
       | And also all commits should be small. Gitflow is an anti-pattern
       | and should be avoided. Long-running branches are for patch
       | releases, not for feature development.
       | 
       | I don't think this is the future of VCS.
       | 
       | Jujutsu (and Gerrit) solves a real git problem - multiple
       | revisions of a change. That's one that creates pain in git when
       | you have a chain of commits you need to rebase based on feedback.
        
         | gzread wrote:
         | People see that CRDTs have no conflicts and proclaim them as
         | the solution to all problems, not seeing that some problems
         | inherently have conflicts and either can't be represented by
         | CRDTs at all, or that the use of CRDTs resolves conflicts in a
         | way that's worse than if you actually thought about conflict
         | resolution. E.g. that multiplayer text editor that interleaved
         | characters from simultaneous edits.
        
         | IgorPartola wrote:
         | I used to use rebase much more than merge but have grown to be
         | more nuanced over the years:
         | 
         | Merge commits from main into a feature branch are totally fine
         | and easier to do than rebasing. After your feature branch is
         | complete you can do one final main-to-feature-branch merge and
         | then merge the feature branch into main with a squash commit.
         | 
         | When updating any branch from remote, I always do a pull rebase
         | to avoid merge commits from a simple pull. This works well
         | 99.99% of the time since what I have changed vs what the remote
         | has changed is obvious to me.
         | 
         | When I work on a project with a dev branch I treat feature
         | branches as coming off dev instead of main. In this case I
         | merge dev into feature branches, then merge feature branches
         | into dev via a squash commit, and then merge main into dev and
         | dev into main as the final step. This way I have a few merge
         | commits on dev and main but only when there is something like
         | an emergency fix that happens on main.
         | 
         | The problem with always using a rebase is that you have to
         | reconcile conflicts at every commit along the way instead of
         | just the final result. That can be a lot more work for commits
         | that will never actually be used to run the code and can in
         | fact mess up your history. Think of it like this:
         | 
         | 1. You create branch foo off main.
         | 
         | 2. You make an emergency commit to main called X.
         | 
         | 3. You create commits A, B, and C on foo to do your feature
         | work. The feature is now complete.
         | 
         | 4. You rebase foo off main and have to resolve the conflict
         | introduced by X happening before A. Let's say it conflicts with
         | all three of your commits (A, B, and C).
         | 
         | 5. You can now merge foo into main with it being a fast forward
         | commit.
         | 
         | Notice that at no point will you want to run the codebase such
         | that it has commits XA or XAB. You only want to run it as XABC.
         | In fact you won't even test if your code works in the state XA
         | or XAB so there is little point in having those checkpoints.
         | You care about three states: main before any of this happened
         | since it was deployed like that, main + X since it was deployed
         | like that, and main with XABC since you added a feature. git
         | blame is really the only time you will ever possibly look at
         | commits A and B individually and even then the utility of it is
         | so limited it isn't worth it.
         | 
         | The reality is that if you only want fast forward commits,
         | chances are you are doing very little to go back and extract
         | code out of old versions a of the codebase. You can tell this
         | by asking yourself: "if I deleted all my git history from main
         | and have just the current state + feature branches off it, will
         | anything bad happen to my production system?" If not, you are
         | not really doing most of what git can do (which is a good
         | thing).
        
           | barrkel wrote:
           | I am now wholly bought into the idea of having a feature
           | branch with (A->B->C) commits is an anti-pattern.
           | 
           | Instead, if the feature doesn't work without the full chain
           | of A+B+C, either the code introduced in A+B is orphaned
           | except by tests and C joins it in; or (and preferably for a
           | feature of any significance), A introduces a feature flag
           | which disables it, and a subsequent commit D removes the
           | feature flag, after it is turned on at a time separate to
           | merge and deploy.
        
             | IgorPartola wrote:
             | I treat each feature branch as my own personal playground.
             | There should be zero reason for anyone to ever look at it.
             | Sometimes they aren't even pushed upstream. Otherwise, just
             | work on main with linear history and feature flags and
             | avoid all this complexity that way.
             | 
             | Just like you don't expect someone else's local codebase to
             | always be in a fully working state since they are actively
             | working on it, why do you expect their working branch to be
             | in a working state?
        
           | DSMan195276 wrote:
           | I think you're somewhat missing the point - if the code from
           | A and B only works if joined with C, then you should squash
           | them all into one commit so that they can't be separated. If
           | you do that then the problem you're describing goes away
           | since you'll only be rebasing a single commit anyway.
           | 
           | Whether this is valuable is up to you, but IMO I'd say it's
           | better practice than not. People do dumb things with the
           | history and it's harder to do dumb things if the commits are
           | self-contained. Additionally if a feature branch includes
           | multiple commits + merges I'd much rather they squash that
           | into a single commit (or a couple logical commits) instead of
           | keeping what's likely a mess of a history anyway.
        
             | IgorPartola wrote:
             | That is literally what I advocate you do for the main
             | branch. A feature branch is allowed to have WIP commits
             | that make sense for the developer working on the branch
             | just like uncommitted code might not be self contained
             | because it is WIP. Once the feature is complete, squash it
             | into one commit and merge it into main. There is very
             | little value to those WIP commits (rare case being when you
             | implement algorithm X but then change to Y and later want
             | to experiment with X again).
        
               | bathwaterpizza wrote:
               | One downside of squash merging is that when you need to
               | split your work across branches, so that they're
               | different PRs, but one depends on the other, then you
               | have to do a rebase after every single one which had
               | dependencies is merged.
        
         | hackrmn wrote:
         | When you say "unit of work", unit of _which_ work are you
         | referring to? The problem with rebasing is that it takes one
         | set of snapshots and replays them on top of another set, so you
         | end up with two "equivalent" units of work. In fact they're
         | _the same_ indeed -- the tree objects are shared, except that
         | if by "work" you mean changes, Git is going to tell you two
         | different histories, obviously.
         | 
         | This is in contrast with [Pijul](https://pijul.org) where
         | changes are patches and are commutative -- you can apply an
         | entire set and the result is supposed to be equivalent
         | regardless of the order the patches are applied in. Now _that_
         | is unit of work" I understand can be applied and undone in
         | "isolation".
         | 
         | Everything else is messy, in my eyes, but perhaps it's orderly
         | to other people. I mean it would be nice if a software system
         | defined with code could be expressed with a set of independent
         | patches where each patch is "atomic" and a feature or a fix
         | etc, to the degree it is possible. With Git, that's a near-
         | impossibility _in the graph_ -- sure you can cherry-pick or
         | rebase a set of commits that belong to a feature (normally on a
         | feature branch), but _why_?
        
           | barrkel wrote:
           | By "unit of work", I mean the atomic delta which can, on its
           | own, become part of the deployable state of the software. The
           | thing which has a Change-Id in Gerrit.
           | 
           | The delta is the important thing. Git is deficient in this
           | respect; it doesn't model a delta. Git hashes identify the
           | tip of a tree.
           | 
           | When you rebase, you ought to be rebasing the change, the
           | unit of work, a thing with an identity separate and
           | independent of where it is based from.
           | 
           | And this is something that the jujutsu / Gerrit model fixes.
        
         | josephg wrote:
         | CRDTs should be able to give you better merge and rebase
         | behaviour. They essentially make rebase and merge commits the
         | same thing - just different views on a commit, and potentially
         | different ways to present the conflict. CRDTs also behave
         | better when commits get merged multiple times in complex graphs
         | - you don't run into the problem of commits conflicting with
         | themselves.
         | 
         | You should also be able to roll back a single commit or chain
         | of commits in a crdt pretty easily. It's the same as the undo
         | problem in collaborative editors - you just apply the inverse
         | of the operation right after the change. And this would work
         | with conflicts - say commits X and Y+Z conflict, and you're in
         | a conflicting state, you could just roll back commit Y which is
         | the problem, while keeping X and Z. And at no point do you need
         | to resolve the conflict first.
         | 
         | All this requires good tooling. But in general, CRDTs can store
         | a superset of the data stored by git. And as a result, they can
         | do all the same things and some new tricks.
        
           | sroussey wrote:
           | In theory, maybe. In practice... last write wins (LWW) is a
           | CFDT operator, so replace every mention of CRDT with LWW and
           | issues will more obvious.
           | 
           | Really though, the problem with merges is not conflicts, it's
           | when the merged code is wrong but was correct on both sides
           | before the merge. At least a conflict draws your attention.
           | 
           | When I had several large (smart but young) teams merging left
           | and right this would come up and they never checked merged
           | code.
           | 
           | Multiply by x100 for AI slop these days. And I see people
           | merge away when the AI altered tests to suit the broken code.
        
             | josephg wrote:
             | > In practice... last write wins (LWW) is a CFDT operator,
             | so replace every mention of CRDT with LWW and issues will
             | more obvious.
             | 
             | Yeah. A lot of people are also confused by the twin
             | meanings of the word "conflict". The "C" in CRDT stands for
             | "Conflict (free)", but that really means "failure free".
             | Ie, given any two concurrent operations, there is a well
             | defined "merge" of the two operations. The merge operation
             | can't fail.
             | 
             | The second meaning is "conflict" as in "git commit
             | conflict", where a merge gets marked as requiring human
             | intervention.
             | 
             | Once you define the terms correctly, its possible to write
             | a CRDT-with-commit-conflicts. Just define a "conflict
             | marker" which are sometimes emitted when merging. Then
             | merging can be defined to always succeed, sometimes
             | emitting conflict markers along the way.
             | 
             | > Really though, the problem with merges is not conflicts,
             | it's when the merged code is wrong but was correct on both
             | sides before the merge.
             | 
             | CRDTs have strictly more information about whats going on
             | than Git does. At worst, we should be able to remake git on
             | top of CRDTs. At best, we can improve the conflict
             | semantics.
        
       | catlifeonmars wrote:
       | Can we stop using line-oriented diffs in favor of AST-oriented
       | diffs?
       | 
       | Is it just lack of tooling, or is there something fundamentally
       | better about line-oriented diffs that I'm missing? For the
       | purpose of this question I'm considering line-oriented as a
       | special case of AST-oriented where the AST is a list of lines
       | (anticipating the response of how not all changes are
       | syntactically meaningful or correct).
        
       | Aperocky wrote:
       | Outside of the merit of the idea itself, I thought I was going to
       | look at a repository at least as complete as Linus when he
       | released git after 3 weeks, especially with the tooling we had
       | today.
       | 
       | Slightly disappointed to see that it is a 470 line python file
       | being touted as "future of version control". Plenty of things are
       | good enough in 470 lines of python, even a merge conflict
       | resolver on top of git - but it looks like it didn't want
       | anything to do with git.
       | 
       | Prototyping is almost free these days, so not sure why we only
       | have the barest of POC here.
        
         | ithkuil wrote:
         | It clearly says in the article that this is just a demo
        
       | merlindru wrote:
       | I recently found a project called sem[1] that does git diffs but
       | is aware of the language itself, giving feedback like "function
       | validateToken added", "variable xyzzy removed", ...
       | 
       | i think that's where version control is going. especially useful
       | with agents and CI
       | 
       | [1] https://ataraxy-labs.github.io/sem/
        
       | lowbloodsugar wrote:
       | Araxis merge. Four views. Theirs, ours, base and "what you did so
       | far in this damned merge hell".
        
       | echrisinger wrote:
       | Has anyone considered a VCS that integrates more vertically with
       | the source code through ASTs?
       | 
       | IE if I change something in my data model, that change & context
       | could be surfaced with agentic tooling.
        
       | aggregator-ios wrote:
       | What CRDT's solve is conflicts at the system level. Not at the
       | semantic level. 2 or more engineers setting a var to a different
       | value cannot be handled by a CRDT.
       | 
       | Engineer A intended value = 1
       | 
       | Engineer B intended value = 2
       | 
       | CRDT picks 2
       | 
       | The outcome could be semantically wrong. It doesn't reflect the
       | intent.
       | 
       | I think the primary issue with git and every other version
       | control is the terrible names for everything. pull, push, merge,
       | fast forward, stash, squash, rebase, theirs, ours, origin,
       | upstream and that's just a subset. And the GUI's. They're all
       | very confusing even to engineers who have been doing this for a
       | decade. On top of this, conflict resolution is confusing because
       | you don't have any prior warnings.
       | 
       | It would be incredibly useful if _before_ you were about to edit
       | a file, the version control system would warn you that someone
       | else has made changes to it already or are actively working on
       | it. In large teams, this sort of automation would reduce
       | conflicts, as long as humans agree to not touch the same file.
       | This would also reduce the amount of quality regressions that
       | result from bad conflict resolutions.
       | 
       | Shameless self plug: I am trying to solve both issues with a
       | simpler UI around git that automates some of this and it's free.
       | https://www.satishmaha.com/BetterGit
        
         | jnsie wrote:
         | > It would be incredibly useful if before you were about to
         | edit a file, the version control system would warn you that
         | someone else has made changes to it already or are actively
         | working on it. In large teams, this sort of automation would
         | reduce conflicts, as long as humans agree to not touch the same
         | file. This would also reduce the amount of quality regressions
         | that result from bad conflict resolutions.
         | 
         | Bringing me back to my VSS days (and I'd much rather you
         | didn't)
        
           | aggregator-ios wrote:
           | I knew I should have put a trigger warning, because I was
           | thinking of this as I was typing it. Sorry!
        
         | mbfg wrote:
         | well, the mismatch here is widened by the fact that almost
         | everyone it seems uses git with a central, prominent, visible,
         | remote repository. Where as git was developed with the a true
         | distributed vision. Now sure that truely distributed thing only
         | becomes final when it reaches some 'central' repo, but it's
         | quite a big different than we all do.
        
         | j1elo wrote:
         | For that you need a _very centralized_ VCS, not a decentralized
         | one. Perforce allows you to lock a file so everybody else
         | cannot make edits to it. If they implemented more fine-grained
         | locking within files, or added warnings to other users trying
         | to check them out for edits, they 'd be just where you want a
         | VCS to be.
         | 
         | How, or better yet, why would Git warn you about a potential
         | conflict beforehand, when the use case is that everyone has a
         | local clone of the repo and might be driving it towards
         | different directions? You are just supposed to pull commits
         | from someone's local branch or push towards one, hence the
         | wording. The fact that it makes sense to cooperate and work on
         | the same direction, to avoid friction and pain, is just a
         | natural accident that grows from the humans using it, but is
         | not something ingrained in the design of the tool.
         | 
         | We're collectively just using Git for the silliest and simplest
         | subset of its possibilities -a VCS with a central source of
         | truth-, while bearing the burden of complexity that comes with
         | a tool designed for distributed workloads.
        
         | sensanaty wrote:
         | I haven't used them, but doesn't SVN or Mercurial do something
         | like this? It blocks people from working on a file by locking
         | them, the problem is that in large teams there are legitimate
         | reasons for multiple people to be working on the same files,
         | especially something like a large i18n file or whatever.
        
         | josephg wrote:
         | > CRDT picks 2
         | 
         | They don't have to.
         | 
         | The crdt library knows that value is in conflict, and it
         | decides what to do about it. Most CRDTs are built for realtime
         | collab editing, where picking an answer is an acceptable
         | choice. But the crdt can instead add conflict marks and make
         | the user decide.
         | 
         | Conflicts are harder for a crdt library to deal with - because
         | you need to keep merging and growing a conflict range. And do
         | that in a way that converges no matter the order of operations
         | you visit. But it's a very tractable problem - someone's just
         | gotta figure out the semantics of conflicts in a consistent way
         | and code it up. And put a decent UI on top.
        
       | ballsweat wrote:
       | Cool timing.
       | 
       | I recently built Artifact:
       | https://www.paganartifact.com/benny/artifact
       | 
       | Mirror: https://github.com/bennyschmidt/artifact
       | 
       | In case anyone was curious what a full rewrite of git would look
       | like in Node!
       | 
       | The main difference is that on the server I only store deltas,
       | not files, and the repo is "built".
       | 
       | But yeah full alternative to git with familiar commands, and a
       | hub to go with it.
        
       | injidup wrote:
       | I'm confused about what this solves. They give the example of
       | someone editing a function and someone deleting the same function
       | and claim that the merge never fails and then go on to
       | demonstrate that indeed rightly the merges still fails. There are
       | still merge markers in the sources. What is the improvement
       | exactly?
        
         | galkk wrote:
         | Yeah, the author fails to present his case even in the intro
         | 
         | > A CRDT merge always succeeds by definition, so there are no
         | conflicts in the traditional sense -- the key insight is that
         | changes should be flagged as conflicting when they touch each
         | other, giving you informative conflict presentation on top of a
         | system which never actually fails. This project works that out.
         | 
         | It has clear contradiction. Crdt always succeed by definition,
         | no conflicts in traditional sense so (rephrasing) conflicting
         | changes are marked as conflicted. Emm, like in any other source
         | control?
         | 
         | In fact, after rereading that intro while writing that answer I
         | start suspect at least smell of an ai writing.
        
           | fleebee wrote:
           | The README of the repo offers a hint:
           | 
           | > _The code in this project was written artisanally. This
           | README was not._
        
           | josephg wrote:
           | The benefit of using a crdt for this is that you can get
           | better merge semantics. Rebase and merge become the same
           | thing. Commits can't somehow conflict with themselves. You
           | can have the system handle 2 non conflicting changes on the
           | same line of code if you want. You can keep the system in a
           | conflict state and add more changes if you want to. Or undo
           | just a single commit from a long time ago. And you can put
           | non text data in an crdt and have all the same merge and
           | branching functionality.
        
       | ballsweat wrote:
       | Everyone should vibe code a VCS from scratch in their fave
       | language.
       | 
       | It's an awesome weekend project, you can have fun visualizing
       | commits in different ways (I'm experimenting with shaders), and
       | importantly:
       | 
       | This is the way forward. So much software is a wrapper around S3
       | etc. now is your chance to make your own toolset.
       | 
       | I imagine this appeals more to DIYer types (I use Pulsar IDE lol)
        
       | braidedpubes wrote:
       | Do I have it right that it's basically timestamp based, except
       | not based on our clocks but one it manages itself?
       | 
       | So as long as all updates have been sent to the server from all
       | clients, it will know what "time" each character changed and be
       | able to merge automatically.
       | 
       | Is that it basically?
        
       | shitfilleddonut wrote:
       | It seems more like the past of version control
        
       | EGreg wrote:
       | I remember I met Bram Cohen (of Bittorent fame!) around 15 years
       | ago. Around that time is when I had started building web-based
       | distributed collaborative systems, starting with Qbix.com and
       | then spun off a company to build blockchain-based smart contracts
       | through Intercoin.org etc.
       | 
       | Anyway, I wanted to suggest a radical idea based on my
       | experience:
       | 
       | Merges are the wrong primitive.
       | 
       | What organizations (whethr centralized or distributed projects)
       | might actually need is:
       | 
       | 1) Graph Database - of Streams and Relations
       | 
       | 2) Governance per Stream - eg ACLs
       | 
       | A code base should be automatically turned into a graph database
       | (functions calling other functions, accessing configs etc) so we
       | know exactly what affects what.
       | 
       | The concept of what is "too near" each other mentioned in the
       | article is not necessarily what leads to conflicts. Conflicts
       | actually happen due to conflicting graph topology and propagating
       | changes.
       | 
       | People should be able to clone some stream (with permission) and
       | each stream (node in the graph) can be versioned.
       | 
       | Forking should happen into workspaces. Workspaces can be
       | GOVERNED. Publishing some version of a stream just means relating
       | it to your stream. Some people might publish one version, others
       | another.
       | 
       | Rebasing is a first-class primitive, rather than a form of
       | merging. A merge is an extremely privileged operation from a
       | governance point of view, where some actor can just "push" (or
       | "merge") thousands of commits. The more commits, the more chance
       | of conflicts.
       | 
       | The same problem occurs with CRDTs. I like CRDTs, but reconciling
       | a big netsplit will result in merging strategies that create lots
       | of unintended semantic side effects.
       | 
       | Instead, what if each individual stream was guarded by policies,
       | there was a rate limit of changes, and people / AIs rejected most
       | proposals. But occasionally they allow it with M of N sign offs.
       | 
       | Think of chatgpt chats that are used to modify evolving
       | artifacts. People and bots working together. The artifacts are
       | streams. And yes, this can even be done for codebases. It isnt
       | about how "near" things are in a file. Rather it is about whether
       | there is a conflict on a graph. When I modify a specific function
       | or variable, the system knows all of its callers downstream. This
       | is true for many other things besides coding too. We can also
       | have AI workflows running 24/7 to try out experiments as a swarm
       | in sandboxes, generate tests and commit the results that pass.
       | But ultimately, each organization determines whether they want to
       | rebase their stream relations to the next version of something or
       | not.
       | 
       | That is what I'm building now with https://safebots.ai
       | 
       | PS: if anyone is interested in this kind of stuff, feel free to
       | schedule a calendly meeting w me on that site. I just got started
       | recently, but I'm dogfooding my own setup and using AI swarms
       | which accelerates the work tremendously.
        
       | theknarf wrote:
       | You can't use CRDTs for version control, having conflicts is the
       | whole point of version control. Sometimes two developers will
       | make changes that fundamentally tries to change the code in two
       | different ways, a merge conflict then leaves it up to the
       | developer who is merging/rebasing to make a choice about the
       | semantics of the program they want to keep. A CRDT would just
       | produce garbage code, its fundamentally the wrong solution. If
       | you want better developer UX for merge conflicts then there are
       | both a bunch of tooling on top of Git, as well as other version
       | control systems, that try to present it in a better way; but that
       | has very little to do with the underlaying datastructure. The
       | very fact that cherry-picking and reverting becomes difficult
       | with this approach should show you that its the wrong approach!
       | Those are really easy operations to do in Git.
        
         | tbrownaw wrote:
         | > _You can 't use CRDTs for version control_
         | 
         | You misunderstand what is being proposed.
         | 
         | Using CRDTs to calculate the results of a merge _does not
         | require_ being allowed to commit the results of that
         | calculation, and doesn 't even require that you be able to
         | physically realize the results in the files in your working
         | copy.
         | 
         | .
         | 
         | Consider for example if you want to track and merge scalar
         | values. Maybe file names if you track renames, maybe file
         | properties if you're not just using a text listing (ie
         | .gitattributes) for that, maybe file content hash to decide
         | whether to actually bother running a line-based merge.
         | 
         | One approach is to use what Wikipedia says is called an OR-
         | set[1], with the restriction that a commit can only have a
         | single unique value; if it was previously in the set then it
         | keeps all the same tags, if it wasn't then it gets a new tag.
         | 
         | That restriction is where the necessity of conflict resolution
         | comes in. It doesn't have to be part of the underlying
         | algorithms, just the interface with the outside world.
         | 
         | [1] https://en.wikipedia.org/wiki/Conflict-
         | free_replicated_data_...
        
           | Retr0id wrote:
           | If semantics-layer conflicts still have to be detected
           | somehow, and resolved by hand, what value is the underlying
           | CRDT providing?
        
       | astrostl wrote:
       | Disagree. We all are -- or should be -- Linux kernel developers.
       | What's more, we should align to a specific and singular VCS
       | worldview informed by BitKeeper, which no longer exists, whether
       | or not we used it. Therefore Git. Thank you for your attention to
       | this matter!
        
         | simultsop wrote:
         | You sound more like a DOS dev instead of linux.
        
       | Ferret7446 wrote:
       | I'm pretty sure jujutsu already does this, and it's interopable
       | with git
        
       | nailer wrote:
       | You're still treating code as text which it isn't (in the same
       | way you wouldn't treat JSON as text) it's actually more like an
       | AST.
       | 
       | Jujutsi (jj) does that. And it's git compatible.
        
         | dcre wrote:
         | I love jj and think virtually every git user should switch to
         | it, but I don't think it treats text as an AST. What do you
         | mean?
        
       | mweidner wrote:
       | I'm surprised to see the emphasis on tracking lines of text,
       | which ties in to the complexity of merge vs merge-the-other-way
       | vs rebase. If we are committed to enhancing the change history,
       | it seems wiser to go all in and store high-level, semantically-
       | meaningful changes, like "move this code into an `if` block and
       | add `else` block ...".
       | 
       | Consider the first example in the readme, "Left deletes the
       | entire function [calculate]. Right adds a logging line in the
       | middle". If you store the left operation as "delete function
       | calculate<unique identifier>" and the right operation as "add
       | line ... to function calculate", then it's obvious how to get the
       | intended result (calculate is completely deleted), regardless of
       | how you order these operations.
       | 
       | I personally think of version control's job not as collaborating
       | on the actual files, but as collaborating on the canonical order
       | of (high-level) operations on those files. This is what a branch
       | is; merge/rebase/cherry-pick are ways of updating a branch's
       | operation order, and you fix a conflict by adding new operations
       | on top. (Though I argue rebase makes the most sense in this
       | model: your end goal is to append to the main branch.)
       | 
       | Once you have high-level operations, you can start adding high-
       | level conflict markers like "this operation changed the docs for
       | function foo; flag a conflict on any new calls to foo". Note that
       | you will need to remember some info about operations' original
       | context (not just their eventual order in the main branch) to
       | surface these conflicts.
        
       | philwelch wrote:
       | Regardless of the merits of CRDT's, I'm just glad someone is
       | finally trying to create a new version control system. Everyone
       | loves to complain about Git but nobody's actually tried to move
       | beyond it in two decades.
        
       | KPGv2 wrote:
       | I've tested out jj a bit, and doesn't it solve the issues
       | presented at the link already? I don't work on a team where I
       | need VC better than git, so I just stick with it for my own
       | private use, but I did test jj out of curiosity, and I could've
       | sworn this is basically the same pitch as switching to jj (but
       | for the CRDT under the hood).
        
       ___________________________________________________________________
       (page generated 2026-03-22 23:00 UTC)