Resolving a tree conflict
A tree conflict can occur when parallel changes by two users cause a contradiction with regards to the hierarchy of versioned files or directories, i.e. a contradiction related to the location, name or existence of a particular versioned file or directory.
Regardless of the operation (a merge, update or switch) during which the conflict occurred, the effects of conflicts and the ways to resolve them are essentially the same.
Example of a tree conflict
Suppose that you decide to rearrange the location of some of the files in the repository.
Let’s assume that initially the trunk contains files named CHANGELOG.txt
and Usage.txt and a currently empty directory named docs, all located at the
root of the trunk.
trunk
├── CHANGELOG.txt
├── Usage.txt
└── docs
Changes on your feature branch
Suppose that you create a new feature branch that you call rearrange_docs
from the trunk and switch to it. And on that feature branch you move the
CHANGELOG.txt and Usage.txt from the root of the branch to a new location,
into the docs directory:
C:\Users\Alex\my_work_dir> svn move CHANGELOG.txt Usage.txt docs/
C:\Users\Alex\my_work_dir> svn commit -m "On rearrange_docs: moved doc files."
This relocation with svn move is essentially a tracked (ancestrally related)
copying of these files to the docs directory and a deletion of these files at
their original location.
So the names and hierarchy of files on the rearrange_docs branch now look as
follows:
rearrange_docs
└── docs
├── CHANGELOG.txt
└── Usage.txt
Changes on the trunk
Suppose that after you created that feature branch, your teammate on the
trunk makes and commits edits to CHANGELOG.txt, which on trunk is still
located at the root of the branch:
C:\Users\Jim\work_dir> svn status
M CHANGELOG.txt
C:\Users\Jim\work_dir> svn commit -m "Edited the CHANGELOG."
Furthermore, your teammate also renames Usage.txt to User_Guide.txt and
commits this change to the trunk:
C:\Users\Jim\work_dir> svn move Usage.txt User_Guide.txt
C:\Users\Jim\work_dir> svn commit -m "Renamed the user guide."
This renaming with svn move is essentially a tracked (ancestrally related)
copying of Usage.txt to User_Guide.txt, and a deletion of the original
Usage.txt.
So the CHANGELOG.txt on the trunk now has trunk-specific edits. And the
names and hierarchy of files on the trunk now look as follows:
trunk
├── CHANGELOG.txt
├── User_Guide.txt
└── docs
Syncing the feature branch
When you then update and sync your feature branch with the trunk, Subversion
will inform you that there are two tree conflicts.
Firstly, there is a tree conflict affecting CHANGELOG.txt. This is because
via the merge, you received a change (an edit) affecting the file
CHANGELOG.txt which should supposedly exist at the root of the branch, but
which no longer exists at that location on your feature branch. Luckily, after
informing you about this tree conflict, modern Subversion is smart enough to
resolve this conflict automatically, and will apply the incoming changes to
the CHANGELOG.txt at its new location on your feature branch
(docs/CHANGELOG.txt). Modern Subversion performs such automatic resolution if
there is only one reasonable course of action.
Secondly, there is a tree conflict affecting Usage.txt. This is because you
received a change (a rename, i.e. a copy and delete) affecting the file
Usage.txt which should supposedly exist at the root of the branch, but which
no longer exists at that location on your feature branch. In this case, to
Subversion, the incoming rename and the parallel relocation on your feature
branch look like two mutually-contradicting changes to the original Usage.txt.
Subversion does not know whose change is preferable, yours or your teammate’s.
Should it rename Usage.txt in place (as a copy and a delete in its original
directory) or should it prefer its existing relocation on the feature branch
(keeping its copy in the docs directory)?
So, you will need to resolve this remaining tree conflict affecting Usage.txt
yourself. A tree conflict can be resolved with the help of interactive
resolution.
Postponing conflict resolution
When a command results in a conflict, typically users choose to postpone
conflict resolution, by entering p (for “postpone”) when prompted.
This lets the current command (such as a merge or an update) finish.
After that, you can examine the conflicted files in the working copy one by one, and resolve these conflicts at a convenient pace. You will need to resolve the conflicts in the working copy before Subversion will allow you to commit your changes.
Resolving a tree conflict
Identifying the conflicted file
To see which items in the working copy currently have unresolved conflicts, display the status of the working copy:
C:\Users\Alex\my_work_dir> svn status
M .
! C Usage.txt
> local missing or deleted or moved away, incoming file delete or move upon merge
A + User_Guide.txt
M docs\CHANGELOG.txt
Summary of conflicts:
Tree conflicts: 1
A tree conflict (a conflict in the naming or location of a moved or deleted
file/directory) is indicated by letter C in the seventh column before the name
of such a conflicted file/directory. In this case, next to Usage.txt.
Subversion will also provide details about the cause of the conflict.
In TortoiseSVN, to see conflicted items, right-click in the File Explorer at the root of your working copy, and then select TortoiseSVN | Check for modifications.
Resolving interactively
When resolving tree conflicts in modern Subversion, it’s best to choose one
of the options suggested by the interactive resolver. Run the svn resolve
command on the conflicted file:
C:\Users\Alex\my_work_dir> svn resolve Usage.txt
In the TortoiseSVN GUI, to choose a resolution option, right-click at the root of your working copy, select TortoiseSVN | Check for modifications, then right-click the conflicted file and select one of the resolution options.
In modern Subversion, the conflict resolver searches repository history for structural changes (deletions, renames/moves and additions) which may have caused the tree conflict. The conflict resolver is able to detect relevant historical renames and moves in the repository, and take them into account when suggesting options to resolve the conflict.
In our example, the resolver will offer the following options:
Select: (p) Postpone, (r) Mark as resolved,
(m) Merge to corresponding local location, (M) Move and merge,
(h) Help, (q) Quit resolution:
You can select the option that you prefer:
-
If you choose
r, Subversion will simply mark the conflict as resolved and leave the current state of your working copy. That is, it will leave both theUser_Guide.txtat the root of the branch andUsage.txtin thedocsdirectory. -
If you choose the lower-case
m, Subversion will merge the two descendants of the originalUsage.txtinto one file, saving the resulting merged file to the corresponding local location (docs/Usage.txt). -
If you choose the upper-case
M, Subversion will merge the two descendants of the originalUsage.txtinto one file, saving the resulting merged file to its incoming location, i.e. to theUser_Guide.txtat the root of the branch.
Resolving manually
Usually, one of the suggested interactive resolutions will match your
intention. In a case when there is no suitable interactive option, choose the
one that is the closest to your intention to mark the conflict as resolved. Then
bring your working copy to the desired state, by using tracked tree change operations:
such as tracked moves with svn move.