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.[9]
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.
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.
Suppose a software project you were working on currently looked like this:
$ svn list -Rv svn://svn.example.com/trunk/
     13 harry                 Sep 06 10:34 ./
     13 harry              27 Sep 06 10:34 COPYING
     13 harry              41 Sep 06 10:32 Makefile
     13 harry              53 Sep 06 10:34 README
     13 harry                 Sep 06 10:32 code/
     13 harry              54 Sep 06 10:32 code/bar.c
     13 harry             130 Sep 06 10:32 code/foo.c
$
        Later, in revision 14, your collaborator Harry renames the file
        bar.c to baz.c.
        Unfortunately, you don't realize this yet.  As it turns out,
        you are busy in your working copy composing a different set of
        changes, some of which also involve modifications
        to bar.c:
$ svn diff
Index: code/foo.c
===================================================================
--- code/foo.c	(revision 13)
+++ code/foo.c	(working copy)
@@ -3,5 +3,5 @@
 int main(int argc, char *argv[])
 {
     printf("I don't like being moved around!\n%s", bar());
-    return 0;
+    return 1;
 }
Index: code/bar.c
===================================================================
--- code/bar.c	(revision 13)
+++ code/bar.c	(working copy)
@@ -1,4 +1,4 @@
 const char *bar(void)
 {
-    return "Me neither!\n";
+    return "Well, I do like being moved around!\n";
 }
$
        You first realize that someone else has
        changed bar.c when your own commit
        attempt fails:
$ svn commit -m "Small fixes" Sending code/bar.c svn: E155011: Commit failed (details follow): svn: E155011: File '/home/svn/project/code/bar.c' is out of date svn: E160013: File not found: transaction '14-e', path '/code/bar.c' $
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.
$ svn update Updating '.': C code/bar.c A code/baz.c U Makefile Updated to revision 14. Summary of conflicts: Tree conflicts: 1 $
In its output, svn update signifies tree conflicts using a capital C in the fourth output column. svn status reveals additional details of the conflict:
$ svn status
M       code/foo.c
A  +  C code/bar.c
      >   local edit, incoming delete upon update
Summary of conflicts:
  Tree conflicts: 1
$
        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. Determining exactly what semantic change was made to the repository is important—you want to know just how your own edits fit into the overall trajectory of the project. So read log messages, talk to your collaborators, study the line-based differences—do whatever you must do—to determine your best course of action.
In this case, Harry's commit log message tells you what you need to know.
$ svn log -r14 ^/trunk ------------------------------------------------------------------------ r14 | harry | 2011-09-06 10:38:17 -0400 (Tue, 06 Sep 2011) | 1 line Changed paths: M /Makefile D /code/bar.c A /code/baz.c (from /code/bar.c:13) Rename bar.c to baz.c, and adjust Makefile accordingly. ------------------------------------------------------------------------ $
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.
$ svn info code/bar.c | tail -n 4 Tree conflict: local edit, incoming delete upon update Source left: (file) ^/trunk/code/bar.c@4 Source right: (none) ^/trunk/code/bar.c@5 $
bar.c is now said to be the
        victim of a tree conflict.
        It cannot be committed until the conflict is resolved:
$ svn commit -m "Small fixes" svn: E155015: Commit failed (details follow): svn: E155015: Aborting commit: '/home/svn/project/code/bar.c' remains in confl ict $
To resolve this conflict, you must either agree or disagree with the move that Harry made.
If you agree with the move, your bar.c
        is superfluous.  You'll want to delete it and mark the tree
        conflict as resolved.  But wait:  you made changes to that
        file!  Before deleting bar.c, you need to
        decide if the changes you made to it need to be applied
        elsewhere, for example to the new baz.c
        file where all of bar.c's code now lives.
        Let's assume that your changes do need to “follow the
        move”.  Subversion isn't smart enough to do this work
        for you[10], so you need to migrate your
        changes manually.
In our example, you could manually re-make your change
        to bar.c pretty easily—it was,
        after all, a single-line change.  That's not always the case,
        though, so we'll show a more scalable approach.  We'll first
        use svn diff to create a patch file.  Then
        we'll edit the headers of that patch file to point to the new
        name of our renamed file.  Finally, we re-apply the modified
        patch to our working copy.
$ svn diff code/bar.c > PATCHFILE
$ cat PATCHFILE
Index: code/bar.c
===================================================================
--- code/bar.c	(working copy)
+++ code/bar.c	(working copy)
@@ -1,4 +1,4 @@
 const char *bar(void)
 {
-    return "Me neither!\n";
+    return "Well, I do like being moved around!\n";
 }
$ ### Edit PATCHFILE to refer to code/baz.c instead of code/bar.c
$ cat PATCHFILE
Index: code/baz.c
===================================================================
--- code/baz.c	(working copy)
+++ code/baz.c	(working copy)
@@ -1,4 +1,4 @@
 const char *bar(void)
 {
-    return "Me neither!\n";
+    return "Well, I do like being moved around!\n";
 }
$ svn patch PATCHFILE
U         code/baz.c
$
        Now that the changes you originally made
        to bar.c have been successfully
        reproduced in baz.c, you can
        delete bar.c and resolve the conflict,
        instructing the resolution logic to accept what is currently
        in the working copy as the desired result.
$ svn delete --force code/bar.c
D         code/bar.c
$ svn resolve --accept=working code/bar.c
Resolved conflicted state of 'code/bar.c'
$ svn status
M       code/foo.c
M       code/baz.c
$ svn diff
Index: code/foo.c
===================================================================
--- code/foo.c  (revision 14)
+++ code/foo.c  (working copy)
@@ -3,5 +3,5 @@
 int main(int argc, char *argv[])
 {
     printf("I don't like being moved around!\n%s", bar());
-    return 0;
+    return 1;
 }
Index: code/baz.c
===================================================================
--- code/baz.c  (revision 14)
+++ code/baz.c  (working copy)
@@ -1,4 +1,4 @@
 const char *bar(void)
 {
-    return "Me neither!\n";
+    return "Well, I do like being moved around!\n";
 }
$
        But what if you do not agree with the move?  Well, in that
        case, 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 also
        revert the changes Harry made to Makefile.)
        Since bar.c is already scheduled for
        re-addition, there is nothing else left to do, and the
        conflict can be marked resolved:
$ svn delete --force code/baz.c
D         code/baz.c
$ svn resolve --accept=working code/bar.c
Resolved conflicted state of 'code/bar.c'
$ svn status
M       code/foo.c
A  +    code/bar.c
D       code/baz.c
M       Makefile
$ svn diff
Index: code/foo.c
===================================================================
--- code/foo.c	(revision 14)
+++ code/foo.c	(working copy)
@@ -3,5 +3,5 @@
 int main(int argc, char *argv[])
 {
     printf("I don't like being moved around!\n%s", bar());
-    return 0;
+    return 1;
 }
Index: code/bar.c
===================================================================
--- code/bar.c	(revision 14)
+++ code/bar.c	(working copy)
@@ -1,4 +1,4 @@
 const char *bar(void)
 {
-    return "Me neither!\n";
+    return "Well, I do like being moved around!\n";
 }
Index: code/baz.c
===================================================================
--- code/baz.c	(revision 14)
+++ code/baz.c	(working copy)
@@ -1,4 +0,0 @@
-const char *bar(void)
-{
-    return "Me neither!\n";
-}
Index: Makefile
===================================================================
--- Makefile	(revision 14)
+++ Makefile	(working copy)
@@ -1,2 +1,2 @@
 foo: 
-	$(CC) -o $@ code/foo.c code/baz.c
+	$(CC) -o $@ code/foo.c code/bar.c
        You've now resolved your first tree conflict! You can commit your changes and tell Harry during tea break about all the extra work he caused for you.
[9] Well, you could mark files containing conflict markers as resolved and commit them, if you really wanted to. But this is rarely done in practice.
[10] In some cases, Subversion 1.5 and 1.6 would actually handle this for you, but this somewhat hit-or-miss functionality was removed in Subversion 1.7.