Edward Thomson [off-list ref] writes:
I would propose that we store the data about the file in conflict as it
occurred through the renames. For example, in a rename 1->2 conflict where
A was renamed to both B and C, you would have a single conflict entry
containing the data for A, B and C. This would allow us to provide more
detailed information to the user - and allow them to (say) choose a single
name to proceed with.
Is this something that has value to core git as well? Alternately, is
there something particularly stupid about this proposal?
I do not offhand see anything particularly stupid; a new optional
index extension section CACHE_EXT_RENAME_CONFLICT might be a good
addition.
Is "one side moves A to B while the other side moves it to C" the
only case, or is it just an example? Off the top of my head, "one
side moves A to x while the other side moves B to x/y" would also be
something we would want to know. I am sure there are other cases
that need to be considered.
I do not think we can discuss the design at the concrete level until
the proposal spells out to cover all interesting cases in order for
implementations to agree on the common semantics.
Junio C Hamano [mailto:gitster@pobox.com] wrote:
I do not offhand see anything particularly stupid; a new optional index extension
section CACHE_EXT_RENAME_CONFLICT might be a good addition.
Is "one side moves A to B while the other side moves it to C" the only case, or is
it just an example? Off the top of my head, "one side moves A to x while the
other side moves B to x/y" would also be something we would want to know. I
am sure there are other cases that need to be considered.
Yes, that was just an example. Certainly I was intending that all conflicts
that arose from renames would end up here since one can't really reason
why the merge tool created a conflict by looking at the index alone - even
knowing the merge tool's similarity algorithms, this would be awfully
expensive to piece back together, even if the index did contain non-zero
stage entries for all the items that were involved in the conflicts.
That said, my rather naive initial thought was that we could repeat *all*
conflicts in this area. This would give tools that knew how to understand
this the ability to go to a single place for conflict data, rather than
producing some merge of high-stage entries that comprise non-rename
conflicts and data from the rename conflict area for rename conflicts.
Thanks-
-ed
Junio C Hamano [mailto:gitster@pobox.com] wrote:
Edward Thomson [off-list ref] writes:
quoted
I would propose that we store the data about the file in conflict as
it occurred through the renames. For example, in a rename 1->2
conflict where A was renamed to both B and C, you would have a single
conflict entry containing the data for A, B and C. This would allow
us to provide more detailed information to the user - and allow them
to (say) choose a single name to proceed with.
Is this something that has value to core git as well? Alternately, is
there something particularly stupid about this proposal?
I do not offhand see anything particularly stupid; a new optional index extension
section CACHE_EXT_RENAME_CONFLICT might be a good addition.
Is "one side moves A to B while the other side moves it to C" the only case, or is
it just an example? Off the top of my head, "one side moves A to x while the
other side moves B to x/y" would also be something we would want to know. I
am sure there are other cases that need to be considered.
I do not think we can discuss the design at the concrete level until the proposal
spells out to cover all interesting cases in order for implementations to agree on
the common semantics.
Sorry about the delay here: besides getting busy with some other things,
I wanted both a complete writeup and to have taken a pass at a test
implementation this in libgit2 to make sure seemed like a reasonably sensible
approach.
I would propose a new extension, 'CONF', to handle conflict data, differing
from the stage >0 entries in the index in that this extension tracks the
conflicting file across names if the underlying merge engine has support
for renames.
I made an attempt to keep the entry data similar to other entries in the
index. I would propose that entries in the conflict are as follows:
Flags
Four octets that describe the conflict. Data includes:
0x01 HAS_ANCESTOR
There is a file in the common ancestor branch that contributes
to this conflict. Its data will follow.
0x02 HAS_OURS
There is a file in "our" branch that contributes to this conflict.
Its data will follow.
0x04 HAS_THEIRS
There is a file in "their" branch that contributes to this conflict.
Its data will follow.
0x08 NAME_CONFLICT_OURS
This item has a path in "our" branch that overlaps a different
item in "their" branch. (Eg, this conflict represents the "our"
side of a rename/add conflict.)
0x10 NAME_CONFLICT_THEIRS
This item has a path in "their" branch that overlaps a different
item in "our" branch. (Eg, this conflict represents the "theirs"
side of a rename/add conflict.)
0x20 DF_CONFLICT_FILE
This is the file involved in a directory/file conflict.
0x40 DF_CONFLICT_CHILD
This is a child of a directory involved in a directory/file conflict.
Other bits are reserved.
Conflict Sides
The data about one side of a conflict will contain:
mode (ASCII string representation of octal, null-terminated)
path (null terminated)
sha1 (raw bytes)
The conflict sides will be written in this order:
Ancestor (if HAS_ANCESTOR is set)
Ours (if HAS_OURS is set)
Theirs (if HAS_THEIRS is set)
I would propose that this not simply track rename conflicts, but all
conflicts. Having a single canonical location is preferable - if the index
contains a CONF section (and the client supports it), it would use that.
Otherwise, the client would look at stage >0 entries.
I would propose that another extension, 'RSVD', track these conflicts once
they are resolved. The format would be the same - when a conflict is
resolved from the CONF the entry will be placed as-is in the RSVD.
Examples are not an exhaustive list, but should help elucidate the name
and d/f conflicts:
Normal edit / edit conflict, where A is edited in ours and theirs:
Conflict one:
Flags = HAS_ANCESTOR|HAS_OURS|HAS_THEIRS
Entry 1 = A [Ancestor]
Entry 2 = B [Ancestor]
Entry 3 = C [Ancestor]
Rename / add conflict, where A is renamed to B in ours and B is added in
theirs:
Conflict one:
Flags = HAS_ANCESTOR|HAS_OURS|NAME_CONFLICT_OURS
Entry 1 = A [Ancestor]
Entry 2 = B [Ours]
Entry 3 = A [Theirs]
Conflict two:
Flags = HAS_THEIRS|NAME_CONFLICT_THEIRS
Entry 1 = File B [Theirs]
D/F conflict, where some file A is deleted in theirs, and a directory
A is created with file child:
Conflict one:
Flags = HAS_ANCESTOR|HAS_OURS|HAS_THEIRS|DF_CONFLICT_FILE
Entry 1 = A [Ancestor]
Entry 2 = A [Ours]
Conflict two:
Flags = HAS_THEIRS|DF_CONFLICT_CHILD
Entry 1 = A/child [Theirs]
Thanks for your input on this.
-ed