Next: , Previous: , Up: Advanced Uses   [Contents][Index]


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 and automate show_conflicts commands can be used to list conflicts between database revisions which would be encountered by the database merge commands. Unfortunately, these commands can’t yet list conflicts between a database revision and the current workspace.

In addition, the conflicts set of commands can be used to specify resolutions for some conflicts. The resolutions are stored in a file, and given to the merge command via the --resolve-conflicts-file=filename or --resolve-conflicts option; see Conflicts.

The merge command normally will perform as many merges as necessary to merge all current heads of a branch. However, when --resolve-conflicts-file is given, the conflicts and their resolutions apply only to the first merge, so the subsequent merges are not done; the merge command must be repeated, possibly with new conflicts and resolutions, to merge the remaining heads.

For the special case of file content conflicts, a merge command invoked without --resolve-conflicts will attempt to use an internal content merger; if that fails, it will attempt to start an external interactive merge tool; the user must then resolve the conflicts and terminate the merge tool, letting monotone continue with the merge. This process is repeated for each file content conflict. See File Content Conflict below for more detail.

For other conflicts, a merge command invoked without --resolve-conflicts will fail.

If conflicts supports resolving a particular conflict, that is the simplest way to resolve it. Otherwise, resolving the different types of conflicts is accomplished by checking out one of the conflicting revisions, making changes as described below, 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.

The possible conflict resolutions are discussed with each conflict in the following sections.

3.6.1 Conflict Types

Monotone versions files, directories, and file attributes 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 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.

When a merge command encounters changes in a file in both heads relative to the common ancestor, it first checks to see if the file has a mtn:manual_merge attribute with value true. If not, it uses an internal merge algorithm to detect whether the changes are to the same lines of the file. If they are not, monotone will use the result of the internal merge as the new file version. Note that this may not always be what the user wants; if the same line is added at two different places in the file, it will be in the result twice.

mtn:manual_merge is automatically set true when a file is added for which the binary_file hook returns true; see attr_init_functions. The user may also set the mtn:manual_merge attribute manually; see mtn attr.

If mtn:manual_merge is present and true, or if the changes are to the same lines of the file, and neither --resolve-conflicts nor --non-interactive was specified, the merge3 hook is called, with the content of both conflicting versions and their common ancestor. When the hook returns, the merge proceeds to the next conflict.

Alternatively, you can use your favorite merge tool asychronously with the merge, and specify the result file in the conflicts file, using the Conflicts command:

mtn conflicts resolve_first user filename

Then --resolve-conflicts is specified on the merge command line.

Finally, rather than using a merge tool it is possible to commit 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.

There are similar conflicts for directories; the process for resolving them is different, because we need to worry about the files in the directories.

Same file

For the first case, the conflict is resolved by dropping one file. The contents should be manually merged, 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.

This process can be confusing; here’s a detailed example. We assume the Conflicts commands are used to resolve this conflict, since that is supported.

Suppose Beth and Abe each commit a new file checkout.sh, with similar contents. 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 start the conflict resolution process, Beth first saves the list of conflicts:

mtn conflicts store

In order to merge Beth’s and Abe’s file versions, Beth retrieves a copy of Abe’s file:

mtn automate get_file_of checkout.sh \
--revision=ae94e6677b8e31692c67d98744dccf5fa9ccffe5 \
> _MTN/resolutions/checkout.sh-abe

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

Then Beth specifies the conflict resolution, and finishes the merge:

mtn conflicts resolve_first_left drop
mtn conflicts resolve_first_right user _MTN/resolutions/checkout.sh-merge
mtn merge --resolve-conflicts-file=_MTN/conflicts
mtn conflicts clean
mtn update

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 (again using Conflicts commands):

mtn conflicts store
mtn conflicts resolve_first_left rename thermostat-westinghouse
mtn conflicts resolve_first_right rename thermostat-honeywell
mtn merge --resolve-conflicts-file=_MTN/conflicts
mtn conflicts clean
mtn update

Now she has her file contents in thermostat-honeywell, and Abe’s in thermostat-westinghouse.

Directories

When two directories are given the same name, there are still the two basic approaches to resolving the conflict; drop or rename. However, if a directory is dropped, all the files in it must also be dropped. Therefore, it is almost always better to first rename one of the directories to a temporary name as the conflict resolution, and then deal with the files individually, renaming or merging and dropping each. Then finally drop the temporary directory. The conflicts commands do not support doing this; it must be done directly.

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.

conflicts does not support resolving this conflict.

Dropped/Modified file Conflict

This conflict occurs when a file is dropped in one merge parent, and modified in the other.

conflicts supports resolving this conflict; the possible resolutions are to drop the file in the result, keep the modified version, or keep a user supplied version.

In addition, the attribute mtn:resolve_conflict may be used to specify a drop resolution for this conflict. --resolve-conflicts must be specified on the merge command for the attribute to be processed. Note that a _MTN/conflicts file left over from a previous merge will be processed when --resolve-conflicts is specified; the user must delete such files when they are no longer needed.

The attribute is useful in the case where the conflict will occur again in the future, for example when a file that is maintained in an upstream branch is not needed, and therefore dropped, in a local branch. The user only needs to specify the conflict resolution once, via the attribute.

Because of the die-die-die policy, monotone internally must first drop the modified file, and then add a new file with the same name and the desired contents. This means history is disconnected; when mtn log is later run for the file, it will stop at this merge, not showing the previous history for the file. That history is still there; the user can see it by starting mtn log again for the same file but in the parent of the merge.

Note that we don’t need a keep value for the mtn:resolve_conflict attribute; if the local branch keeps a file that the upstream branch drops, the first keep resolution will break history, and the conflict will not occur again.

A special case occurs when the user re-adds the file after dropping it, then attempts to merge. In this case, the possible resolutions are to keep the re-added version, or keep a user modified version, replacing the re-added version (drop is not a valid resolution).

There is no such thing as a dropped/modified directory; if the directory is empty, the only possible change is rename, which is ignored.

If the directory is not empty, that creates a special case of dropped/modified file conflict; if the file is kept, it must also be renamed to an existing directory.

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.

conflicts does not yet support resolving this conflict.

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.

conflicts does not yet support resolving this conflict.

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.

conflicts supports resolving this conflict. However, if the orphaned node is a directory that is not empty, and the desired resolution is ’drop’, the user must drop the directory contents and commit before invoking the conflicts commands.

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.

conflicts does not yet support resolving this conflict.

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.

conflicts does not yet support resolving this conflict.


Next: , Previous: , Up: Advanced Uses   [Contents][Index]

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status