All of lore.kernel.org
 help / color / mirror / Atom feed
* Premerging topics (was: [RFD] annnotating a pair of commit objects?)
@ 2013-04-10 20:35 Antoine Pelisse
  2013-04-22  9:23 ` Antoine Pelisse
  2013-04-23  6:34 ` Johan Herland
  0 siblings, 2 replies; 16+ messages in thread
From: Antoine Pelisse @ 2013-04-10 20:35 UTC (permalink / raw)
  To: Michael Haggerty, Junio C Hamano, Jeff King; +Cc: git

The goal is to propose a structure for storing and pre-merging pairs of commits.

Data-structure
==============

We could use a note ref to store the pre-merge information. Each commit
would be annotated with a blob containing the list of pre-merges (one
sha1 per line with sha1 pointing to a merge commit). The commit on the
other side of a merge would also be annotated.

The choice of the refname could be done like we do with notes:
- Have a default value
- Have a default value configured in config
- Use a specific value when merging/creating the pre-merges

Here are my concerns:

Pros
----
1. Notes allow dynamic annotation a commit
2. If we manage to fix 4, we can easily download all pre-merges from a
remote host by fetching the ref (or clean by deleting the ref).
3. Conflicts on pre-merge notes could probably be resolved by concatenation.

Cons
----
4. Checking connectivity means opening the blob and parsing it
5. Regular notes and pre-merge notes have to be handled separately
because of 4.

I'm hoping we can keep the pros and avoid the cons, but I'm kind of
stuck here. Help would be really appreciated (or maybe this is a totally
wrong direction, and I would also like to know ;)

Merging (Using what we saved)
=============================
The goal is to merge branches J and B using existing pre-merges.

E0. Create an empty stack S
E1. Create set of commits 'J..B' and 'B..J' (that is probably already done)
E2. For each commit C in smallest(J..B, B..J), execute E3
E3. For each premerge P in notes-premerge(C), execute E4
E4. If one of both parents of P belongs to biggest(J..B, B..J), stack P in S
E5. Merge J and B using all pre-merges from S

Let's consider that |J..B| is smaller than |B..J|.
E0 is executed only once
E1 is O(|J..B| + |B..J|)
E2 is O(|J..B|)
E3 is O(|J..B| x the average number of pre-merge per commits P_avg)
E4 is executed for each parent (let's say it's two/constant, after all
the topic is "pair" of commits), so still O(|J..B| x P_avg)
E5 I don't know (how it can be done, and what would be the resulting
time complexity)

So the time cost for steps E0 to E4 is O(|J..B| + |B..J| x P_avg)

Tools (Save the pre-merges)
===========================

Of course we need several tools to maintain the list of premerges, and
to easily compute them. For example, it would be nice to be able to do
something like:

    $ git pre-merge topicA topicB topicC

to find, resolve and store all interactions between the topics. We could
then easily derive to something that would allow to pre-merge a new
topic with all topics already merged in master..pu (for example).

Anyway, this task is left for latter.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Premerging topics (was: [RFD] annnotating a pair of commit objects?)
  2013-04-10 20:35 Premerging topics (was: [RFD] annnotating a pair of commit objects?) Antoine Pelisse
@ 2013-04-22  9:23 ` Antoine Pelisse
  2013-04-23  6:34 ` Johan Herland
  1 sibling, 0 replies; 16+ messages in thread
From: Antoine Pelisse @ 2013-04-22  9:23 UTC (permalink / raw)
  To: Michael Haggerty, Junio C Hamano, Jeff King; +Cc: git

Any comment on that ? I think anyone using a "Topic Workflow" could
use that feature and that it would be a nice addition to the project.
Maybe I'm totally wrong in the proposal below (please tell me !), but
there are some unanswered question that prevents me from starting (and
I'd really like this to be discussed before actually starting).

On Wed, Apr 10, 2013 at 10:35 PM, Antoine Pelisse <apelisse@gmail.com> wrote:
>
> The goal is to propose a structure for storing and pre-merging pairs of commits.
>
> Data-structure
> ==============
>
> We could use a note ref to store the pre-merge information. Each commit
> would be annotated with a blob containing the list of pre-merges (one
> sha1 per line with sha1 pointing to a merge commit). The commit on the
> other side of a merge would also be annotated.
>
> The choice of the refname could be done like we do with notes:
> - Have a default value
> - Have a default value configured in config
> - Use a specific value when merging/creating the pre-merges
>
> Here are my concerns:
>
> Pros
> ----
> 1. Notes allow dynamic annotation a commit
> 2. If we manage to fix 4, we can easily download all pre-merges from a
> remote host by fetching the ref (or clean by deleting the ref).
> 3. Conflicts on pre-merge notes could probably be resolved by concatenation.
>
> Cons
> ----
> 4. Checking connectivity means opening the blob and parsing it
> 5. Regular notes and pre-merge notes have to be handled separately
> because of 4.
>
> I'm hoping we can keep the pros and avoid the cons, but I'm kind of
> stuck here. Help would be really appreciated (or maybe this is a totally
> wrong direction, and I would also like to know ;)
>
> Merging (Using what we saved)
> =============================
> The goal is to merge branches J and B using existing pre-merges.
>
> E0. Create an empty stack S
> E1. Create set of commits 'J..B' and 'B..J' (that is probably already done)
> E2. For each commit C in smallest(J..B, B..J), execute E3
> E3. For each premerge P in notes-premerge(C), execute E4
> E4. If one of both parents of P belongs to biggest(J..B, B..J), stack P in S
> E5. Merge J and B using all pre-merges from S
>
> Let's consider that |J..B| is smaller than |B..J|.
> E0 is executed only once
> E1 is O(|J..B| + |B..J|)
> E2 is O(|J..B|)
> E3 is O(|J..B| x the average number of pre-merge per commits P_avg)
> E4 is executed for each parent (let's say it's two/constant, after all
> the topic is "pair" of commits), so still O(|J..B| x P_avg)
> E5 I don't know (how it can be done, and what would be the resulting
> time complexity)
>
> So the time cost for steps E0 to E4 is O(|J..B| + |B..J| x P_avg)
>
> Tools (Save the pre-merges)
> ===========================
>
> Of course we need several tools to maintain the list of premerges, and
> to easily compute them. For example, it would be nice to be able to do
> something like:
>
>     $ git pre-merge topicA topicB topicC
>
> to find, resolve and store all interactions between the topics. We could
> then easily derive to something that would allow to pre-merge a new
> topic with all topics already merged in master..pu (for example).
>
> Anyway, this task is left for latter.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Premerging topics (was: [RFD] annnotating a pair of commit objects?)
  2013-04-10 20:35 Premerging topics (was: [RFD] annnotating a pair of commit objects?) Antoine Pelisse
  2013-04-22  9:23 ` Antoine Pelisse
@ 2013-04-23  6:34 ` Johan Herland
  2013-04-23 14:51   ` Antoine Pelisse
  2013-04-23 14:53   ` Junio C Hamano
  1 sibling, 2 replies; 16+ messages in thread
From: Johan Herland @ 2013-04-23  6:34 UTC (permalink / raw)
  To: Antoine Pelisse; +Cc: Michael Haggerty, Junio C Hamano, Jeff King, git

On Wed, Apr 10, 2013 at 10:35 PM, Antoine Pelisse <apelisse@gmail.com> wrote:
> The goal is to propose a structure for storing and pre-merging pairs of commits.
>
> Data-structure
> ==============
>
> We could use a note ref to store the pre-merge information. Each commit
> would be annotated with a blob containing the list of pre-merges (one
> sha1 per line with sha1 pointing to a merge commit). The commit on the
> other side of a merge would also be annotated.
> The choice of the refname could be done like we do with notes:
> - Have a default value
> - Have a default value configured in config
> - Use a specific value when merging/creating the pre-merges
>
> Here are my concerns:
>
> Pros
> ----
> 1. Notes allow dynamic annotation a commit
> 2. If we manage to fix 4, we can easily download all pre-merges from a
> remote host by fetching the ref (or clean by deleting the ref).
> 3. Conflicts on pre-merge notes could probably be resolved by concatenation.
>
> Cons
> ----
> 4. Checking connectivity means opening the blob and parsing it

Can you solve this problem with a tree object, instead of inventing a
specially-formatted blob?

I.e. given pre-merge info P for a merge between commits A and B: A is
annotated by a tree object that contains all pre-merges where A is
involved. Each entry in the tree object has a filename and a blob
SHA1; we store other commit involved in this pre-merge (B) in the
filename, and the pre-merge data (P) in the blob SHA1.

Conversely, B is annotated with a tree object containing all pre-merge
entries concerning B, and within there, is an entry called A, pointing
to the same P.

You still need "special handling" in that you have to know that
"refs/notes/pre-merge" (or whatever it's called) stores tree objects
instead of blobs, and how to interpret the contents of those trees,
but you'll need such knowledge in any case.

A nice side-effect of using tree objects to store pre-merge entries,
is that you can do a tree-level merge of them, and it'll do the Right
Thing (assuming two-way merge with no common history), i.e. perform a
union merge, and leave you to handle conflicts of individual
pre-merges (i.e. you'll only get conflicts when both sides offer
different pre-merge data for A + B).

> 5. Regular notes and pre-merge notes have to be handled separately
> because of 4.

Sort of, but you get that for any automated usage of notes for a
specific purpose. Just look at the notes-cache mechanism in
notes-cache.{h,c}. That's another example of functionality layered on
top of notes that makes assumptions on how its notes trees are
structured.

> I'm hoping we can keep the pros and avoid the cons, but I'm kind of
> stuck here. Help would be really appreciated (or maybe this is a totally
> wrong direction, and I would also like to know ;)
>
> Merging (Using what we saved)
> =============================
> The goal is to merge branches J and B using existing pre-merges.
>
> E0. Create an empty stack S
> E1. Create set of commits 'J..B' and 'B..J' (that is probably already done)
> E2. For each commit C in smallest(J..B, B..J), execute E3
> E3. For each premerge P in notes-premerge(C), execute E4
> E4. If one of both parents of P belongs to biggest(J..B, B..J), stack P in S

I don't think _both_ parents of P can belong to biggest(J..B, B..J).
AFAICS J..B and B..J must always be completely disjoint sets of
commits (this is easier to see when you consider that "A..B" is
equivalent to "B ^A" for any commits A and B), and in E2/E3, you have
already made sure that P has a parent in one of them. There is then no
way that the same parent can occur in the other set, so you have at
most _one_ parent in the other set.

> E5. Merge J and B using all pre-merges from S

This is where things get complicated... :)

First there is one important thing that I have not seen a decision on
yet (maybe this was discussed in an earlier thread?):

Given pre-merge data P for commit A and B, does P encode the merge of
the entire history up to A with the entire history up to B, or does it
only encode the merging of the changes introduced in A with the
changes introduced in B? In other words, are we merging snapshots or
diffs?

In the former case, we only need to find the most recent commits A and
B on their respective branches - for which P exists - and then execute
that one P (or at most two Ps, if there is a criss-cross pre-merge
situation). In the other case, however, we need to enumerate all Ps
that apply to the two branches, and find a way to execute them
chronologically, dealing with missing Ps and conflicting Ps along the
way. IMHO, only the former approach seems practically solvable.

So you do not need to enumerate all Ps in J..B vs. B..J, you only need
to find the _most_ _recent_ P, and execute that one.

> Let's consider that |J..B| is smaller than |B..J|.
> E0 is executed only once
> E1 is O(|J..B| + |B..J|)
> E2 is O(|J..B|)
> E3 is O(|J..B| x the average number of pre-merge per commits P_avg)
> E4 is executed for each parent (let's say it's two/constant, after all
> the topic is "pair" of commits), so still O(|J..B| x P_avg)
> E5 I don't know (how it can be done, and what would be the resulting
> time complexity)
>
> So the time cost for steps E0 to E4 is O(|J..B| + |B..J| x P_avg)
>
> Tools (Save the pre-merges)
> ===========================
>
> Of course we need several tools to maintain the list of premerges, and
> to easily compute them. For example, it would be nice to be able to do
> something like:
>
>     $ git pre-merge topicA topicB topicC
>
> to find, resolve and store all interactions between the topics.

Let's leave out octopus merges for now, and only concentrate on two
branches at a time.


Hope this helps,

...Johan


PS: Could you also use this mechanism to store rerere information?


> We could
> then easily derive to something that would allow to pre-merge a new
> topic with all topics already merged in master..pu (for example).
> Anyway, this task is left for latter.

--
Johan Herland, <johan@herland.net>
www.herland.net

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Premerging topics (was: [RFD] annnotating a pair of commit objects?)
  2013-04-23  6:34 ` Johan Herland
@ 2013-04-23 14:51   ` Antoine Pelisse
  2013-04-23 23:06     ` Johan Herland
  2013-04-23 14:53   ` Junio C Hamano
  1 sibling, 1 reply; 16+ messages in thread
From: Antoine Pelisse @ 2013-04-23 14:51 UTC (permalink / raw)
  To: Johan Herland; +Cc: Michael Haggerty, Junio C Hamano, Jeff King, git

On Tue, Apr 23, 2013 at 8:34 AM, Johan Herland <johan@herland.net> wrote:
> On Wed, Apr 10, 2013 at 10:35 PM, Antoine Pelisse <apelisse@gmail.com> wrote:
>> Data-structure
>> ==============
>> We could use a note ref to store the pre-merge information. Each commit
>> would be annotated with a blob containing the list of pre-merges (one
>> sha1 per line with sha1 pointing to a merge commit). The commit on the
>> other side of a merge would also be annotated.
>> The choice of the refname could be done like we do with notes:
>> - Have a default value
>> - Have a default value configured in config
>> - Use a specific value when merging/creating the pre-merges
>>[snipped]
>> Cons
>> ----
>> 4. Checking connectivity means opening the blob and parsing it
>
> Can you solve this problem with a tree object, instead of inventing a
> specially-formatted blob?

That looks like a good idea.

> I.e. given pre-merge info P for a merge between commits A and B: A is
> annotated by a tree object that contains all pre-merges where A is
> involved. Each entry in the tree object has a filename and a blob
> SHA1; we store other commit involved in this pre-merge (B) in the
> filename, and the pre-merge data (P) in the blob SHA1.

But P is a commit(/merge with two parents), not a blob. Can we have trees
pointing to commits instead of blobs ?

> A nice side-effect of using tree objects to store pre-merge entries,
> is that you can do a tree-level merge of them, and it'll do the Right
> Thing (assuming two-way merge with no common history), i.e. perform a
> union merge, and leave you to handle conflicts of individual
> pre-merges (i.e. you'll only get conflicts when both sides offer
> different pre-merge data for A + B).

I'm definitely not sure what you mean here, especially with "tree-level
merge". Also I think we could be doing three-way merges. But I'm
no merge-strategies expert, so I'm kind of confused.

>> 5. Regular notes and pre-merge notes have to be handled separately
>> because of 4.
>
> Sort of, but you get that for any automated usage of notes for a
> specific purpose. Just look at the notes-cache mechanism in
> notes-cache.{h,c}. That's another example of functionality layered on
> top of notes that makes assumptions on how its notes trees are
> structured.

Thanks, I will have a look at it.

>> The goal is to merge branches J and B using existing pre-merges.
>>
>> E0. Create an empty stack S
>> E1. Create set of commits 'J..B' and 'B..J' (that is probably already done)
>> E2. For each commit C in smallest(J..B, B..J), execute E3
>> E3. For each premerge P in notes-premerge(C), execute E4
>> E4. If one of both parents of P belongs to biggest(J..B, B..J), stack P in S
>
> I don't think _both_ parents of P can belong to biggest(J..B, B..J).
> AFAICS J..B and B..J must always be completely disjoint sets of
> commits (this is easier to see when you consider that "A..B" is
> equivalent to "B ^A" for any commits A and B), and in E2/E3, you have
> already made sure that P has a parent in one of them. There is then no
> way that the same parent can occur in the other set, so you have at
> most _one_ parent in the other set.

I agree with that. After step E3, one of the parent belongs to one of
the two branches. Step E4 makes sure the other parent belongs to the other
branch (and not another unrelated branch).

>> E5. Merge J and B using all pre-merges from S
>
> This is where things get complicated... :)
>
> First there is one important thing that I have not seen a decision on
> yet (maybe this was discussed in an earlier thread?):
>
> Given pre-merge data P for commit A and B, does P encode the merge of
> the entire history up to A with the entire history up to B, or does it
> only encode the merging of the changes introduced in A with the
> changes introduced in B? In other words, are we merging snapshots or
> diffs?
>
> In the former case, we only need to find the most recent commits A and
> B on their respective branches - for which P exists - and then execute
> that one P (or at most two Ps, if there is a criss-cross pre-merge
> situation). In the other case, however, we need to enumerate all Ps
> that apply to the two branches, and find a way to execute them
> chronologically, dealing with missing Ps and conflicting Ps along the
> way. IMHO, only the former approach seems practically solvable.
>
> So you do not need to enumerate all Ps in J..B vs. B..J, you only need
> to find the _most_ _recent_ P, and execute that one.

Indeed, we only need to know the most recent. That's a good point.

       B1   B2    B3
    O---o---o-----o
    |      / \      \
    |    P1  P2     M
    |    /    |     /
     \__o_____o___o
       J1   J2  J3

In this use-case, we can use P1 to compute P2, and then we only need P2
to compute the real merge M. The idea would be to use P1 as an implicit
third parent to the pre-merge P2, and then P2 as an implicit third
parent to the real merge M.

>>     $ git pre-merge topicA topicB topicC
>>
>> to find, resolve and store all interactions between the topics.
>
> Let's leave out octopus merges for now, and only concentrate on two
> branches at a time.

I was not thinking about octopus merge here, but an easy way to
pre-merge many topic in a "single step", so it could be used like this:

    $ git pre-merge $(git for-each-ref refs/heads/??/*)

And that would pre-merge each pair of branches between each other. That
is: "n choose 2" (with n the number of branches given)

> Hope this helps,

It does, thanks !

> PS: Could you also use this mechanism to store rerere information?

That's one of the primary goal. The problem it would solves are:
- You could apply pre-merges even on clean merges, while rerere focuses
on conflict resolution. (typical use case is: somebody renames a
function in one topic, somebody decides to use that function in another
topic. You won't have a conflict in this situation but the code no
longer compiles.)
- You could easily pull/push pre-merges while today there is not built-in
mechanism to exchange/remote-save rerere's

Cheers,
Antoine

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Premerging topics
  2013-04-23  6:34 ` Johan Herland
  2013-04-23 14:51   ` Antoine Pelisse
@ 2013-04-23 14:53   ` Junio C Hamano
  2013-04-23 15:17     ` Antoine Pelisse
  1 sibling, 1 reply; 16+ messages in thread
From: Junio C Hamano @ 2013-04-23 14:53 UTC (permalink / raw)
  To: Johan Herland; +Cc: Antoine Pelisse, Michael Haggerty, Jeff King, git

Johan Herland <johan@herland.net> writes:

> Can you solve this problem with a tree object, instead of inventing a
> specially-formatted blob?

Hmm.  What problem are you guys trying to solve?

I think Michael's use of a merge commit to record a merge result is
sufficient as a means to record how to recreate an evil merge.

  http://thread.gmane.org/gmane.comp.version-control.git/212570/focus=212578

FWIW, in the [RFD], I wasn't asking for ideas on that part.  When
rebuiling 'pu', I use an even simpler solution to have rerere
autoresolve the mechanical part of the merge, and then cherry-pick a
separate commit from refs/merge-fix/ hierarchy on the result, and it
works perfectly fine (this is done by the 'Reintegrate' script on
the 'todo' branch; see Documentation/howto/maintain-git.txt).

When topic A is closer to be done than topic B (in other words, when
I merge topic B to an integration branch, topic A is already merged
there), and these topics have semantic conflicts (e.g. A renames a
function foo() to bar(), while B adds a new callsite of foo()), a
mechanical merge of B may succeed without any textual conflict (or
if there is, rerere can resolve it), but a semantic fix-up needs to
do "s/foo/bar/g" on the result.

I would do something like this for the first time:

	... while on 'pu', A has already been merged ...
        git merge B ;# may conflict
        edit textual conflicts away
        git rerere ;# remember the textual resolution
        git commit ;# commit _without_ semantics adjustment
        edit semantic conflict away, i.e. s/foo/bar/g
        git commit
        git update-ref refs/merge-fix/B

After that, next time I rebuild 'pu', when the automated procedure
processes B, it would "git merge B", "git rerere", make sure textual
conflicts are gone, and "git cherry-pick refs/merge-fix/B".  To make
sure this would work, what I typically do immediately after doing
all of the above is:

	git reset --hard HEAD^^

to drop the fix-up commit and merge of B, and actually tell the
automated procedure to process B.  It should recreate the evil merge
using the information I just recorded.

So "how a recipe to recreate an evil merge is recorded", as far as I
am concerned, is an already solved problem.

The part of the existing solution I was not happy was deciding when
to use which "merge-fix" commit to cherry-pick.  If I start merging
topic B before topic A, the "merge-fix/B" needs to be renamed to
"merge-fix/A" in the above.  Otherwise, when B is merged to 'pu',
there is no 'A' merged to it yet, so merge-fix that munges its new
call to foo() to call bar() instead will _break_ things [*1*].

And that was why I wanted to have a data structure that is quick to
query to answer "I am about to merge B.  Does the history already
have an A for which I have recorded a merge-fix for <A,B> pair?"


[Footnote]

*1* If A has other kinds of conflicts with other topics, it is not
sufficient to just rename "merge-fix/B" to "merge-fix/A"---the
effect of cherry-picking "merge-fix/B" needs to be merged to
existing "merge-fix/A".  If a merge-fix is recorded for a pair of
commits that necessitates an evil merge, this naturally goes away.
I can keep a merge-fix for the <A,B> pair whether I merge A before
or after B, and semantic conflicts A may have with another topic C
would be stored in a separate merge-fix for <A,C> pair.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Premerging topics
  2013-04-23 14:53   ` Junio C Hamano
@ 2013-04-23 15:17     ` Antoine Pelisse
  2013-04-23 15:29       ` Junio C Hamano
  0 siblings, 1 reply; 16+ messages in thread
From: Antoine Pelisse @ 2013-04-23 15:17 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Johan Herland, Michael Haggerty, Jeff King, git

On Tue, Apr 23, 2013 at 4:53 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Johan Herland <johan@herland.net> writes:
>
>> Can you solve this problem with a tree object, instead of inventing a
>> specially-formatted blob?
>
> Hmm.  What problem are you guys trying to solve?
>
> [snipped..]
> And that was why I wanted to have a data structure that is quick to
> query to answer "I am about to merge B.  Does the history already
> have an A for which I have recorded a merge-fix for <A,B> pair?"

That's exactly the problem I'm trying to solve.
I'm willing to have an efficient way to merge topicC that has semantic
conflicts with topicA and topicB.
As topics will be merged together first in pu, then in next and
finally in master, chances are that they won't be merged in the same
order (or then, why would we even care about a topic workflow?). And I
have the feeling that "merge-fix/B" or "merge-fix/A" doesn't hold
enough information to do that accurately.

The idea is then to store the <A, B> pair as a note, and to associate
a "merge" to that (solving the semantic conflict). It would then be
used as an implicit third parent for the merge of "branch containing
A" and "branch containing B". This is pretty much what Michael said in
the $gmane you talked about.

Cheers,
Antoine

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Premerging topics
  2013-04-23 15:17     ` Antoine Pelisse
@ 2013-04-23 15:29       ` Junio C Hamano
  2013-04-23 15:36         ` Antoine Pelisse
  0 siblings, 1 reply; 16+ messages in thread
From: Junio C Hamano @ 2013-04-23 15:29 UTC (permalink / raw)
  To: Antoine Pelisse; +Cc: Johan Herland, Michael Haggerty, Jeff King, git

Antoine Pelisse <apelisse@gmail.com> writes:

> And I
> have the feeling that "merge-fix/B" or "merge-fix/A" doesn't hold
> enough information to do that accurately.

Oh, you do not have to resort to feeling; these names do _not_ hold
enough information, period.  We already know that, that was why I was
unhappy, and that was why I sent the "annotating a pair of commit
objects" RFD in the first place ;-).

> The idea is then to store the <A, B> pair as a note, and to associate
> a "merge" to that (solving the semantic conflict).

OK, and as the datastore for <A, B> pair you were thinking about
using a specially-formatted blob and Johan suggested to use a
regular tree object?

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Premerging topics
  2013-04-23 15:29       ` Junio C Hamano
@ 2013-04-23 15:36         ` Antoine Pelisse
  0 siblings, 0 replies; 16+ messages in thread
From: Antoine Pelisse @ 2013-04-23 15:36 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Johan Herland, Michael Haggerty, Jeff King, git

On Tue, Apr 23, 2013 at 5:29 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Antoine Pelisse <apelisse@gmail.com> writes:
>
>> And I
>> have the feeling that "merge-fix/B" or "merge-fix/A" doesn't hold
>> enough information to do that accurately.
>
> Oh, you do not have to resort to feeling; these names do _not_ hold
> enough information, period.  We already know that, that was why I was
> unhappy, and that was why I sent the "annotating a pair of commit
> objects" RFD in the first place ;-).

:)

>> The idea is then to store the <A, B> pair as a note, and to associate
>> a "merge" to that (solving the semantic conflict).
>
> OK, and as the datastore for <A, B> pair you were thinking about
> using a specially-formatted blob and Johan suggested to use a
> regular tree object?

Exactly. But as I said, it should associate the pair to a merge. And
trees contain other trees or blobs, not commits. I'm wondering if this
is a problem.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Premerging topics (was: [RFD] annnotating a pair of commit objects?)
  2013-04-23 14:51   ` Antoine Pelisse
@ 2013-04-23 23:06     ` Johan Herland
  2013-04-24  5:48       ` Premerging topics Junio C Hamano
  0 siblings, 1 reply; 16+ messages in thread
From: Johan Herland @ 2013-04-23 23:06 UTC (permalink / raw)
  To: Antoine Pelisse; +Cc: Michael Haggerty, Junio C Hamano, Jeff King, git

On Tue, Apr 23, 2013 at 4:51 PM, Antoine Pelisse <apelisse@gmail.com> wrote:
> On Tue, Apr 23, 2013 at 8:34 AM, Johan Herland <johan@herland.net> wrote:
>> On Wed, Apr 10, 2013 at 10:35 PM, Antoine Pelisse <apelisse@gmail.com> wrote:
>>> Data-structure
>>> ==============
>>> We could use a note ref to store the pre-merge information. Each commit
>>> would be annotated with a blob containing the list of pre-merges (one
>>> sha1 per line with sha1 pointing to a merge commit). The commit on the
>>> other side of a merge would also be annotated.
>>> The choice of the refname could be done like we do with notes:
>>> - Have a default value
>>> - Have a default value configured in config
>>> - Use a specific value when merging/creating the pre-merges
>>>[snipped]
>>> Cons
>>> ----
>>> 4. Checking connectivity means opening the blob and parsing it
>>
>> Can you solve this problem with a tree object, instead of inventing a
>> specially-formatted blob?
>
> That looks like a good idea.
>
>> I.e. given pre-merge info P for a merge between commits A and B: A is
>> annotated by a tree object that contains all pre-merges where A is
>> involved. Each entry in the tree object has a filename and a blob
>> SHA1; we store other commit involved in this pre-merge (B) in the
>> filename, and the pre-merge data (P) in the blob SHA1.
>
> But P is a commit(/merge with two parents), not a blob. Can we have trees
> pointing to commits instead of blobs ?

Sort of. We do so when recording submodules in regular git trees. The
submodule is recorded as a tree entry whose type is commit, name is the
subdir containing the submodule, and SHA1 is the commit ID recorded for
that submodule at this point in history. So it definitely _can_ be done.
That said, I'm not sure whether it's actually a good idea in this case...

I apologize for not having followed the initial discussion. I did not
know that the pre-merge information would be stored as commits.
I figured since it would only contain a partial merge resolution, it
could be represented as something like a tree object containing (only)
the pre-resolved paths...

>> A nice side-effect of using tree objects to store pre-merge entries,
>> is that you can do a tree-level merge of them, and it'll do the Right
>> Thing (assuming two-way merge with no common history), i.e. perform a
>> union merge, and leave you to handle conflicts of individual
>> pre-merges (i.e. you'll only get conflicts when both sides offer
>> different pre-merge data for A + B).
>
> I'm definitely not sure what you mean here, especially with "tree-level
> merge". Also I think we could be doing three-way merges. But I'm
> no merge-strategies expert, so I'm kind of confused.

I was simply thinking of the simple two-way merge that can be done between
two independent trees:
- All paths that exist in only one tree, exist unchanged in the result
- All paths that are identical in both trees exist unchanged in the result
- All paths that exist in both trees, but are different, yield a conflict

In your pre-merge domain, this would become (for given commit A, B, C):
- If one tree records a pre-merge for (A,B) and the other for (A,C), then
  both (A,B) and (A,C) will exist in the result
- If both trees records the _same_ pre-merge resolution for (A,B), then
  that will also exist in the result
- If one tree records one way of pre-merging (A,B), and the other tree
  records a _different_ way of pre-merging (A,B), then there will be a
  conflict that needs resolving.

>>> 5. Regular notes and pre-merge notes have to be handled separately
>>> because of 4.
>>
>> Sort of, but you get that for any automated usage of notes for a
>> specific purpose. Just look at the notes-cache mechanism in
>> notes-cache.{h,c}. That's another example of functionality layered on
>> top of notes that makes assumptions on how its notes trees are
>> structured.
>
> Thanks, I will have a look at it.
>
>>> The goal is to merge branches J and B using existing pre-merges.
>>>
>>> E0. Create an empty stack S
>>> E1. Create set of commits 'J..B' and 'B..J' (that is probably already done)
>>> E2. For each commit C in smallest(J..B, B..J), execute E3
>>> E3. For each premerge P in notes-premerge(C), execute E4
>>> E4. If one of both parents of P belongs to biggest(J..B, B..J), stack P in S
>>
>> I don't think _both_ parents of P can belong to biggest(J..B, B..J).
>> AFAICS J..B and B..J must always be completely disjoint sets of
>> commits (this is easier to see when you consider that "A..B" is
>> equivalent to "B ^A" for any commits A and B), and in E2/E3, you have
>> already made sure that P has a parent in one of them. There is then no
>> way that the same parent can occur in the other set, so you have at
>> most _one_ parent in the other set.
>
> I agree with that. After step E3, one of the parent belongs to one of
> the two branches. Step E4 makes sure the other parent belongs to the other
> branch (and not another unrelated branch).
>
>>> E5. Merge J and B using all pre-merges from S
>>
>> This is where things get complicated... :)
>>
>> First there is one important thing that I have not seen a decision on
>> yet (maybe this was discussed in an earlier thread?):
>>
>> Given pre-merge data P for commit A and B, does P encode the merge of
>> the entire history up to A with the entire history up to B, or does it
>> only encode the merging of the changes introduced in A with the
>> changes introduced in B? In other words, are we merging snapshots or
>> diffs?
>>
>> In the former case, we only need to find the most recent commits A and
>> B on their respective branches - for which P exists - and then execute
>> that one P (or at most two Ps, if there is a criss-cross pre-merge
>> situation). In the other case, however, we need to enumerate all Ps
>> that apply to the two branches, and find a way to execute them
>> chronologically, dealing with missing Ps and conflicting Ps along the
>> way. IMHO, only the former approach seems practically solvable.
>>
>> So you do not need to enumerate all Ps in J..B vs. B..J, you only need
>> to find the _most_ _recent_ P, and execute that one.
>
> Indeed, we only need to know the most recent. That's a good point.
>
>        B1   B2    B3
>     O---o---o-----o
>     |      / \      \
>     |    P1  P2     M
>     |    /    |     /
>      \__o_____o___o
>        J1   J2  J3
>
> In this use-case, we can use P1 to compute P2, and then we only need P2
> to compute the real merge M. The idea would be to use P1 as an implicit
> third parent to the pre-merge P2, and then P2 as an implicit third
> parent to the real merge M.

I'm not sure what is really meant by "implicit third parent" here. Will
Git automatically help you (i.e. auto-resolve conflicts in the correct
manner) if you do an octopus merge between (B3, J3, P2)? I thought you
would have to start by merging J3 and B3, and then - as part of the
conflict resolution process - you invoke the pre-merge machinery, which
goes searching for pre-merges and finds P2, which is then used to help
auto-resolve (some of) the conflicts between B3 and J3. This means that
P2 is not a merge parent in the traditional sense, and I also don't think
that you want to record P2 as a "proper" parent of the resulting merge
commit M.

At this point I also wonder why the pre-merges (P1, P2) has to be
recorded as commit objects. Do they have meaningful commit messages?

...Johan

>>>     $ git pre-merge topicA topicB topicC
>>>
>>> to find, resolve and store all interactions between the topics.
>>
>> Let's leave out octopus merges for now, and only concentrate on two
>> branches at a time.
>
> I was not thinking about octopus merge here, but an easy way to
> pre-merge many topic in a "single step", so it could be used like this:
>
>     $ git pre-merge $(git for-each-ref refs/heads/??/*)
>
> And that would pre-merge each pair of branches between each other. That
> is: "n choose 2" (with n the number of branches given)
>
>> Hope this helps,
>
> It does, thanks !
>
>> PS: Could you also use this mechanism to store rerere information?
>
> That's one of the primary goal. The problem it would solves are:
> - You could apply pre-merges even on clean merges, while rerere focuses
> on conflict resolution. (typical use case is: somebody renames a
> function in one topic, somebody decides to use that function in another
> topic. You won't have a conflict in this situation but the code no
> longer compiles.)
> - You could easily pull/push pre-merges while today there is not built-in
> mechanism to exchange/remote-save rerere's


--
Johan Herland, <johan@herland.net>
www.herland.net

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Premerging topics
  2013-04-23 23:06     ` Johan Herland
@ 2013-04-24  5:48       ` Junio C Hamano
  2013-04-24  6:22         ` Johan Herland
  2013-04-29 13:04         ` Antoine Pelisse
  0 siblings, 2 replies; 16+ messages in thread
From: Junio C Hamano @ 2013-04-24  5:48 UTC (permalink / raw)
  To: Johan Herland; +Cc: Antoine Pelisse, Michael Haggerty, Jeff King, git

Johan Herland <johan@herland.net> writes:

>> But P is a commit(/merge with two parents), not a blob. Can we have trees
>> pointing to commits instead of blobs ?
>
> Sort of. We do so when recording submodules in regular git trees.

You are using notes to maintain reachability, aren't you?  Because
commit objects that appears in trees are not treated as reachable
from the trees, that won't fly.

I think you guys are making it unnecessarily complex by using notes.
To record a prepared evil merge for merging branch that contains A
with another branch that contains B (assuming that the interation
between A and B is what makes the evil merge necessary, e.g. A
renames a function foo() to bar(), while B adds new callsite that
calls foo()), we can store a single commit that records the prepared
evil merge under "refs/merge-fix/$A-$B" where A and B are their
object names.

Then when merging a branch Y that contains B into our history X that
already contains A (or vice versa),

  ---o---o---A---o---X... ???
      \                  .
       \                .
        \              .
         o---B----o---Y

we can enumerate the commits that appear in "log --left-right X...Y"
on the left/right side and notice there is refs/merge-fix/$A-$B.

So the simplest implementation of "an efficient data store to record
a commit for <A,B> pair" turns out to be just a ref namespace ;-)

There may be other <C,D> pairs in X...Y history, and it probably is
the sane thing to do to replay prepackaged evil merges from older to
newer in the topological sense, but that loop would be trivial, once
we understand how to replay a single such evil merge.

The actual merge-fix data should be just a commit with a single
parent. The easiest way to prepare it would be like this:

  ---o---o---A
      \       \
       \       M---F
        \     /
         o---B

where M is the result of mechanical merge between A and B (there
could be textual conflicts and you could choose to leave them in, or
you could choose to have rerere resolve it.  As long as you do the
same when replaying this prepackaged evil merge, this choice does
not matter, but using rerere will make your life easier), and F is
the final result you would want, with semantics conflicts resolved.
In other words, in the ideal world, you would have resolved a merge
between A and B to record the tree of F.

Point "F" with refs/merge-fix/$A-$B and you are done.

When you replay this prepackaged evil merge, first you mechanically
merge X and Y without worrying about M or F to produce N.  If you
allowed rerere to resolve textual conflicts between A and B when you
recorded M, allow rerere to resolve this merge.  Otherwise leave the
textual conflict in.

  ---o---o---A---o---X
      \               \
       \               N
        \             /
         o---B---o---Y

Then on top of N, you cherry-pick F, which will bring the semantic
conflict resolution between M and F on top of N.

  ---o---o---A---o---X
      \               \
       \               N---F'
        \             /
         o---B---o---Y

Once you know the tree shape of F', then you no longer need N.  Just
amend it away and make the tree recorded in F' the result of the
merge between X and Y.

  ---o---o---A---o---X---.
      \                   \
       \                  F''
        \                /
         o---B---o---Y--.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Premerging topics
  2013-04-24  5:48       ` Premerging topics Junio C Hamano
@ 2013-04-24  6:22         ` Johan Herland
  2013-04-24  7:14           ` Junio C Hamano
  2013-04-29 13:04         ` Antoine Pelisse
  1 sibling, 1 reply; 16+ messages in thread
From: Johan Herland @ 2013-04-24  6:22 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Antoine Pelisse, Michael Haggerty, Jeff King, git

On Wed, Apr 24, 2013 at 7:48 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Johan Herland <johan@herland.net> writes:
>
>>> But P is a commit(/merge with two parents), not a blob. Can we have trees
>>> pointing to commits instead of blobs ?
>>
>> Sort of. We do so when recording submodules in regular git trees.
>
> You are using notes to maintain reachability, aren't you?  Because
> commit objects that appears in trees are not treated as reachable
> from the trees, that won't fly.
>
> I think you guys are making it unnecessarily complex by using notes.
> To record a prepared evil merge for merging branch that contains A
> with another branch that contains B (assuming that the interation
> between A and B is what makes the evil merge necessary, e.g. A
> renames a function foo() to bar(), while B adds new callsite that
> calls foo()), we can store a single commit that records the prepared
> evil merge under "refs/merge-fix/$A-$B" where A and B are their
> object names.
>
> Then when merging a branch Y that contains B into our history X that
> already contains A (or vice versa),
>
>   ---o---o---A---o---X... ???
>       \                  .
>        \                .
>         \              .
>          o---B----o---Y
>
> we can enumerate the commits that appear in "log --left-right X...Y"
> on the left/right side and notice there is refs/merge-fix/$A-$B.
>
> So the simplest implementation of "an efficient data store to record
> a commit for <A,B> pair" turns out to be just a ref namespace ;-)
>
> There may be other <C,D> pairs in X...Y history, and it probably is
> the sane thing to do to replay prepackaged evil merges from older to
> newer in the topological sense, but that loop would be trivial, once
> we understand how to replay a single such evil merge.

This raises the same question I recently asked Antoine: For a given
prepackaged merge <X,Y>, do we assume that it only resolves conflicts
between the changes introduced in commit X vs. changes introduced in
commit Y, or do we assume that it resolves conflicts between the
histories leading up to X and Y, respectively? In other words, does
<X,Y> _supercede_ earlier pre-merges between the histories leading up
to X and Y?

I think the latter makes more sense, since we can then reduce the
number of pre-merges to consider in the final merge. There might still
be more than one pre-merge to consider, though, e.g. in criss-cross
cases like this:

  ---o---o---o---o---o---o---o---o
      \             /     \       \
       \           /       \       \
        \         /         \       \
         o---o---o           P2      \
          \       \         /         \
           \       \       /           M
            \       \     /           /
             o---o---+---o           /
              \       \   \         /
               \       P1  \       /
                \     /     \     /
                 o---o---o---o---o

(there is no commit at the "+")

> The actual merge-fix data should be just a commit with a single
> parent. The easiest way to prepare it would be like this:
>
>   ---o---o---A
>       \       \
>        \       M---F
>         \     /
>          o---B
>
> where M is the result of mechanical merge between A and B (there
> could be textual conflicts and you could choose to leave them in, or
> you could choose to have rerere resolve it.  As long as you do the
> same when replaying this prepackaged evil merge, this choice does
> not matter, but using rerere will make your life easier), and F is
> the final result you would want, with semantics conflicts resolved.
> In other words, in the ideal world, you would have resolved a merge
> between A and B to record the tree of F.
>
> Point "F" with refs/merge-fix/$A-$B and you are done.
>
> When you replay this prepackaged evil merge, first you mechanically
> merge X and Y without worrying about M or F to produce N.  If you
> allowed rerere to resolve textual conflicts between A and B when you
> recorded M, allow rerere to resolve this merge.  Otherwise leave the
> textual conflict in.
>
>   ---o---o---A---o---X
>       \               \
>        \               N
>         \             /
>          o---B---o---Y
>
> Then on top of N, you cherry-pick F, which will bring the semantic
> conflict resolution between M and F on top of N.
>
>   ---o---o---A---o---X
>       \               \
>        \               N---F'
>         \             /
>          o---B---o---Y
>
> Once you know the tree shape of F', then you no longer need N.  Just
> amend it away and make the tree recorded in F' the result of the
> merge between X and Y.
>
>   ---o---o---A---o---X---.
>       \                   \
>        \                  F''
>         \                /
>          o---B---o---Y--.

This is obviously a much better way to solve it. It might already be
obvious, but I would suggest when making "refs/merge-fix/$A-$B" that you
canonicalize the name by always choosing A and B such that A precedes B
alphabetically. That way you won't have problems with both recording
"refs/merge-fix/$A-$B" and "refs/merge-fix/$B-$A".


...Johan

--
Johan Herland, <johan@herland.net>
www.herland.net

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Premerging topics
  2013-04-24  6:22         ` Johan Herland
@ 2013-04-24  7:14           ` Junio C Hamano
  2013-04-29 19:06             ` Antoine Pelisse
  0 siblings, 1 reply; 16+ messages in thread
From: Junio C Hamano @ 2013-04-24  7:14 UTC (permalink / raw)
  To: Johan Herland; +Cc: Antoine Pelisse, Michael Haggerty, Jeff King, git

Johan Herland <johan@herland.net> writes:

> This raises the same question I recently asked Antoine: For a given
> prepackaged merge <X,Y>, do we assume that it only resolves conflicts
> between the changes introduced in commit X vs. changes introduced in
> commit Y, or do we assume that it resolves conflicts between the
> histories leading up to X and Y, respectively? In other words, does
> <X,Y> _supercede_ earlier pre-merges between the histories leading up
> to X and Y?

That is an interesting question.  There are largely two cases.

When you replayed M---F to produce N---F', there may have been no
textual or semantic conflict.  Which means that there were no new
reason between A--X and B--Y that necessitates an evil merge.  A
later merge between a descendant of X (but not Y) and a descendant
of Y (but not X) can cherry pick the same <A,B> (M---F) on top of a
mechanical merge,

On the other hand, you may have had either a textual or a semantic
conflict when replaying <A,B> on N, and you had to fix up F' for it
to be the correct resolution of merge between X and Y.

  ---o---o---A---o---X
      \               \
       \               N---F'
        \             /
         o---B---o---Y

In such a case, you do want to record the fixed N---F' as the
prepackaged resolution for <X,Y>.  Any time later when somebody is
on a branch that has X (but not Y) and merges a branch that has Y
(but not X), that N---F' should be the one to cherry-pick on top of
a mechanical merge O between S and T.  What <A,B> (M---F) did is
superseded if you are going to replay <X,Y>.

  ---o---o---A---o---X----------S
      \       \       \          \
       \       M--F    N---F'     O---F''
        \     /       /          /
         o---B---o---Y----------T

You can tell that by noticing that A is an ancestor of X and B is an
ancestor of Y.  As you said, this is a good way to reduce the number
of prepackaged evil merges that need to be considered.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Premerging topics
  2013-04-24  5:48       ` Premerging topics Junio C Hamano
  2013-04-24  6:22         ` Johan Herland
@ 2013-04-29 13:04         ` Antoine Pelisse
  2013-04-29 15:08           ` Junio C Hamano
  1 sibling, 1 reply; 16+ messages in thread
From: Antoine Pelisse @ 2013-04-29 13:04 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Johan Herland, Michael Haggerty, Jeff King, git

On Wed, Apr 24, 2013 at 7:48 AM, Junio C Hamano <gitster@pobox.com> wrote:
> there
> could be textual conflicts and you could choose to leave them in, or
> you could choose to have rerere resolve it.  As long as you do the
> same when replaying this prepackaged evil merge, this choice does
> not matter, but using rerere will make your life easier

The problem is that rerere can not be easily shared, and I'm afraid it
would be almost impossible to go without it (do you commit N with
conflict markers hoping that F' will remove them?).
But, as it looks like you would save F on top of M, it means that M
would be reachable, and thus rerere would be "recomputable" from
somewhere else.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Premerging topics
  2013-04-29 13:04         ` Antoine Pelisse
@ 2013-04-29 15:08           ` Junio C Hamano
  0 siblings, 0 replies; 16+ messages in thread
From: Junio C Hamano @ 2013-04-29 15:08 UTC (permalink / raw)
  To: Antoine Pelisse; +Cc: Johan Herland, Michael Haggerty, Jeff King, git

Antoine Pelisse <apelisse@gmail.com> writes:

> But, as it looks like you would save F on top of M, it means that M
> would be reachable, and thus rerere would be "recomputable" from
> somewhere else.

Exactly.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Premerging topics
  2013-04-24  7:14           ` Junio C Hamano
@ 2013-04-29 19:06             ` Antoine Pelisse
  2013-04-29 22:19               ` Junio C Hamano
  0 siblings, 1 reply; 16+ messages in thread
From: Antoine Pelisse @ 2013-04-29 19:06 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Johan Herland, Michael Haggerty, Jeff King, git

Should we think about adding some commands for that ?

On the very top of my head (there is certainly more than that):
- Save such a change: By basically creating a ref to HEAD (HEAD being
the commit, HEAD^ the fixed merge) with merge-fix/HEAD^^1-HEAD^^2
- Apply the merge-fix: On top of a merge, find the most recent
merge-fix for HEAD^1/HEAD^2 (according to what was discussed), and
squash it.

On Wed, Apr 24, 2013 at 9:14 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Johan Herland <johan@herland.net> writes:
>
>> This raises the same question I recently asked Antoine: For a given
>> prepackaged merge <X,Y>, do we assume that it only resolves conflicts
>> between the changes introduced in commit X vs. changes introduced in
>> commit Y, or do we assume that it resolves conflicts between the
>> histories leading up to X and Y, respectively? In other words, does
>> <X,Y> _supercede_ earlier pre-merges between the histories leading up
>> to X and Y?
>
> That is an interesting question.  There are largely two cases.
>
> When you replayed M---F to produce N---F', there may have been no
> textual or semantic conflict.  Which means that there were no new
> reason between A--X and B--Y that necessitates an evil merge.  A
> later merge between a descendant of X (but not Y) and a descendant
> of Y (but not X) can cherry pick the same <A,B> (M---F) on top of a
> mechanical merge,
>
> On the other hand, you may have had either a textual or a semantic
> conflict when replaying <A,B> on N, and you had to fix up F' for it
> to be the correct resolution of merge between X and Y.
>
>   ---o---o---A---o---X
>       \               \
>        \               N---F'
>         \             /
>          o---B---o---Y
>
> In such a case, you do want to record the fixed N---F' as the
> prepackaged resolution for <X,Y>.  Any time later when somebody is
> on a branch that has X (but not Y) and merges a branch that has Y
> (but not X), that N---F' should be the one to cherry-pick on top of
> a mechanical merge O between S and T.  What <A,B> (M---F) did is
> superseded if you are going to replay <X,Y>.
>
>   ---o---o---A---o---X----------S
>       \       \       \          \
>        \       M--F    N---F'     O---F''
>         \     /       /          /
>          o---B---o---Y----------T
>
> You can tell that by noticing that A is an ancestor of X and B is an
> ancestor of Y.  As you said, this is a good way to reduce the number
> of prepackaged evil merges that need to be considered.
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Premerging topics
  2013-04-29 19:06             ` Antoine Pelisse
@ 2013-04-29 22:19               ` Junio C Hamano
  0 siblings, 0 replies; 16+ messages in thread
From: Junio C Hamano @ 2013-04-29 22:19 UTC (permalink / raw)
  To: Antoine Pelisse; +Cc: Johan Herland, Michael Haggerty, Jeff King, git

Antoine Pelisse <apelisse@gmail.com> writes:

> Should we think about adding some commands for that ?
>
> On the very top of my head (there is certainly more than that):
> - Save such a change: By basically creating a ref to HEAD (HEAD being
> the commit, HEAD^ the fixed merge) with merge-fix/HEAD^^1-HEAD^^2
> - Apply the merge-fix: On top of a merge, find the most recent
> merge-fix for HEAD^1/HEAD^2 (according to what was discussed), and
> squash it.

Yeah, some nasties may live in the details, but these two operations
are needed and probably sufficient as the end-user facing UI.

The "save" step, when done manually, needs to be a two-step process
that saves M and then F separately, but somebody _might_ be able to
come up with a clever idea to let the user jump directly to F
without recording M.  If such a triangle (A and B merges to F) can
be recorded as merge-fix/A-B, that would certainly be less error
prone and easier for the users to use.  Having said that, in the
presense of possible textual conflicts when creating M, I do not
think of a way that is easily implementable mechanically to
internally sift changes for M and F when replaying it while
resolving a merge between X and Y to produce N and eventually F'.

The "apply" step should be a single step, and it should be easy to
implement mechanically if M and F are recorded separately (but
again, you may be able to re-synthesise M from A and B when you need
to replay the evil merge).

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2013-04-29 22:19 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-04-10 20:35 Premerging topics (was: [RFD] annnotating a pair of commit objects?) Antoine Pelisse
2013-04-22  9:23 ` Antoine Pelisse
2013-04-23  6:34 ` Johan Herland
2013-04-23 14:51   ` Antoine Pelisse
2013-04-23 23:06     ` Johan Herland
2013-04-24  5:48       ` Premerging topics Junio C Hamano
2013-04-24  6:22         ` Johan Herland
2013-04-24  7:14           ` Junio C Hamano
2013-04-29 19:06             ` Antoine Pelisse
2013-04-29 22:19               ` Junio C Hamano
2013-04-29 13:04         ` Antoine Pelisse
2013-04-29 15:08           ` Junio C Hamano
2013-04-23 14:53   ` Junio C Hamano
2013-04-23 15:17     ` Antoine Pelisse
2013-04-23 15:29       ` Junio C Hamano
2013-04-23 15:36         ` Antoine Pelisse

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.