From: Antonio Mennillo Date: Sun, 21 Sep 2025 14:06:12 GMT Subject: Re: [RFC] git-rebase-clean: mitigating a “semantic conflict cascade” during rebase Message-ID: In-Reply-To: Hi, Sorry for the duplicate earlier, I realized my email was rejected by the mailing list for being HTML, I have no pc available now. Resending in plain text Thank you again for your detailed and thoughtful response. I apologize for my delayed reply. I'm currently traveling and away from my development environment, which is making it difficult to properly address all the important technical points you've raised. I don't find your emails as negative, quite the opposite, I repeat: it's precious insight and experience sharing. Please expect my detailed response by Wednesday at the latest. I appreciate your patience and the time you've taken to engage so deeply with this proposal. Best regards, Antonio Il giorno sab 20 set 2025 alle ore 21:14 Elijah Newren ha scritto: > > Hi, > > On Fri, Sep 19, 2025 at 2:17 PM Antonio Mennillo > wrote: > > > > Hi Brian, > > > > Thank you again for the feedback, it gave me a fundamental piece of > > puzzle about Git's design constraints that I hadn't fully considered. > > > > You're right about tree-sitter being inappropriate for Git core. That > > approach is too narrow, covering only specific languages. My v2.0.0 > > already prioritizes Git's existing plumbing to track content changes > > universally, with tree-sitter as an optional enhancement. This stays > > content-agnostic and removes that which I can define as a source of > > nondeterminism and heuristic complexity that it's elegant to avoid. > > > > To summarize the mechanism: > > > > 1) Squash the feature branch into a single commit: temporarily > > compressing the branch makes all internal semantic dependencies > > visible at once, avoiding cascade conflicts during step-by-step rebase > > with non-atomic commits. > > > > 2) Resolve conflicts once with full context: the semantic issues are > > "suspended" in this unified state where everything is coherent. > > > > 3) Restore original commits by replaying saved diffs: using a > > hash-based approach with git's native diff/apply machinery, the tool > > remains file-type agnostic. The restored commits may still break > > individually (e.g., won't compile in isolation), but the branch is now > > rebased with granular history preserved. > > I don't understand how this is possible, other than in trivial cases. > Lots of questions: > > How exactly is replaying the saved diffs supposed to work? Replaying > those diffs would run into conflicts, otherwise you wouldn't have been > trying to search for a modified strategy in the first place. How do > you resolve those? Are you assuming all conflicts are orthogonal, > i.e. that the conflicts from patches A and B are never on overlapping > or even nearby lines to each other? In such a case, there wouldn't be > any "cascade of conflicts" to resolve anyway, so the approach would be > unnecessary. And if this isn't true, then I don't see how you can > resolve all the conflicts at once and magically split them out into > separate commits and replay things in a way that doesn't have > conflicts -- at least not without further human intervention. > > And that was focusing on content conflicts. What do you do with > non-content conflicts, such as file mode differences, file/directory > conflicts, symlink/submodule conflicts, rename conflict, directory > rename conflict, etc.? > > But going back to content conflicts, are you somehow sidestepping the > need to assume orthogonality? Perhaps when you attempt to replay and > hit a conflict, you just take the end-result for that hunk range for > the first patch that touches it, and for any other patch that touches > that hunk range you simply discard the changes for those since they've > been squashed into the first patch? Or something similar? > > As another way to look at this problem, what about cases where > individual commits being replayed will conflict, but merging the end > result has no conflicts? (In other words, only the intermediate > states had a conflict of some type -- a simple example of this is > someone making a change and then shortly later reverting it.) In such > a case, by resolving conflicts only at the end, there was no > resolution of the conflicts experienced by those intermediate states. > What do you do there? > > What about cases like > https://git-scm.com/docs/gitfaq#Documentation/gitfaq.txt-IfImakeachangeontwobranchesbutrevertitononewhydoesthemergeofthosebranchesincludethechange > (both sides of history make a change, and one side also reverts that > change) -- by merging the squashed result, you'd end up with the > change being applied, but when you try to split it out into separate > commits, you have "apply the change" followed by "revert the change" > -- how does that result in the change being applied in the end result? > > Are there cases where your algorithm feels indistinguishable from > squashing all the commits, having the user resolve conflicts, and then > randomly assigning the hunks to a completely new set of commits > (beyond the obvious differences in commit messages and perhaps number > of commits)? Every algorithm I can think of for automatically playing > existing commits while only resolving conflicts at the end would seem > to sometimes suffer from this kind of downside, but it's entirely > possible I'm only thinking of a few brute force algorithms and I'm > missing something clever that you might be doing. > > > To address your header file example specifically: when common.h no > > longer includes stdlib.h after rebasing onto main, you would indeed > > need to add #include during conflict resolution. With my > > tool, you'd add this include once while resolving the squashed > > commit's conflicts. The fix then persists through all restored commits > > - so instead of potentially fixing the same missing header multiple > > times across commits during a normal rebase, you handle it once. > > You're correct that the tool cannot determine which specific commit > > should ideally contain this fix (that would require compilation > > testing), but it prevents the cascading resolution burden while > > preserving the granular history. > > I think there may have been a misunderstanding here. The purpose > wasn't granular history, it was meaningful logical commits; those tend > to come in granular sizes, but granularity was more of a side-effect > rather than the purpose. Having a disfigured granular history is quite > different than meaningful logical commits. > > > The key point: this doesn't fix non-atomic commits. The semantic > > problems remain if you examine individual commits. But it prevents > > these issues from causing redundant conflict resolution during rebase > > by compressing the timeline of the branch in a single instant "t" > > where the semantic non-atomic misalignment appears simultaneously. > > > > The tool trades ideal per-commit correctness for efficiency in > > real-world scenarios where atomic commits aren't always achievable > > (junior developers, emergency fixes, legacy codebases). > > I'm pretty biased here, but let me take exception with your wording > that these are not achievable cases. I'm going to push back on that, > rather strongly. In fact, I'd go further and say that legacy > codebases are where logical small commits make the *most* sense > (sometimes with small new projects the "why" and the "what" you're > doing is obvious and so there's not much to write in a commit message, > and anyone can follow along, whereas in a legacy codebase you need to > carefully document why you are making changes and ensure each change > in isolation makes sense so others can figure out why each line of > code does what it does). In regards to junio developers, letting > junior developers develop bad habits (and even facilitating such) just > leads to them later being senior developers with bad habits; I think > it'd be better to take the time to coach them on proper practices > instead. And in the remaining case, what you describe sounds to me > like a rushed emergency fix, and I feel like rushed emergency fixes > result in more emergencies later. > > I understand that many are reluctant to put in the effort to make > clear, logical commits, but I feel that each of your cases are > examples of unwillingness or lack of training, not an actual > inability. > > As noted above, I'm quite biased here, and would rather encourage > people to make clear, logical, easy-to-follow-and-review-years-later > steps that are documented as commits. I think tools which encourage > or facilitate doing the opposite are things that should be shunned. > (I hate squash-merging in GitHub for this reason, and GitHub's lack of > focus on treating commit messages as important first-class material > for review has long bothered me deeply, as I've commented elsewhere.) > Others are free to disagree with me and pursue their own path, but > that's my position. > > > Regarding expectations: documentation will be clear that this only > > reduces redundant conflict resolution. It doesn't make commits atomic > > or understand semantics. It manages semantic inconsistency by > > compression, intended as reduced dimensionality. The defects remain in > > history but no longer interfere with rebasing. > > > > I apologize if the code evolution seems rushed - v2.0.0 was developed > > quickly to establish a working implementation of the core concept. For > > v3.0.0, I plan to remove tree-sitter entirely to achieve complete > > language-agnosticism. I'll also need to properly evaluate edge cases > > like submodules and merge commits through integration testing, though > > the squash operation should hopefully be quite independent from these > > structures. My testing focus will be on ensuring determinism, proper > > rollback capabilities, and full idempotency across all supported > > scenarios. > > > > The current implementation is available at > > https://github.com/anthem87/clean-rebase/tree/v2.0.0 if you'd like to > > explore the approach. > > > > Thanks again for the patience and the attention. > > I hope my email doesn't come across as too negative. I'm a big fan of > exploring and attempting new things. While I am biased against tools > that work against logical & bisectable changes, and I'm worried your > tool is going to face an awful lot of problematic cases if you > continue with it, hopefully my email provides more context for you and > alerts you to some cases you might need to investigate if you want to > push the tool further. > > Even if I am not in the camp that'd be interested in using your tool, > I am very curious if you have clever ideas for any of the special > cases I listed above and how to handle them; sometimes any such ideas > might have ways of being wielded elsewhere.