[HN Gopher] Mergiraf: Syntax-Aware Merging for Git
       ___________________________________________________________________
        
       Mergiraf: Syntax-Aware Merging for Git
        
       Author : Velocifyer
       Score  : 145 points
       Date   : 2025-11-03 14:54 UTC (10 days ago)
        
 (HTM) web link (lwn.net)
 (TXT) w3m dump (lwn.net)
        
       | pavelai wrote:
       | Very impressive enhancement. Not a panacea though. It uses tree-
       | sitter approach to solve situations when two users change the
       | same line of code. For example one change function name and other
       | adds a new argument. It will merge it without conflicts. It still
       | has some troubles to solve complex issues, without knowing author
       | intensions. But can significantly simplify developers' lives. Not
       | sure if it would land into git very soon. It requires all git to
       | know all the parsers you need. But definitely worth adding.
        
         | Velocifyer wrote:
         | This is a seprate tool that one can tell git to use.
        
         | 1718627440 wrote:
         | What does it do, when the change in function name mean that the
         | number of spaces before each parameter (alignment) changed?
        
       | mnemonet wrote:
       | This is a very interesting idea that could save a lot of time and
       | pain in big projects.
       | 
       | The example shown reminds me pf Zed's CRDTs [1], and their
       | journey to build a fine-grained version control system for
       | agentic development [2]--I imagine this work could prove useful
       | to the Zed/Cursor team, and likely shares a lot of functionality
       | with DeltaDB [2].
       | 
       | - [1]: https://zed.dev/blog/crdts
       | 
       | - [2]: https://zed.dev/blog/sequoia-backs-zed
        
         | vinnyhaps wrote:
         | I'm pretty sure one of the Zed founders wrote tree-sitter, so
         | I'm sure there's some overlap
         | 
         | It's really cool to see tree-sitter unlock so many of these use
         | cases. I love using [difftastic] for my diffing tool to get
         | context aware diffs. So in the example from the article, the
         | diff would highlight the `void` and `int` changes with a
         | heavier background of red and green respectively
         | 
         | [difftastic]: https://github.com/Wilfred/difftastic
        
           | conartist6 wrote:
           | Max Brunsfeld in fact, yep. He went along to Zed from the
           | Atom team.
           | 
           | But curiously Zed hasn't been very interested in Tree-sitter.
           | They don't seem to see it as having much strategic value to
           | their company, which is odd because lots of other people do
           | see it as a valuable platform. You have Tweag building code
           | formatting on it, you had GitHub building stack graphs on it,
           | you have Merigraph. You even have sone really "out there"
           | stuff like the Software Evolution Library!
        
             | olejorgenb wrote:
             | They use it quite a bit in Zed though. What do you count as
             | "not very interested"?
        
       | ltbarcly3 wrote:
       | claude "resolve merge conflicts"
        
         | littlestymaar wrote:
         | Using 30s worth of H100 GPU instead of <10ms worth of an entry-
         | level CPU, for a worse result.
         | 
         | Well done.
        
           | ltbarcly3 wrote:
           | "Compositing text into graphical data to display it on a 2D
           | array of millions of 32bit RGB pixels instead of just using a
           | pencil and a 50 cent notebook."
           | 
           | Actually I've done this a hundred times now and it has yet to
           | make a single mistake. I don't give a crap how much GPU it
           | uses, grandpa.
        
         | Cthulhu_ wrote:
         | OK, I'm going to try and resolve these merge conflicts for you!
         | 
         | First, let me pull up the diff and git status
         | 
         | ......
         | 
         | ....
         | 
         | ...
         | 
         | .
         | 
         | Hmm, that didn't quite work, let me try that again!
        
           | ltbarcly3 wrote:
           | I've resolved hundreds of conflicted merges this way and I
           | don't remember it making a single mistake.
        
             | n4r9 wrote:
             | Might that be because LLMs are potentially negatively
             | impacting your memory?
        
               | ltbarcly3 wrote:
               | Yea that's probably it. Or you're wrong? One of those for
               | sure.
        
       | jayd16 wrote:
       | I wish there were a lot more syntax aware merges built into git
       | (et al). Why are separate columns on the same row of a CSV or
       | multiple appends to a list (in any language you don't want a
       | trailing comma) so annoying to merge?
       | 
       | It could be so much better.
        
       | sysguest wrote:
       | finally...
       | 
       | I've been using 1-arg-1-line to avoid most conflicts
        
         | Cthulhu_ wrote:
         | I've been doing some SQL again and one technique I learned
         | years ago was having each thing on its own line, both to reduce
         | churn in version control and allow for easier reordering and
         | commenting out.
         | 
         | Instead of                   SELECT foo, bar, quux FROM baz
         | WHERE storge = 'grault';
         | 
         | do                   SELECT            foo           ,bar
         | ,quux         FROM           baz         WHERE           storge
         | = 'grault'         ;
         | 
         | It's pretty hideous in this example but for bigger queries
         | maintained over a long period of time it can be beneficial. I
         | assume, it's been nearly 20 years since I did anything more
         | serious with SQL.
        
       | Valodim wrote:
       | fyi, comes configured in jj by default. Just `jj resolve --tool
       | mergiraf` and some conflicts go away :)
        
       | mentalgear wrote:
       | - Related in fine-grained diffing approach: Git heatmap: diff
       | viewer for code reviews
       | 
       | > Heatmap color-codes every diff line/token by how much human
       | attention it probably needs. Unlike PR-review bots, we try to
       | flag not just by "is it a bug?" but by "is it worth a second
       | look?" (examples: hard-coded secret, weird crypto mode, gnarly
       | logic).
       | 
       | https://0github.com/
        
         | Valodim wrote:
         | The idea is cool but boy does it make you blind to anything the
         | AI doesn't deem noteworthy. Comes down to whether you trust a
         | human reviewer more, or the LLM
        
         | worldsayshi wrote:
         | Hmm, it would be nice to just see a heatmap over how many times
         | a line has been changed. There must be some easy-ish way to do
         | that right?
        
           | Cthulhu_ wrote:
           | I think you'd need to write a tool that goes through all
           | revisions of a file and does a count, but if that's cached
           | then it's doable. There's a few tools to view that by file
           | though, including some Git commands, it's a valuable tool to
           | determine which files are edited the most (see also the word
           | "churn").
        
       | paulirish wrote:
       | Have been using Mergiraf for the past 4 months. It's
       | automatically solved about 70% of my conflicts and, luckily, I've
       | never contested any of them. Pretty pleased.
        
         | Sesse__ wrote:
         | This is my experience as well. Not a gamechanger, but
         | definitely on the positive side.
        
         | goku12 wrote:
         | > luckily, I've never contested any of them.
         | 
         | That's to be expected. The philosophy behind git merges is that
         | it will merge only if it is absolutely and unambiguously sure
         | that the resolution is correct. That's when there is only one
         | solution for the merge. It will just throw it's hands up and
         | leave it to the developer if there is any ambiguity - that's if
         | there's more than one way to do the merge.
         | 
         | Every single chunk of merge is a potential conflict. But have
         | you ever contested the regular merge algorithm (ort by default)
         | when it did work? Like when the merge was fully successful, or
         | the successfully merged chunks within a conflicted merge? You
         | can expect the same experience with any merge algorithm that
         | sticks to the git philosophy of being a git [1]. Problems will
         | happen only if they start using some complex heuristics or LLM
         | or something unpredictable like that for the merge.
         | 
         | > It's automatically solved about 70% of my conflicts
         | 
         | At the risk of explaining the obvious, I'm going to try to
         | explain this. (So please don't get angry at me if you already
         | know this.) Imagine that you're trying to manually merge 2
         | branches without any sort of merge algorithm. For the first
         | case, just assume that you don't know the programming language
         | (imagine that it's in some foreign script). All you have to go
         | by is the record of when each line was added in each branch.
         | The best 'dumb' strategy you have to go with, is the 3-way
         | merge [2]. The referenced page illustrates this. It clearly
         | shows you the advantage of the 3-way merge algorithm over the
         | traditional 2-way merge that we all are familiar with.
         | 
         | But this method still has a disadvantage. You are looking at
         | the source files simply as a bunch of lines, without the
         | knowledge of its more granular structures like the syntax.
         | (Note: That assumption itself may be wrong. That's why merges
         | and git in general doesn't work well on binary files.) At best,
         | all you can hope for is that the two branches don't contain any
         | edits on the same or the adjacent lines. You won't even know
         | the order in which the lines should be arranged. Now you have a
         | conflict - a merge that you're leaving for someone else to
         | solve.
         | 
         | Now assume a second case. You know the programming language
         | this time. But you have no idea what the program does - it's
         | not your project. Even with that limitation, you'll still be
         | able to do a better job than just comparing the lines blindly.
         | Mergiraf docs has a page full of these examples [3]. You can
         | see how obvious the merges look - there is no way you can go
         | wrong. See if you can resolve them just by looking at the
         | lines. That's why mergiraf gives you much better performance
         | without any errors.
         | 
         | There is of course a deeper level of knowledge - the semantic
         | level. The knowledge of what the program does. You need that
         | knowledge to resolve 100% of the merges. And that ultimate
         | merge algorithm is ... you.
         | 
         | > Pretty pleased.
         | 
         | Understandable. But I see a potential problem here. As you are
         | aware, the files to submit to mergiraf are specified in the
         | gitattributes file. There are two ways this can go wrong.
         | First, someone else with your repo may not have or even know
         | about mergiraf. The second, even bigger problem is that some
         | people have global gitattributes files [4] where you place your
         | default attributes. It's possible to setup mergiraf there. But
         | if you do so, your colleagues may not even get a clue as to why
         | certain merges succeed for you, but fail for all of them.
         | 
         | The above problem becomes a bigger issue because merge and
         | rebase conflicts sometimes reappear in later merges or rebases.
         | If that's something mergiraf can solve and you have it, then
         | everything's fine. But if the conflict reappears for someone
         | without mergiraf, they will have to repeat the manual
         | resolution again and again. This happens because git simply
         | wont commit a merge or rebase until we resolve the conflict
         | manually. Therefore, git has no idea what we did in between to
         | resolve it - that is not recorded anywhere. (Well, git-rerere
         | [5] records it if we ask it to. But that's a local-only
         | solution. Everyone will have to do it once on their system.)
         | 
         | There is actually a known solution to the problem. It's called
         | 'first class conflicts' [6]. The idea is to record the
         | conflicts and its resolution in the repo itself (the same info
         | that rerere stores, but in the shared repo). This means that a
         | conflict once resolved will not come back again, because the
         | structured information to resolve it is available in the repo.
         | This means not everyone needs mergiraf and nobody needs to
         | repeat a completed manual resolution. It has other advantages
         | too. You can just continue working after a conflicted merge and
         | leave the resolution for later. Or you could send the conflicts
         | to someone else more specialized in that area of the code.
         | 
         | I have seen this feature in Jujutsu [6] and Pijul [7]. Git
         | doesn't have it probably because this wasn't around when it was
         | developed. But Jujutsu uses git repository format and they
         | somehow managed to implement first-class conflicts on it.
         | Meanwhile, the concept is already there in git as rerere. So
         | perhaps first-class conflicts are possible in Git too. It would
         | be awesome if we had that in Git too. So if anybody who sees
         | this knows how to do it, please please take it up as a wish!
         | 
         | [1]
         | https://github.com/git/git/blob/e83c5163316f89bfbde7d9ab23ca...
         | 
         | [2] https://blog.git-init.com/the-magic-of-3-way-merge/
         | 
         | [3] https://mergiraf.org/conflicts.html
         | 
         | [4] https://git-scm.com/docs/git-config#Documentation/git-
         | config...
         | 
         | [5] https://git-scm.com/docs/git-rerere
         | 
         | [6] https://jj-vcs.github.io/jj/latest/conflicts/
         | 
         | [7] https://pijul.com/manual/why_pijul.html#modeling-conflicts
        
           | 1718627440 wrote:
           | > But have you ever contested the regular merge algorithm
           | (ort by default) when it did work?
           | 
           | Depends on what you mean by 'contested', but yes. You can
           | have "merge conflicts", that are even correct as far as the
           | syntax is concerned, but are garbage on a semantic level.
        
             | goku12 wrote:
             | I'm not talking about the conflicts. I'm talking about the
             | hunks that were resolved successfully. Sometimes they're
             | part of successful merges. Sometimes they're part of
             | conflicted merges where some other hunk was in conflict.
        
               | 1718627440 wrote:
               | Me too. A merge can be entirely without merge conflicts
               | and still wrong, because it has (semantic or
               | architectural) "merge conflicts".
        
       | gritzko wrote:
       | > After extracting a list of every merge conflict in the kernel's
       | Git history, I tried using Mergiraf to resolve them. 6,987 still
       | resulted in conflicts, but 428 were resolved successfully. A much
       | larger fraction of merge conflicts were still partially resolved.
        
         | bjackman wrote:
         | Take this with a grain of salt as I haven't tested this claim,
         | but I think C might be a pretty weak language for this tool
         | because you can't really parse it without running the whole
         | preprocessor, which it can't do:
         | 
         | https://codeberg.org/mergiraf/mergiraf/issues/612#issuecomme...
         | 
         | So I think in a more sensible language you might get much
         | better results than this.
        
           | gritzko wrote:
           | Another aspect is the fact this repo reflects Torvalds' view
           | of the world. He operates in large-ish changesets.
        
       | scoodah wrote:
       | Way back in the day when I primarily wrote c# I used to use a
       | tool called SemanticMerge. It was pretty cool, it actually parsed
       | the code and could pick up refactors like moving a method to a
       | different class and what not. This kinda reminds me of that a
       | bit.
        
         | Cthulhu_ wrote:
         | Yeah, the article mentions a similar project for Java; I'm a
         | bit surprised / disappointed that there's no more language
         | specific merge tools tbh, or a super-tool that has plugins for
         | individual languages. Maybe this article will attract more
         | attention though.
        
       | James_K wrote:
       | Very interesting to see what Tree Sitter starting to get used for
       | more things.
        
       | virajk_31 wrote:
       | I really liked the last section of your article, thanks for the
       | numbers
        
       | 1718627440 wrote:
       | > Therefore, this merge conflict can be resolved automatically by
       | putting the lines in any order. The resulting merged program has
       | the same behavior either way.
       | 
       | That means that if I the programmer care about the order, I must
       | now review lines, where no merge conflict is indicated. I am not
       | sure I would like that.
        
       | indentit wrote:
       | I tried using Mergiraf a year or so ago, and ended up with so
       | many weird problems that I eventually tracked down to being
       | caused by it, that I disabled and uninstalled it and never looked
       | back - it was more hassle than it was worth
        
       ___________________________________________________________________
       (page generated 2025-11-13 23:02 UTC)