Next: Workspace Collisions, Previous: Inodeprints, Up: Advanced Uses [Contents][Index]
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.
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.
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 add
ed 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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: Workspace Collisions, Previous: Inodeprints, Up: Advanced Uses [Contents][Index]