Junio C Hamano [mailto:gitster@xxxxxxxxx] wrote: > Edward Thomson <ethomson@xxxxxxxxxxxxx> 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. 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 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html