Subversion Refactoring – Moving – Deleting Best Practices in eclipse’s subversive or subclipse Plugin

DISCLAIMER: If you use svn from the command line, this post is possibly irrelevant for you.

Possibly, you have found that post in a search engine, because you have had problems when doing refactoring in eclipse in a project checked out via svn. In that case, you may not want or need any introduction. Jump right away to the best practices. However, if not, you may want to know what this is all about. This post may seem awkward, futile or even harmful to those, who have not had similar problems as me when performing – let’s say – heavy refactoring work like moving and deleting files and folders in a checked out version of an svn repository. What kind of problems could there be, you might ask. Well, mainly problems that you cannot sync or merge your version with the repository after refactoring and your checked out version is – let’s call it – broken. What could have caused breaking your version, you might ask further. Honestly, the answer is: I don’t know. Actually, svn should prevent such breaking. However, if you work with an IDE like eclipse (or derivates thereof like Flash Builder), you will need an svn plugin for eclipse. And the plugin needs an additional service provider. So, there are a quite a few of different components involved in the actual handling with the svn server that could produce errors like not updating the svn meta files appropriately, causing things to break.

So, how can this post be futile? It is futile, if you do not have any problems like those mentioned above. If you do not work in an IDE with svn but on the command line, chances are that everything works out like a charm when doing refactoring work. Maybe you even perform changes directly with commands like ‘svn move’ or ‘svn delete’. Good! Fine! I don’t. I want everything nice and integrated into my IDE. So, how can this post be harmful? Well, if you follow my best practices, you will have A LOT of different version numbers in your repository. This is not exactly harmful, as each of the checked in versions should be completely functional and working. They may, however, semantically not be actually different versions regarding their functionality. Therefore, one could regard this as bad svn style. But I don’t care. It works. It is correct.

So, here are my best practices:

  1. Always commit all changes of your (working) project before you move or delete anything.
  2. Do NEVER delete folders with files or folders in it. svn stores information about modified and deleted files in a (hidden) .svn folder inside each folder. If you delete files in a folder AND the folder itself, chances are that some part of the svn toolchain does not update the .svn folder in the parent directory appropriately and there is no chance of letting svn know about the deleted files inside the deleted folder. The approach that works best for me is to delete files and folders recursively starting from the submost files and folders in the file tree. Delete files in the submost folder! Commit! Update (yes)! Delete folder! Commit! Update (yes)! As i said, proceed recursively through all folders.
  3. Do never delete two folders at once! To be more precise, if you delete all files in a source folder respectively in a package (a folder in the source folder always IS a package) in eclipse and the subfolder is empty, eclipse tends to group these empty folders visually into one package. For instance, if you have the folder structure ‘de.johannesluderschmidt.gestures.swipe’ in which the package/folder ‘gestures’ only contains the folder/package ‘swipe’ and no other folders or files, eclipse will show only one folder/package ‘gestures.swipe’ instead of a tree structure if ‘swipe’ is also an empty folder. Therefore, if you want to delete those two folders, the only thing eclipse offers you to do is to delete both folders AT ONCE by right clicking and choosing ‘Delete’. As to point 2, deleting nested files/folders is NOT A GOOD IDEA with svn. Proceed according to 2. If this is not possible in eclipse, go to your Finder, Explorer, command line or whatnot and delete the folders according to 2 manually in the file system.
  4. Be aware that if you choose ‘Rename’ in the context menu of a class, there will be no simple renaming in svn. For svn, the class file you renamed will be marked as deleted and a new class file will be created with the modified contents of the old class. Therefore, stick to 1. before renaming classes.

If you somehow break the synchronization between your project and the repository, back up your copy, delete your copy (NOT the backup) afterwards, check out the repository again and join the checked out and the backed up version manually. Hence, always be sure to check in code changes before deleting or moving ANYTHING according to point 1. Otherwise, you will have living hell.

If you have additional thoughts or best practices, please be so kind to post them in the comments. I struggled so many times with svn and eclipse in the last years that I am sure not to be the only one. So please share your knowledge!

Oh, and if anyone wants to recommend using Git (or Mercurial or whatnot) instead of svn: Yes, sure, nice. Better. I know. But such a humble hint will not help anyone that has to use svn at work.

Tagged with: eclipse, refactoring, subclipse, subversion, subversive, svn
  • This is excellent advice, for the simple reason that it agrees exactly with what I have figured out over time 🙂 Not theoretical, but practical knowledge. Many tears of frustration are shed along the way, is it not ?

    I do wonder about one thing, however: if you want to delete a folder tree with non-empty subfolders, why don’t you just delete the root folder with one “delete” operation in the eclipse svn repository view ? That’s what I do nowadays (for a long time before that I did the bottom-up recursive delete you describe, in the package explorer or navigation views).

    But I still have a nagging doubt as to whether there might be a problem lurking in this “delete the whole tree at once in the repository view” procedure. I was looking for something on this subject when I found your post.

    Suppose I have three branches A, B and C. A was commited first, later B was branched from A, and still later C was branched from B. If I delete B, will the repository manager be able to reconstruct C when someone wants to check out C ?

    I ask this because (some versions of ?) svn use a delta method to store revisions. If B is stored as a deltaA, and C as a deltaB, then actually checking out C involves calculating A + deltaA + deltaB. If B = deltaA is missing when C is to be checked out, C can’t be reconstructed as ((A + deltaA) + deltaB), because (A + deltaA) can’t be reconstructed.

  • @Stu Clayton Yes, C will be perfectly fine and you can still check it out. The reason for this is, you actually cannot delete B. You can only commit a new revision in which B is removed, but all previous revisions, where B was still there are not removed by this! So the deltas which are stored for branch C can still be applied to the “historical” data of B.

    You can also look at this another way: If this wasn’t the case, modifications to B would also affect C, which is exactly what branches are meant to prevent. You branch to have independently developing versions of some sources, so any operation on something else than the current branch will not affect it.

    As a technical sidenote: SVN does not have a special notion of branches (or tags for that matter). It simply allows you to copy anything to anywhere and convention has it that we initally create the three directories “trunk”, “tags”, and “branches” in which we organize our files accordingly. Creating a “branch” simply means copying the entire trunk directory to a nicely named subdirectory in the branches directory. So your question is technically equivalent to “Does deleting file A also affect file B which was created by making a copy of A?”

    And for completeness: Creating a “tag” is exactly the same as “branching”, except that by convention we don’t modify/commit a tag after it has been created! But SVN does not prevent you from doing so… there are only files/directories and the basic operations of adding/updating/removing/copying them (ok, there are some more, but that’s essentially it).

    All that is also a reason why there is only one global revision number (instead of having one per trunk/branch): It uniquely identifies the state of the whole repository at a particular point in time.