Launchpad Entry: https://launchpad.net/products/bzr/+spec/bzr-cpick-data
Created: 2005-10-31 by AaronBentley
We should store merge information about each file explicitly. This should be recorded in the persistent store and in the working inventory, which also helps optimise commit in the common case.
Weave merge can handle cherrypicks well, but only if the right data is recorded in the weave. These changes will ensure that the right data is included in the weave.
Cherry-picks are partial merges, but there are two types of partial merges
- Merging only some revisions from a branch
- Merging only the changes to particular files
Tracking the first type of partial merge is nice, but requires extensive changes to the revision storage model. The model currently assumes that all lines were introduced either by a fully-merged ancestor, or by the revision itself. While tracking this information will produce better weave merges, it requires considerably more work. However, the current behaviour
So for now, we will concern ourselves with the second type.
We propose to track the predecessors that commit will use for each file in addition to the pending-merges list. This will supplement (but not supplant) the per-tree data. The per-tree data will still be used to determine the parents listed in the revision.
This will allow for more ancestors to be recorded in contents weaves, enabling better merges. It will also make it possible to distinguish between files added by a merge and files added by the user. This allows revert to behave differently for each case which is the behaviour expected by users..:
- Reverting files added by the user will simply make them unversioned.
- Reverting files added by a merge will cause them to be deleted.
- We want good support for cherry-picking
- We will achieve that support through weave merge
- Weaves can represent cherry-pick data (this may not be true-- we may need to make it true).
A user, Alice, is working on a branch of the mainline. She applies the changes revision 10 made to file A. She commits. She applies the changes revision 11 made to file B (without the changes revision 1 made). She commits.
Another user, Bob, independently makes the same change to file A, but not to file B.
A third user, Cuthbert, merges Alice, and commits. Merges Bob and commits. Merges the mainline and commits. Gets no conflicts at any point.
We add a new field to the inventory data: 'predecessors'. This will have 0 to many revision references, which may be ghosts. These references list only the heads of the predecessors. I.e. none of the references in this list are parents of each other (in the presence of ghosts this constraint may be broken, as it may not be calculable).
This means that it will not handle cherry-picking in sense 1. -- AaronBentley
<file file_id="bzrignore-20050311232317-81f7b71efa2db11a" name=".bzrignore" > <predecessors> <revision_ref revision_id="firstname.lastname@example.org" /> <revision_ref revision_id="email@example.com" /> </predecessors> </file_id>
The following operations will alter the predecessors list for files:
- Commit: Commit will use the predecessors list in its calculation for whether a new revision is needed, and also for the weave ancestors list when inserting a revision into a file weave. After commit the predecessors list for a file will be set appropriately for the *next* commit to use verbatim. No processing of a files weave should be needed if the predecessors list is one entry long and the id matches the id in the basis inventory, and the file has not been altered/reparented/renamed.
Uncommit: When uncommitting, the predecessors list for all files that had new revisions recorded in any of the popped-revisions will be set to the predecessors list used in the inventory of the oldest popped revision. If there is no predecessors list in that inventory, then the revision id of the file-id in the new last_revision()'s inventory will be used, unless the file id was new in that commit, in which case (obviously) no entry or predecessors are needed.
- Merge: Merge will invoke the find_previous_heads routine on each inventory entry in the output tree if any of the following are true: the file was renamed/reparented/content changed/ the merge-source has a revision id not in the current list of predecessors. The previous heads becomes the new predecessors list.
- Revert: Revert will put the predecessors list back to the revision id of the file in the basis inventory. If the file is not in the basis inventory, then its entry is removed from the working inventory. If the file id is not present in the basis inventory and the predecessors list in the working inventory was not empty, then the file was created by a merge and revert should delete it.
- Add: Add will add an empty predecessors list for files.
- Delete: Just removes the file id from the inventory.
No UI changes required
Commit, merge, uncommit, revert logic will need changing, though none should be needed at the UI layer.
upgrade should be taught to process the current pending merges file and create predecessors lists for all the files in the tree, as commit does today. There is a new format bump needed for this change.
I believe that weave format currently tracks ancestors and assumes each ancestor is fully merged. This may need to change, so that it indicates merged revisions instead.