Skip to main content

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 the User_Guide.txt at the root of the branch and Usage.txt in the docs directory.

  • If you choose the lower-case m, Subversion will merge the two descendants of the original Usage.txt into 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 original Usage.txt into one file, saving the resulting merged file to its incoming location, i.e. to the User_Guide.txt at 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.