Subject: Re: [RFC] git-rebase-clean: mitigating a “semantic conflict cascade”during rebase

From: "brian m. carlson" <[email-masked]>
Date: Thu, 18 Sep 2025 22:22:22 +0000

On 2025-09-18 at 17:02:59, Antonio Mennillo wrote:
> Hi Brian,
> 
> Thank you for the thoughtful response, and please excuse me if I am a
> bit clumsy —
> this is my first interaction with the Git community.
> 
> > Usually we would recommend that each commit be atomic...
> 
> I perfectly understand this best practice. In my context, working with
> many junior developers,
> it is not always possible to enforce atomic commits. In some
> “emergency” situations we
> squashed just to make progress, even if that meant losing granularity.

Yeah, I've seen that at previous employers.  Even where I work now, I
definitely see differing levels of interest in atomic commits with nice
commit messages.

> Your explanation really helped me see things more clearly, and I appreciated
> the constructive (non-toxic) way you put it.

Well, thank you.

> Yes, rerere helps with repeated textual conflicts, but the scenario I
> worry about
> is semantic: if commit M changes an interface and commit N implements it, then
> changing M during rebase can make N semantically invalid. rerere
> cannot solve that
> — it remembers markers, but cannot understand that “this
> implementation no longer
> matches the interface.”

Yes, this is effectively unavoidable because Git doesn't know the
structure of your code or data.  For instance, in Rust, I could add a
new mandatory-to-implement method to a trait and then all
implementations would need an update.

> That feedback inspired me to improve the tool. Version 2.0.0
> (literally born today,
> thanks to your comment) now works differently:
> 
> 1. Temporarily squash the feature branch (so the rebase is effectively `1/1`)
> 2. Resolve conflicts once, with the full final context
> 3. Automatically re-expand the squash by replaying saved diffs, restoring
>    the original commits (with new hashes, as expected in any rebase)

You haven't described exactly how this works, but it looks like it
performs a fixed set of transforms (e.g., symbol renames).  That can be
useful, but it isn't sufficient in a lot of cases.

For instance, in some work on Git I'm doing, I need to include a header
file for a function.  It was previously included in another header, but
my rebase onto the main branch had it removed, so I need to add it into
the C file I'm working on.  The only way I can 100% know which commit
needs that change programmatically is to try to compile on each commit
until it fails, and insert it there.  This, of course, requires atomic
commits.

In a lot of cases, I use git-autofixup[0], which looks at changed lines
in the diff to determine which commit to squash the changes into. It's a
great idea, but it has limitations, since sometimes a change logically
attaches to a commit but isn't close to it in the context of the diff
(such as my header inclusion change above), and sometimes I've changed
similar lines in an earlier commit A (where my change should be
squashed) as well as in later commit B, yet it gets attributed to B
accidentally.  It's convenient and generally works well, but I have to
be careful not to trust it entirely.

> I would be very interested in whether the community sees this worth exploring
> as an **experimental rebase strategy** (something like `git rebase
> --squash-restore`),
> or if it overlaps with existing mechanisms I am not aware of.

I think the fact that it adds a dependency on tree-sitter is kind of a
non-starter for us.  We're currently having a mildly contentious
discussion over the use of Rust in Git and it won't be mandatory until
Git 3.0.

It certainly covers some use cases, but it looks like it only handles
deletions, file renames, and symbol renames, and the latter only for a
small set of file types.  There's a lot of cases that it doesn't handle,
and I'm afraid that people will end up disappointed by expecting it to
magically handle a lot more than it does.  That doesn't mean it isn't a
useful and valuable tool for many use cases, but users may have much
higher expectations that it will magically solve their problems when
that isn't the case.  I have some tools that I've written myself that
are like that, for instance.

I'll also point out that we try to avoid hard-coding known languages.
People use lots of languages with Git, some of which are not even known
to Vim, which has an exceptionally complete list of file types and
syntax highlighting.  People also do non-code things with Git; for
instance, I store my creative writing in a repository, and other people
use Git for working on documentation or technical books.  As much as
possible, we want tooling that works for at least generic text files and
ideally, all files.
-- 
brian m. carlson (they/them)
Toronto, Ontario, CA