notes on applying a merge changeset

Denys Duchier duchier at ps.uni-sb.de
Thu Dec 29 01:55:19 GMT 2005


These notes are primarily for my own benefit, but I'd appreciate
feedback.

KINDS OF CHANGES IN A CHANGESET ENTRY
-------------------------------------

Each changeset entry stipulates 3 kinds of changes:

  * what is changed in the topology (the tree structure)
  * what is changed in the contents
  * what is changed in the metadata

In each case, there are four possible kinds:

  * delete
  * create
  * modify
  * keep

Actually, in order to support changing the type of an entry, we may
want to admit a 4th value "typechange" as a new kind of "contents"
change.

topology_change_kind:

  * delete: the id is in src but not in dst
  * create: the id is in dst but not in src
  * modify: the id is in both, and the entry is moved and/or renamed
  * keep  : the id is in both, and the entry is neither moved nor renamed

contents_change_kind:

  * delete: there is contents associated with id in src, but not in dst
  * create: there is contents associated with id in dst, but not is src
  * modify: id is associated with different contents in src and dst
  * keep  : id is associated with the  same contents in src and dst

metadata_change_kind:

  * delete: there is metadata associated with id in src, but not in dst
  * create: there is metadata associated with id in dst, but not in src
  * modify: id is associated with different metadata in src and dst
  * keep  : id is associated with the  same metadata in src and dst

change_kinds:

  returns a triple of strings (topology,contents,metadata) describing
  the changes in the respective dimensions.

PHASES OF APPLICATION OF A CHANGESET
------------------------------------

Application of a merge changeset happens in 2 phases:

  * apply_into_limbo
  * apply_from_limbo

For each entry:

  T,C,M = self.change_kinds()


APPLY_INTO_LIMBO:
~~~~~~~~~~~~~~~~~

This phase considers changeset entries sorted bottom-up according to
the src tree (the this tree).  For each entry:

  if T=="delete": {DELETE ENTRY}
  if C=="delete": {DELETE FILE (if present)}
  if T=="modify": {MOVE FILE (if present) AND ENTRY INTO LIMBO}


APPLY FROM LIMBO:
~~~~~~~~~~~~~~~~~

This phase considers changeset entries sorted top-down according to
the dst tree (the other tree).  For each entry:

  if T=="modify": {MOVE FILE (if present) AND ENTRY FROM LIMBO}
  if T=="create": {INSERT ENTRY}
  if C=="create": {CREATE FILE IN PLACE}
  if C=="modify": {MODIFY FILE IN PLACE / OR CREATE IF NOT PRESENT}
  if M=="create": {APPLY TO ENTRY, ALSO TO FILE IF PRESENT}
  if M=="modify": {APPLY TO ENTRY, ALSO TO FILE IF PRESENT}


There is currently code that attempts to preserve uncommited changes
in metadata (the exec flag).  I think that all uncommited changes
should be "preserved".  In other words: we should be merging into a
"working tree", not merely into a pristine checkout of a committed
revision.

I do not see why merging into a tree with uncommitted changes should
be ruled out.  I understand that it may be desirable to warn the user
about possibly unintended consequences, but I don't think that the UI
should be dictating the library API.

Cheers,

--Denys






More information about the bazaar mailing list