Junio C Hamano [mailto:gits...@pobox.com] wrote:
> Edward Thomson <ethom...@microsoft.com> 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to