Re: [PATCH v2 0/7] Drop support for git rebase --preserve-merges

10 messages, 5 authors, 2021-09-13 · open the first message on its own page

Re: [PATCH v2 0/7] Drop support for git rebase --preserve-merges

From: Junio C Hamano <hidden>
Date: 2021-09-01 22:25:16

"Johannes Schindelin via GitGitGadget" [off-list ref]
writes:
In 427c3bd28ab (rebase: deprecate --preserve-merges, 2019-03-11) (which was
included in v2.22.0), we officially deprecated the --preserve-merges
backend. Over two years later, it is time to drop that backend, and here is
a patch series that does just that.
A good goal.  There is no remaining use case where (a fictitious and
properly working version of) "--preserve-merges" option cannot be
replaced by "--rebase-merges", is it?  I somehow had a feeling that
the other Johannes (sorry if it weren't you, j6t) had cases that the
former worked better, but perhaps I am mis-remembering things.

Thanks.

Re: [PATCH v2 0/7] Drop support for git rebase --preserve-merges

From: Johannes Schindelin <hidden>
Date: 2021-09-02 14:19:55

Hi Junio,

On Wed, 1 Sep 2021, Junio C Hamano wrote:
"Johannes Schindelin via GitGitGadget" [off-list ref]
writes:
quoted
In 427c3bd28ab (rebase: deprecate --preserve-merges, 2019-03-11) (which was
included in v2.22.0), we officially deprecated the --preserve-merges
backend. Over two years later, it is time to drop that backend, and here is
a patch series that does just that.
A good goal.  There is no remaining use case where (a fictitious and
properly working version of) "--preserve-merges" option cannot be
replaced by "--rebase-merges", is it?  I somehow had a feeling that
the other Johannes (sorry if it weren't you, j6t) had cases that the
former worked better, but perhaps I am mis-remembering things.
I think that I managed to address whatever concerns there were about the
`--rebase-merges` backend in the meantime.

To be honest, I developed one (minor) concern in the meantime... Should we
maybe try to be nicer to our users and keep handling the
`--preserve-merges` option by explicitly erroring out with the suggestion
to use `--rebase-merges` instead? Not everybody reads release notes, after
all. In fact, it is my experience that preciously few users have the time
to even skim release notes...

Ciao,
Dscho

Re: [PATCH v2 0/7] Drop support for git rebase --preserve-merges

From: Johannes Sixt <hidden>
Date: 2021-09-02 20:06:10

Am 02.09.21 um 16:18 schrieb Johannes Schindelin:
On Wed, 1 Sep 2021, Junio C Hamano wrote:
quoted
A good goal.  There is no remaining use case where (a fictitious and
properly working version of) "--preserve-merges" option cannot be
replaced by "--rebase-merges", is it?  I somehow had a feeling that
the other Johannes (sorry if it weren't you, j6t) had cases that the
former worked better, but perhaps I am mis-remembering things.
I think that I managed to address whatever concerns there were about the
`--rebase-merges` backend in the meantime.
That was either my suggestion/desire to make no-rebase-cousins the
default. That has been settled.

Or my wish not to redo the merge, but to replay the first-parent
difference. The idea never got traction, and I've long since abandoned
my implementation of it.
To be honest, I developed one (minor) concern in the meantime... Should we
maybe try to be nicer to our users and keep handling the
`--preserve-merges` option by explicitly erroring out with the suggestion
to use `--rebase-merges` instead? Not everybody reads release notes, after
all. In fact, it is my experience that preciously few users have the time
to even skim release notes...
A valid concern, I would think.

-- Hannes

Re: [PATCH v2 0/7] Drop support for git rebase --preserve-merges

From: Ævar Arnfjörð Bjarmason <hidden>
Date: 2021-09-06 06:59:36

On Wed, Sep 01 2021, Junio C Hamano wrote:
"Johannes Schindelin via GitGitGadget" [off-list ref]
writes:
quoted
In 427c3bd28ab (rebase: deprecate --preserve-merges, 2019-03-11) (which was
included in v2.22.0), we officially deprecated the --preserve-merges
backend. Over two years later, it is time to drop that backend, and here is
a patch series that does just that.
A good goal.  There is no remaining use case where (a fictitious and
properly working version of) "--preserve-merges" option cannot be
replaced by "--rebase-merges", is it?  I somehow had a feeling that
the other Johannes (sorry if it weren't you, j6t) had cases that the
former worked better, but perhaps I am mis-remembering things.
Fair enough. To be clear I think this series is fine as-is, we've just
usually done "now that this function is dead, rm it" as part of the
series that makes it dead, so I figured fixups/squashes to change those
parts would be welcome & integrated, likewise Alban Gruin's suggestions
in [off-list ref].

But the git-sh-i18n.sh change and/or his suggestions can be done after
this lands...

Re: [PATCH v2 0/7] Drop support for git rebase --preserve-merges

From: Johannes Schindelin <hidden>
Date: 2021-09-07 17:33:47

Hi Hannes,

On Thu, 2 Sep 2021, Johannes Sixt wrote:
Am 02.09.21 um 16:18 schrieb Johannes Schindelin:
quoted
On Wed, 1 Sep 2021, Junio C Hamano wrote:
quoted
A good goal.  There is no remaining use case where (a fictitious and
properly working version of) "--preserve-merges" option cannot be
replaced by "--rebase-merges", is it?  I somehow had a feeling that
the other Johannes (sorry if it weren't you, j6t) had cases that the
former worked better, but perhaps I am mis-remembering things.
I think that I managed to address whatever concerns there were about the
`--rebase-merges` backend in the meantime.
That was either my suggestion/desire to make no-rebase-cousins the
default. That has been settled.

Or my wish not to redo the merge, but to replay the first-parent
difference. The idea never got traction, and I've long since abandoned
my implementation of it.
Thank you for clarifying.

Yes, I remember how that idea came up, and I even tried that strategy for
a couple of merging rebases of Git for Windows' branch thicket. Sadly, it
did not work half as well as I had hoped.

The best idea I had back then still is in want of being implemented: sort
of a "four-way merge". It is basically the same as a three-way merge, but
allows for the pre-images to differ in the context (and yes, this cannot
be represented using the current conflict markers). Definitely not
trivial.
quoted
To be honest, I developed one (minor) concern in the meantime... Should we
maybe try to be nicer to our users and keep handling the
`--preserve-merges` option by explicitly erroring out with the suggestion
to use `--rebase-merges` instead? Not everybody reads release notes, after
all. In fact, it is my experience that preciously few users have the time
to even skim release notes...
A valid concern, I would think.
Good. Since you concur with my hunch, I implemented that change.

Thank you for reviewing,
Dscho

Re: [PATCH v2 0/7] Drop support for git rebase --preserve-merges

From: Elijah Newren <hidden>
Date: 2021-09-07 22:48:36

On Tue, Sep 7, 2021 at 11:51 AM Johannes Schindelin
[off-list ref] wrote:
Hi Hannes,

On Thu, 2 Sep 2021, Johannes Sixt wrote:
quoted
Am 02.09.21 um 16:18 schrieb Johannes Schindelin:
quoted
On Wed, 1 Sep 2021, Junio C Hamano wrote:
quoted
A good goal.  There is no remaining use case where (a fictitious and
properly working version of) "--preserve-merges" option cannot be
replaced by "--rebase-merges", is it?  I somehow had a feeling that
the other Johannes (sorry if it weren't you, j6t) had cases that the
former worked better, but perhaps I am mis-remembering things.
I think that I managed to address whatever concerns there were about the
`--rebase-merges` backend in the meantime.
That was either my suggestion/desire to make no-rebase-cousins the
default. That has been settled.

Or my wish not to redo the merge, but to replay the first-parent
difference. The idea never got traction, and I've long since abandoned
my implementation of it.
Thank you for clarifying.

Yes, I remember how that idea came up, and I even tried that strategy for
a couple of merging rebases of Git for Windows' branch thicket. Sadly, it
did not work half as well as I had hoped.

The best idea I had back then still is in want of being implemented: sort
of a "four-way merge". It is basically the same as a three-way merge, but
allows for the pre-images to differ in the context (and yes, this cannot
be represented using the current conflict markers). Definitely not
trivial.
merge-ort opens a new possibility (since it does merges without
touching the index or working tree): Take the merge commit, M, that
you are trying to transplant.  Hold on to it for a minute.  Do what
rebase-merges does now; namely, do a simple merge of the desired new
branches that otherwise ignores M to get your new merge commit N.
Hang on to N too for a minute.  Now use merge-ort to auto-remerge M
(much like AUTO_MERGE or --remerge-diff does) to get a new merge
commit that we'll call pre-M.  If M was a clean merge that the user
didn't amend, then pre-M will match M.  If M wasn't a clean merge or
was amended, then pre-M will otherwise differ from M by not including
any manual changes the user made when they originally created M --
such as removing conflict markers, fixing semantic conflicts, evil
changes, etc.

Now we've got three merge commits: pre-M, M, and N.  (Technically,
pre-M and N might be toplevel trees rather than full commits, but
whatever.)  The difference between pre-M and M represent the manual
work the user did in order to create M.  Now, do a three-way
(non-recursive) merge of those commits, to get the rebased result, R.
This operation has the affect of applying the changes from pre-M to M
on top of N.

There's obviously some edge cases (e.g. nested conflict markers), but
I think they're better than the edge cases presented by the
alternatives:
  * the first-parent difference idea silently discards intermediate
changes from reapplying other patches (especially if other patches are
added or dropped), which to me feels _very_ dangerous
  * the current rebase-merges idea silently discards manual user
changes within the original merge commit (i.e. it hopes that there is
no difference between pre-M and M), which can also be lossy
  * I don't think this idea drops any data, but it does run the risk
of conflicts that are difficult to understand.  But I suspect less so
than your five-way merge would entail.

If the difficulty of conflicts in this scheme is too high, we could do
a few things like providing multiple versions (e.g. if either
pre-M:file or N:file had conflicts, or maybe if R:file has nested
conflicts, then place both R:file and N:file in the working tree
somewhere) or pointing at special commands that help users figure out
what went on (e.g. 'git log -1 --remerge-diff M -- file').

Re: [PATCH v2 0/7] Drop support for git rebase --preserve-merges

From: Johannes Schindelin <hidden>
Date: 2021-09-10 12:08:57

Hi Elijah,

On Tue, 7 Sep 2021, Elijah Newren wrote:
On Tue, Sep 7, 2021 at 11:51 AM Johannes Schindelin
[off-list ref] wrote:
quoted
On Thu, 2 Sep 2021, Johannes Sixt wrote:
quoted
Am 02.09.21 um 16:18 schrieb Johannes Schindelin:
quoted
On Wed, 1 Sep 2021, Junio C Hamano wrote:
quoted
A good goal.  There is no remaining use case where (a fictitious and
properly working version of) "--preserve-merges" option cannot be
replaced by "--rebase-merges", is it?  I somehow had a feeling that
the other Johannes (sorry if it weren't you, j6t) had cases that the
former worked better, but perhaps I am mis-remembering things.
I think that I managed to address whatever concerns there were about the
`--rebase-merges` backend in the meantime.
That was either my suggestion/desire to make no-rebase-cousins the
default. That has been settled.

Or my wish not to redo the merge, but to replay the first-parent
difference. The idea never got traction, and I've long since abandoned
my implementation of it.
Thank you for clarifying.

Yes, I remember how that idea came up, and I even tried that strategy for
a couple of merging rebases of Git for Windows' branch thicket. Sadly, it
did not work half as well as I had hoped.

The best idea I had back then still is in want of being implemented: sort
of a "four-way merge". It is basically the same as a three-way merge, but
allows for the pre-images to differ in the context (and yes, this cannot
be represented using the current conflict markers). Definitely not
trivial.
merge-ort opens a new possibility (since it does merges without
touching the index or working tree): Take the merge commit, M, that
you are trying to transplant.  Hold on to it for a minute.  Do what
rebase-merges does now; namely, do a simple merge of the desired new
branches that otherwise ignores M to get your new merge commit N.
Hang on to N too for a minute.  Now use merge-ort to auto-remerge M
(much like AUTO_MERGE or --remerge-diff does) to get a new merge
commit that we'll call pre-M.  If M was a clean merge that the user
didn't amend, then pre-M will match M.  If M wasn't a clean merge or
was amended, then pre-M will otherwise differ from M by not including
any manual changes the user made when they originally created M --
such as removing conflict markers, fixing semantic conflicts, evil
changes, etc.

Now we've got three merge commits: pre-M, M, and N.  (Technically,
pre-M and N might be toplevel trees rather than full commits, but
whatever.)  The difference between pre-M and M represent the manual
work the user did in order to create M.  Now, do a three-way
(non-recursive) merge of those commits, to get the rebased result, R.
This operation has the affect of applying the changes from pre-M to M
on top of N.

There's obviously some edge cases (e.g. nested conflict markers), but
I think they're better than the edge cases presented by the
alternatives:
  * the first-parent difference idea silently discards intermediate
changes from reapplying other patches (especially if other patches are
added or dropped), which to me feels _very_ dangerous
  * the current rebase-merges idea silently discards manual user
changes within the original merge commit (i.e. it hopes that there is
no difference between pre-M and M), which can also be lossy
  * I don't think this idea drops any data, but it does run the risk
of conflicts that are difficult to understand.  But I suspect less so
than your five-way merge would entail.

If the difficulty of conflicts in this scheme is too high, we could do
a few things like providing multiple versions (e.g. if either
pre-M:file or N:file had conflicts, or maybe if R:file has nested
conflicts, then place both R:file and N:file in the working tree
somewhere) or pointing at special commands that help users figure out
what went on (e.g. 'git log -1 --remerge-diff M -- file').
While I agree that `merge-ort` makes a lot of things much better, I think
in this context we need to keep in mind that those nested merge conflicts
can really hurt.

In my tests (I tried to implement a strategy where a 3-way merge is done
with M and N^, using the parent commits of M as merge parents
successively, see
https://lore.kernel.org/git/nycvar.QRO.7.76.6.1804130002090.65@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz/
for the nitty gritty), I ran into _nasty_ nested merge conflicts, even
with trivial examples. And I came to the conviction that treating the
merge conflict markers as Just Another Line was the main culprit.

I wish I had the time to try out your proposed strategy with the
conconcted example I presented in that mail I linked above. Because now I
am curious what it would do...

Ciao,
Dscho

Re: [PATCH v2 0/7] Drop support for git rebase --preserve-merges

From: Elijah Newren <hidden>
Date: 2021-09-10 17:16:36

On Fri, Sep 10, 2021 at 5:08 AM Johannes Schindelin
[off-list ref] wrote:
Hi Elijah,

On Tue, 7 Sep 2021, Elijah Newren wrote:
quoted
On Tue, Sep 7, 2021 at 11:51 AM Johannes Schindelin
[off-list ref] wrote:
quoted
...
quoted
quoted
Thank you for clarifying.

Yes, I remember how that idea came up, and I even tried that strategy for
a couple of merging rebases of Git for Windows' branch thicket. Sadly, it
did not work half as well as I had hoped.

The best idea I had back then still is in want of being implemented: sort
of a "four-way merge". It is basically the same as a three-way merge, but
allows for the pre-images to differ in the context (and yes, this cannot
be represented using the current conflict markers). Definitely not
trivial.
merge-ort opens a new possibility (since it does merges without
touching the index or working tree): Take the merge commit, M, that
you are trying to transplant.  Hold on to it for a minute.  Do what
rebase-merges does now; namely, do a simple merge of the desired new
branches that otherwise ignores M to get your new merge commit N.
Hang on to N too for a minute.  Now use merge-ort to auto-remerge M
(much like AUTO_MERGE or --remerge-diff does) to get a new merge
commit that we'll call pre-M.  If M was a clean merge that the user
didn't amend, then pre-M will match M.  If M wasn't a clean merge or
was amended, then pre-M will otherwise differ from M by not including
any manual changes the user made when they originally created M --
such as removing conflict markers, fixing semantic conflicts, evil
changes, etc.

Now we've got three merge commits: pre-M, M, and N.  (Technically,
pre-M and N might be toplevel trees rather than full commits, but
whatever.)  The difference between pre-M and M represent the manual
work the user did in order to create M.  Now, do a three-way
(non-recursive) merge of those commits, to get the rebased result, R.
This operation has the affect of applying the changes from pre-M to M
on top of N.

There's obviously some edge cases (e.g. nested conflict markers), but
I think they're better than the edge cases presented by the
alternatives:
  * the first-parent difference idea silently discards intermediate
changes from reapplying other patches (especially if other patches are
added or dropped), which to me feels _very_ dangerous
  * the current rebase-merges idea silently discards manual user
changes within the original merge commit (i.e. it hopes that there is
no difference between pre-M and M), which can also be lossy
  * I don't think this idea drops any data, but it does run the risk
of conflicts that are difficult to understand.  But I suspect less so
than your five-way merge would entail.

If the difficulty of conflicts in this scheme is too high, we could do
a few things like providing multiple versions (e.g. if either
pre-M:file or N:file had conflicts, or maybe if R:file has nested
conflicts, then place both R:file and N:file in the working tree
somewhere) or pointing at special commands that help users figure out
what went on (e.g. 'git log -1 --remerge-diff M -- file').
While I agree that `merge-ort` makes a lot of things much better, I think
in this context we need to keep in mind that those nested merge conflicts
can really hurt.
Yes, and I'm not sure you fully appreciate how much either.  Your
discussion in the other thread of nested conflicts suggests you may
not be aware of a few facts; for regular merges (not talking about
rebase-merges yet):

* Merges can have nested conflicts DESPITE having unique merge bases
and NOT using merge.conflictstyle=diff3
* With unique merge bases (i.e. not a "recursive" merge), a merge will
have at most two layers of conflicts
* non-unique merge-bases and merge.conflictstyle=diff3 make nested
conflicts much more likely
* There is no limit on the number of nestings of conflict markers for a merge

Now, in terms of rebase-merges:

You noted in the other thread the possibility of being unable to
differentiate conflict markers because they had the same length.
However, increasing the length on the second merge by one or two
characters is not sufficient in general, because that might just make
you match the length of one of the nested conflicts from the other
merge.  You need to programmatically determine the sizes of the
conflict markers in the first merge, and then adjust based on it for
your other merge(s).


I know this will sound like I'm scaring you off of my idea even
further, but I actually think despite the above that my ideas for
rebase-merges may have merit.  I just want people to actually
understand the edge and corner cases.  From my reading of the previous
threads on rebasing merges, I'm concerned that there is no discussion
of arbitrarily nested conflict markers and a complete omission of any
considerations for path-based rather than content-based conflicts.
In my tests (I tried to implement a strategy where a 3-way merge is done
with M and N^, using the parent commits of M as merge parents
successively, see
https://lore.kernel.org/git/nycvar.QRO.7.76.6.1804130002090.65@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz/
for the nitty gritty), I ran into _nasty_ nested merge conflicts, even
with trivial examples. And I came to the conviction that treating the
merge conflict markers as Just Another Line was the main culprit.
I agree that we should not treat merge conflict markers as Just
Another Line.  There are other issues I can mention besides the above
here, but I'm getting kind of long already.

However, I think a big part of the problem you ran into was that the
previous suggestions only work nicely in _really_ simple cases.  In
particular, although I like Phillip's suggested sequence of merges[1]
a lot more than the other suggestions in that thread or from prior
threads, his suggestion is going to be prone to unnecessary nested
conflict markers, as you found in your testcase.

[1] https://lore.kernel.org/git/6c8749ca-ec5d-b4b7-f1a0-50d9ad2949a5@talktalk.net/
I wish I had the time to try out your proposed strategy with the
conconcted example I presented in that mail I linked above. Because now I
am curious what it would do...
For this simple testcase, as best I understood it (you didn't quite
describe it fully so I had to take a guess or two), it provides a
simpler conflict than either of the two you showed you got (from
different merge orderings of Phillip's suggestion).   However, let me
double check that I understood your testcase correctly; please correct
any errors in my understanding.  I believe the commit graph you were
describing was this:

* rebase-of-original-merge
|\
| * rebase-of-local-add-caller-of-core
* | rebase-of-local-rename-to-hi
|/
* upstream
|
|
|
| * original-merge
| |\
| | * local-add-caller-of-core
| |/
|/|
| * local-rename-to-hi
|/
* initial-version


Further, the versions of main.c in each of those are as follows:

==> initial-version:
int core(void) {
    printf("Hello, world!\n");
}


==> local-rename-to-hi:
int hi(void) {
    printf("Hello, world!\n");
}


==> local-add-caller-of-core:
int core(void) {
    printf("Hello, world!\n");
}
/* caller */
void caller(void) {
    core();
}


==> what an automatic merge of the two local-* branches would give:
int hi(void) {
    printf("Hello, world!\n");
}
/* caller */
void caller(void) {
    core();
}


==> original-merge (amended from above by s/core/hi/ in caller()):
int hi(void) {
    printf("Hello, world!\n");
}
/* caller */
void caller(void) {
    hi();
}


==> upstream:
int greeting(void) {
    printf("Hello, world!\n");
}
/* main event loop */
void event_loop(void) {
    /* TODO: place holder for now */
}


==> rebase-of-local-rename-to-hi (kept 'hi' over 'greeting'):
int hi(void) {
    printf("Hello, world!\n");
}
/* main event loop */
void event_loop(void) {
    /* TODO: place holder for now */
}


==> rebase-of-local-add-caller-of-core (kept both new functions,
updated caller):
int greeting(void) {
    printf("Hello, world!\n");
}
/* main event loop */
void event_loop(void) {
    /* TODO: place holder for now */
}
/* caller */
void caller(void) {
    greeting();
}



If I've understood that all correctly, then my idea will give you the
following conflict to resolve:

==> rebase-of-original-merge, before conflict resolution:
int hi(void) {
    printf("Hello, world!\n");
}
/* main event loop */
void event_loop(void) {
    /* TODO: place holder for now */
}
/* caller */
void caller(void) {
<<<<<<< HEAD
    greeting();
||||||| auto-remerge of original-merge
    core();
=======
    hi();
quoted
quoted
quoted
quoted
quoted
quoted
original-merge
}

merge-ort and --rebase-merges, was Re: [PATCH v2 0/7] Drop support for git rebase --preserve-merges

From: Johannes Schindelin <hidden>
Date: 2021-09-13 11:24:41

Hi Elijah,

On Fri, 10 Sep 2021, Elijah Newren wrote:
On Fri, Sep 10, 2021 at 5:08 AM Johannes Schindelin
[off-list ref] wrote:
quoted
On Tue, 7 Sep 2021, Elijah Newren wrote:
quoted
On Tue, Sep 7, 2021 at 11:51 AM Johannes Schindelin
[off-list ref] wrote:

[... talk about re-resolving merge conflicts when recreating merges
 in a `git rebase --rebase-merges` run ...]
...
quoted
While I agree that `merge-ort` makes a lot of things much better, I think
in this context we need to keep in mind that those nested merge conflicts
can really hurt.
Yes, and I'm not sure you fully appreciate how much either.
*grin*
[... a lot of insight that I totally agree with ...]

I believe the commit graph you were describing was this:

* rebase-of-original-merge
|\
| * rebase-of-local-add-caller-of-core
* | rebase-of-local-rename-to-hi
|/
* upstream
|
|
|
| * original-merge
| |\
| | * local-add-caller-of-core
| |/
|/|
| * local-rename-to-hi
|/
* initial-version


Further, the versions of main.c in each of those are as follows:

==> initial-version:
int core(void) {
    printf("Hello, world!\n");
}


==> local-rename-to-hi:
int hi(void) {
    printf("Hello, world!\n");
}


==> local-add-caller-of-core:
int core(void) {
    printf("Hello, world!\n");
}
/* caller */
void caller(void) {
    core();
}


==> what an automatic merge of the two local-* branches would give:
int hi(void) {
    printf("Hello, world!\n");
}
/* caller */
void caller(void) {
    core();
}


==> original-merge (amended from above by s/core/hi/ in caller()):
int hi(void) {
    printf("Hello, world!\n");
}
/* caller */
void caller(void) {
    hi();
}


==> upstream:
int greeting(void) {
    printf("Hello, world!\n");
}
/* main event loop */
void event_loop(void) {
    /* TODO: place holder for now */
}


==> rebase-of-local-rename-to-hi (kept 'hi' over 'greeting'):
int hi(void) {
    printf("Hello, world!\n");
}
/* main event loop */
void event_loop(void) {
    /* TODO: place holder for now */
}


==> rebase-of-local-add-caller-of-core (kept both new functions,
updated caller):
int greeting(void) {
    printf("Hello, world!\n");
}
/* main event loop */
void event_loop(void) {
    /* TODO: place holder for now */
}
/* caller */
void caller(void) {
    greeting();
}
That all matches my recollection of what I wanted to drive at.
If I've understood that all correctly, then my idea will give you the
following conflict to resolve:

==> rebase-of-original-merge, before conflict resolution:
int hi(void) {
    printf("Hello, world!\n");
}
/* main event loop */
void event_loop(void) {
    /* TODO: place holder for now */
}
/* caller */
void caller(void) {
<<<<<<< HEAD
    greeting();
||||||| auto-remerge of original-merge
    core();
=======
    hi();
quoted
quoted
quoted
quoted
quoted
quoted
quoted
original-merge
}
That looks very intriguing! I would _love_ to play with this a bit, and I
think you provided enough guidance to get going. I am currently preparing
to go mostly offline for the second half of September, read: I won't be
able to play with this before October. But I am definitely interested,
this sounds very exciting.

Ciao,
Dscho

Re: merge-ort and --rebase-merges, was Re: [PATCH v2 0/7] Drop support for git rebase --preserve-merges

From: Elijah Newren <hidden>
Date: 2021-09-13 15:53:43

On Mon, Sep 13, 2021 at 4:24 AM Johannes Schindelin
[off-list ref] wrote:
Hi Elijah,

On Fri, 10 Sep 2021, Elijah Newren wrote:
quoted
On Fri, Sep 10, 2021 at 5:08 AM Johannes Schindelin
[off-list ref] wrote:
quoted
On Tue, 7 Sep 2021, Elijah Newren wrote:
[...snip...]
quoted
If I've understood that all correctly, then my idea will give you the
following conflict to resolve:

==> rebase-of-original-merge, before conflict resolution:
int hi(void) {
    printf("Hello, world!\n");
}
/* main event loop */
void event_loop(void) {
    /* TODO: place holder for now */
}
/* caller */
void caller(void) {
<<<<<<< HEAD
    greeting();
||||||| auto-remerge of original-merge
    core();
=======
    hi();
quoted
quoted
quoted
quoted
quoted
quoted
quoted
original-merge
}
That looks very intriguing! I would _love_ to play with this a bit, and I
think you provided enough guidance to get going. I am currently preparing
to go mostly offline for the second half of September, read: I won't be
able to play with this before October. But I am definitely interested,
this sounds very exciting.
If you start working on it, let me know.  I was thinking of playing
with it, but don't know exactly when I'll get time to do so; very
unlikely before October, and reasonably likely not even before the end
of the year.

While I've provided the high level details in this thread which are
good enough to handle the simple cases, I think that the interesting
bits are the non-simple cases.  I have not thought all of them
through, but I'll include below some notes of mine that might be
helpful if you get to it first.  Note that I focus below on the
non-simple cases, and discuss content-based conflicts before covering
path-based ones:


* We're doing a three way merge of merges: pre-M, M, and N to get R; M
is the original merge, pre-M is (automatic) remerge of M, and N is
automatic merge of rebased parents of M.

* Note that N is what current rebase-merges uses, so we have all
information from that merge and can provide it to the user when or if
it is helpful.

* Both pre-M and N may themselves have conflicts.

* We need to programmatically handle conflict marker length when pre-M
and/or N have nested conflicts.  (must modify merge routines to return
the maximal conflict marker depth used)

* Special case that pre-M matches N (per hunk): If both pre-M and N
have conflict markers, but they happen to match, then we know to take
the version from M and the result IS clean (at least for that hunk).
So, you can still get a clean merge even if there are conflicts in
both pre-M and N.

* Special case that pre-M matches M (per hunk): Usually in the
three-way merge of "Base, Left, Right => Result", if Base matches
either side then you get a clean merge.  However, if pre-M matches M
but N has conflicts, the result is NOT clean.  Another way to look at
this is that conflict markers are special and should be treated
differently than other lines.  (And path-based conflicts probably need
special handling too, as discussed below.)

* In the case of complicated conflicts, consider providing user with
both R:resulting-file and N:resulting-file (and point them at `git log
-1 --remerge-diff M [-- resulting-file]`)

* Having either binary files or path-based conflicts (e.g.
modify/delete, file vs. directory vs. submodule, switch to symlink vs.
switch to executable, rename/add, rename/rename -- either 1to2 or
2to1, directory rename detection, etc.) in either pre-M or N -- or
both -- are going to need special care.

* One example of path-based conflicts:  Let's say pre-M had no
conflict at path P, and that pre-M:P and M:P matched.  Let's say that
N:P had a modify/delete conflict.  Note that for modify/delete
conflicts we tend to print a message to the console and leave the
modified version of the file in the working tree.  Here, despite the
fact that pre-M:P and M:P matched, we cannot just take the modified
file from N at P as the merge result.  The modify/delete conflict
should persist and the user given an opportunity to resolve it.
Representing the modify/delete might be an interesting question,
though since...

* If both pre-M and N have conflicts, then pre-M would have had up to
three versions of file in the index at higher stages, N would have had
up to three versions of file in the index at higher stages, and M
would have one.  We cannot represent all 7 versions of the file in the
index at the end, which means conflict representation might be tricky.
content-based conflicts are easier to handle here than path-based
ones, since content-based conflicts can just do similar to what
rename/rename(2to1) conflicts do today: just stick the result of the
preliminary three-way merges into the index.  path-based conflicts get
more interesting because you can't do a preliminary merge of binary
files or a preliminary merge of a modify/delete, etc.

* If both pre-M and N have path-based conflicts, but of different
types, how exactly do we mention that to the user?  Just list all the
types?  (This probably qualifies as a case of a "complicated" conflict
where we want to (also?) provide the user with N:resulting-file
instead of (just?) R:resulting-file.)  We may also need to modify
merge machinery to return types of conflicts per-path, an extension of
what my "merge-into" series (not yet submitted) provides.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help