Dealing with Structural Conflicts

So far, we have only talked about conflicts at the level
of file content. When you and your collaborators make overlapping
changes within the same file, Subversion forces you to merge those
changes before you can commit.[7]

But what happens if your collaborators move or delete a file
that you are still working on? Maybe there was a miscommunication,
and one person thinks the file should be deleted, while another
person still wants to commit changes to the file. Or maybe your
collaborators did some refactoring, renaming files and moving
around directories in the process. If you were still working on
these files, those modifications may need to be applied to the
files at their new location. Such conflicts manifest themselves at
the directory tree structure level rather than at the file content
level, and are known as tree conflicts.

Tree conflicts prior to Subversion 1.6

Prior to Subversion 1.6, tree conflicts could yield
rather unexpected results. For example, if a file was
locally modified, but had been renamed in the repository,
running svn update would make Subversion
carry out the following steps:

Check the file to be renamed for local
modifications.

Delete the file at its old location, and
if it had local modifications, keep an on-disk copy
of the file at the old location. This on-disk copy
now appears as an unversioned file in the working
copy.

Add the file, as it exists in the repository,
at its new location.

When this situation arises, there is the possibility
that the user makes a commit without realizing that local
modifications have been left in a now-unversioned file in
the working copy, and have not reached the repository.
This gets more and more likely (and tedious) if the number
of files affected by this problem is large.

Since Subversion 1.6, this and other similar situations
are flagged as conflicts in the working copy.

As with textual conflicts, tree conflicts prevent a commit
from being made from the conflicted state, giving the user the
opportunity to examine the state of the working copy for potential
problems arising from the tree conflict, and resolving any such
problems before committing.

An example Tree Conflict

Suppose a software project you were working on currently
looked like this:

At this point, you need to run svn update.
Besides bringing our working copy up to date so that you can
see Harry's changes, this also flags a tree conflict so you
have the opportunity to evaluate and properly resolve it.

Note how bar.c is automatically scheduled for re-addition
in your working copy, which simplifies things in case you want
to keep the file.

Because a move in Subversion is implemented as a copy operation
followed by a delete operation, and these two operations cannot
be easily related to one another during an update, all Subversion
can warn you about is an incoming delete operation on a locally
modified file.
This delete operation may be part of a move,
or it could be a genuine delete operation. Talking to your
collaborators, or, as a last resort, svn log,
is a good way to find out what has actually happened.

Both foo.c and baz.c
are reported as locally modified in the output of
svn status. You made the changes to
foo.c yourself, so this should not be
surprising. But why is baz.c reported as
locally modified?

The answer is that despite the limitations of the move implementation,
Subversion was smart enough to transfer your local edits in
bar.c into baz.c:

Local edits to the file bar.c, which is
renamed during an update to baz.c, will
only be applied to bar.c if your working
copy of bar.c is based on the revision in
which it was last modified before being moved in the repository.
Otherwise, Subversion will resort to retreiving
baz.c from the repository, and will not
try to transfer your local modifications to it. You will have
to do so manually.

svn info shows the URLs of the items
involved in the conflict. The left
URL shows the source of the local side of the conflict,
while the right URL shows the source
of the incoming side of the conflict. These URLs indicate
where you should start searching the repository's history
for the change which conflicts with your local change.

If you do not agree with the move, you can delete
baz.c instead, after making sure any
changes made to it after it was renamed are either preserved
or not worth keeping. Do not forget to revert the changes
Harry made to the Makefile.
Since bar.c is already scheduled for
re-addition, there is nothing else left to do, and the conflict
can be marked resolved:

You are reading Version Control with Subversion (for Subversion 1.6), by Ben Collins-Sussman, Brian W. Fitzpatrick, and C. Michael Pilato.
This work is licensed under the Creative Commons Attribution License v2.0.
To submit comments, corrections, or other contributions to the text, please visit http://www.svnbook.com/.