Next: , Previous: Inodeprints, Up: Advanced Uses


3.6 Merge Conflicts

Several different types of conflicts may be encountered when merging two revisions using the database merge commands merge, explicit_merge, propagate and merge_into_dir or when using the workspace merge commands update, pluck and merge_into_workspace. The show_conflicts command can be used to list conflicts between database revisions which would be encountered by the database merge commands. Unfortunately, this command can't yet list conflicts between a database revision and the current workspace revision which would be encountered by the workspace merge commands.

3.6.1 Conflict Types

Monotone versions both files and directories explicitly and it tracks individual file and directory identity from birth to death so that name changes throughout the full life-cycle can be tracked exactly. Partly because of these qualities, monotone also notices several types of conflicts that other version control systems may not.

The two most common conflicts are described first, then all other possible conflicts.

File Content Conflict

This type of conflict is generally the one encountered most commonly and represents conflicting changes made to lines of text within two versions of a single file.

Monotone does not generally use CVS style conflict markers for content conflicts. Instead it makes the content of both conflicting files and the content of their common ancestor available for use with your favorite merge tool. See the merge3 hook for more information.

Alternatively, rather than using a merge tool it is possible to make further changes to one or both of the conflicting file versions so that they will merge cleanly. This can also be a very helpful strategy if the merge conflicts are due to sections of text in the file being moved from one location to another. Rather than struggling to merge such conflicting changes with a merge tool, similar rearrangements can be made to one of the conflicting files before redoing the merge.

Duplicate Name Conflict

A duplicate name conflict occurs when two distinct files or directories have been given the same name in the two merge parents. This can occur when each of the merge parents adds a new file or directory with the conflicting name, or when one parent adds a new file or directory with the conflicting name and the other renames an existing file or directory to the conflicting name, or when both parents rename an existing file or directory to the conflicting name.

In earlier versions of monotone (before version 0.39) this type of conflict was referred to as a rename target conflict although it doesn't necessarily have anything to do with renames.

There are two main situations in which duplicate name conflicts occur:

These conflicts are reported when someone tries to merge the two revisions containing the new files.

Same file

For the first case, the conflict is resolved by droping one file. The contents should be manually merged first, in case they are slightly different. Typically, a user will have one of the files in their current workspace; the other can be retrieved via automate get_file_of; the revision id is shown in the merge error message. The process can be confusing; here's a detailed example.

Suppose Beth and Abe each commit a new file checkout.sh. When Beth attempts to merge the two heads, she gets a message like:

     mtn: 2 heads on branch 'testbranch'
     mtn: [left]  ae94e6677b8e31692c67d98744dccf5fa9ccffe5
     mtn: [right] dfdf50b19fb971f502671b0cfa6d15d69a0d04bb
     mtn: conflict: duplicate name 'checkout.sh'
     mtn: added as a new file on the left
     mtn: added as a new file on the right
     mtn: error: merge failed due to unresolved conflicts

The file labeled right is the file in Beth's workspace. To retrieve a copy of Abe's file, Beth executes:

     mtn automate get_file_of checkout.sh \
     --revision=ae94e6677b8e31692c67d98744dccf5fa9ccffe5 \
     > checkout.sh-merge

Now Beth manually merges (using her favorite merge tool) checkout.sh and checkout.sh-merge, leaving the results in checkout.sh-merge (not in her copy).

Then Beth drops her copy, and commits that change:

     mtn drop checkout.sh
     mtn commit --message "resolving conflicting 'checkout.sh'"

Now Beth can merge the two heads, and update her workspace:

     mtn merge
     mtn update

This leaves a copy of Abe's original checkout.sh. Beth overwrites it with her merged version, and commits again:

     rm checkout.sh
     mv checkout.sh-merge checkout.sh
     mtn commit --message "resolving conflicting 'checkout.sh' - done"

When Abe later syncs and updates, he will get the merged version.

Different files

The second case, where two different files accidently have the same name, is resolved by renaming one or both of them.

Suppose Beth and Abe each start working on different thermostat models (say Honeywell and Westinghouse), but they both name the file thermostat. When Beth attempts to merge, she will get the same error message as in the first case. When she retrieves Abe's file, she will see that they should be different files. So she renames her file, merges, and updates:

     mtn rename thermostat thermostat-honeywell
     mtn merge
     mtn update

Now she has her file in thermostat-honeywell, and Abe's in thermostat. She may rename Abe's file to thermostat-westinghouse, or ask Abe to do that.

If a project has a good file naming convention, this second case should be rare.

Missing Root Conflict

Monotone's merge strategy is sometimes referred to as die-die-die merge, with reference to the fact that when a file or directory is deleted there is no means of resurrecting it. Merging the deletion of a file or directory will always result in that file or directory being deleted.

A missing root conflict occurs when some directory has been moved to the root directory in one of the merge parents and has been deleted in the other merge parent. Because of die-die-die merge the result will not contain the directory that has been moved to the root.

Missing root conflicts should be very rare because it is unlikely that a project's root directory will change. It is even more unlikely that a project's root directory will be changed to some other directory in one merge parent and that this directory will also be deleted in the other merge parent. Even still, a missing root directory conflict can be easily resolved by moving another directory to the root in the merge parent where the root directory was previously changed. Because of die-die-die merge, no change to resolve the conflict can be made to the merge parent that deleted the directory which was moved to the root in the other merge parent.

See the pivot_root command for more information on moving another directory to the project root.

Invalid Name Conflict

Monotone reserves the name _MTN in a workspace root directory for internal use and treats this name as illegal for a versioned file or directory in the project root. This name is legal for a versioned file or directory as long as it is not in the project root directory.

An invalid name conflict occurs when some directory is moved to the project root in one of the merge parents and a file or directory that exists in this new root directory is renamed to _MTN or a new file or directory is added with the name _MTN to this directory in the other merge parent.

Invalid name conflicts should be very rare because it is unlikely that a project's root directory will change. It is even more unlikely that a project's root directory will change and the new root directory will contain a file or directory named _MTN. Even still, an invalid name conflict can be easily resolved in several different ways. A different root directory can be chosen, the offending _MTN file or directory can be renamed or deleted, or it can be moved to some other subdirectory in the project.

See the pivot_root command for more information on moving another directory to the project root.

Directory Loop Conflict

A directory loop conflict occurs when one directory is moved under a second in one of the merge parents and the second directory is moved under the first in the other merge parent.

Directory loop conflicts should be rare but can be easily resolved by moving one of the conflicting directories out from under the other.

Orphaned Node Conflict

An orphaned node conflict occurs when a directory and all of its contents are deleted in one of the merge parents and further files or directories are added to this deleted directory, or renamed into it, in the other merge parent.

Orphaned node conflicts do happen occasionally but can be easily resolved by renaming the orphaned files or directories out of the directory that has been deleted and into another directory that exists in both merge parents, or that has been added in the revision containing the orphaned files or directories.

Multiple Name Conflict

A multiple name conflict occurs when a single file or directory has been renamed to two different names in the two merge parents. Monotone does not allow this and requires that each file and directory has exactly one unique name.

Multiple name conflicts do happen occasionally but can be easily resolved by renaming the conflicting file or directory in one or both of the merge parents so that both agree on the name.

In earlier versions of monotone (those before version 0.39) this type of conflict was referred to as a name conflict.

Attribute Conflict

An attribute conflict occurs when a versioned attribute on a file or directory is set to two different values by the two merge parents or if one of the merge parents changes the attribute's value and the other deletes the attribute entirely.

Attribute conflicts may happen occasionally but can be easily resolved by ensuring that the attribute is set to the same value or is deleted in both of the merge parents. Attributes are not merged using the die-die-die rules and may be resurrected by simply setting their values.

3.6.2 Conflict Resolution

Resolving the different types of conflicts is accomplished by checking out one of the conflicting revisions, making changes as described above, committing these changes as a new revision and then running the merge again using this new revision as one of the merge parents. This process can be repeated as necessary to get two revisions into a state where they will merge cleanly, or with a minimum of file content conflicts.