[PATCH] new feature: takeover
From: Jonathan Gilbert <o2w9gs702_at_sneakemail.com>
Date: 2005-07-05 20:36:18 CEST
The story goes a little bit like this:
You're a lowly developer for some start-up company. For a couple of years, they use no source control at all, and the Visual Studio projects you've worked on build up on your hard drive. As the company grows, the number of developers also grows, and eventually, someone higher up decides to institute an SCM system. They pick the most obvious choice for a house using Visual Studio: Visual SourceSafe. They import all the projects from the most recent backup while you're in the meeting where they announce it.
So, when you return to your desk, you have your own copies of all the projects, and they have older versions of them all already in the Visual SourceSafe "database". You go through all your projects, and discover thankfully that all you need to do is select "File->Source Control->Change Source Control" in the IDE to "Bind" each project to the copy in the VSS repository. Thus things continue until one day, the VSS "database" becomes horribly corrupt.
The person in charge of the repository restores it from backup, but of course wants to prevent such things from happening in future. They read up a bit and are horrified to discover that VSS actually has many well-known flaws, and opt to switch to SVN, the "new CVS", since it has decent Visual Studio integration and is very easy to administer & use. So, once again, during the meeting where you learn about this, they migrate the VSS database over to the new SVN server.
You return to your desk and unbind all your projects from the now-defunct VSS server. Some of the files have changes, though, and of course there are a plaethora of files not under version control. You search and search for a way to tell SVN "Okay, this source tree is yours now", and are horrified to discover that there is no such function! For each of dozens of projects, you will have to do a brand new checkout from SVN, manually compare the trees and move the modified/unversioned files from the old tree to the new tree. This will take you a full day or more of time you could have been spending programming.
It is because of the above scenario (though in my case on a smaller, more personal scale) that, after some thought, I decided to sit down and hack a new command into the SVN command-line client. After investigating the issue and pondering the various factors involved, I realized that if an "svn checkout" operation were to simply ignore existing working copies, then subsequent commands like "svn status", "svn diff", "svn commit", and so forth would simply see the file as having been modified from the most recent checkout. If the files were in fact older than the repository copies, or if they were damaged in some way, "svn revert" would trivially restore them to what was in the repository.
I had already tried "svn checkout" overtop of the existing source tree, and that bailed with an "object of the same name already exists" error code. So, I grabbed the latest release source code and stripped out the parts that would require additional external libraries, and within an hour or so I had 1.2.0 building on my machine. I tracked down the source of that error message, and added plumbing to convey to it a boolean indicating whether my new "takeover" operation was being done, which, I emphasize, differs from a checkout only in that it leaves the existing working copy alone. If the boolean was set, then it would ignore the fact that the file already existed.
I had naively assumed that the code to actually place the file would be close to the error message, but of course I was completely wrong. So, I also added plumbing (within the file's "baton") to convey the fact that a file was in the process of being taken over and should not be re-installed from the text-base. This worked, but had two flaws:
1. The notification output still listed 'A' for the file, instead of indicating that it had not been touched.
I solved this by adding a new notification code, "svn_wc_notify_update_takeover", which places a 'T' where "svn_wc_notify_update_add" places an 'A'. The end of the "install_file" function checks if the file has been taken over, and passes it to the notify function if it has.
2. More troublingly, the "entries" file lacked a 'text-time' attribute for nodes representing files that had just been taken over.
Oddly enough, this didn't actually cause any problems that I could see; "svn status", "svn diff", "svn revert" all worked as expected without the expected "text-time" entry. However, I thought, nevertheless, that it would be a good idea to put that entry there. After some analysis of the code, I added a new log entry to set the file's "entries" entry 'text-time' attribute to the last commit time reported by the repository. This is conveyed to the function from the "change-file-prop" command, handled in libsvn_wc:update_editor.c, which conveys the commit time to the file baton during the execution of the update script.
The plumbing to get the "taking_over" boolean to the "add_file" method where the original "object of the same name already exists" error needed to be suppressed required a new parameter to the "add_file" method of the "svn_delta_editor_t" vtable. Since this vtable is used for everything that wants to walk the filesystem, both when handling update scripts and also when sending revisions back to the server, this has added that same parameter to functions implementing the "add_file" member to which the flag does not apply. In these cases, I named the parameter "taking_over__ignored" to indicate that the function did not plan to take any action related to the boolean's value.
Anyway, I have tested the change with a simple test case on my local repository, and it appears to work, so I submit it here for your perusal. I was not originally planning to submit it, suspecting that the depth of the changes and the moderate hackery involved would make it unlikely to be accepted, but sussman encouraged me to submit it nonetheless, just to see what the response will be. So, here it is :-)
Enjoy the attached diff,
P.S. the diff is against the head of tags/1.2.0, since that source code came with .DSP files enabling me to work on the project without installing Python on my Windows box. Had I grabbed the actual SVN head, I would have had difficulty creating the necessary project files, and would probably have lost interest before even coming up with a working build :-) So, to play with this diff, you will need to either check out the 1.2.0 tag from SVN to apply it against or reconcile the patch against the changes that have been made since 1.2.0 was branched from the trunk. My patch-reconciliation-fu is not strong, and I've used up all my available time making the changes in the first place, so all I can do is apologize for it being out-of-date. Anyway, enough rambling :-)
This is an archived mail posted to the Subversion Dev mailing list.