MetaCvs is a version control system built on the CVS (ConcurrentVersionsSystem) platform. http://users.footprints.net/~kaz/mcvs.html Under CVS, a project is stored in the repository as a mirror of the checked out copy. That is to say, the CVS repository has the same file system hierarchy as the project, except that the files are RCS files, containing individual version histories. The names of the RCS files are derived directly from the checked out files, by the addition of a ,v suffix. Meta-CVS uses CVS differently. The CVS repository corresponding to a Meta-CVS project does not have the same tree shape as the checked-out project. The RCS files are arranged in a flat database. Moreover, their names are randomly-generated identifiers encoded in hexadecimal. Meta-CVS stores an additional text document called MAP (its RCS complement in the repository being MAP,v) which marks up the directory structure, in a Lisp notation. This markup document not only maps the anonymous objects to path names, but also specifies symbolic links, execute permissions and user-defined properties. Storing the directory structure as markup allows it to be readily susceptible to all of the normal version control operations: parallel editing, branching, merging, conflict resolution. The Meta-CVS software itself is a Lisp program which implements all the algorithms on the client side in order to bring the above data representation to life. At the core of Meta-CVS are algorithms which maintain the directory structure of the sandbox according to the markup document. Meta-CVS can patch the structure of the sandbox in order to keep it synchronized with changes in the markup. This may sound frightening (you do an update from the repository and your tree, with locally edited files and all, is being rearranged around before your eyes!) But in fact it is very robust. It's so robust that it's even harder to lose uncommitted changes under Meta-CVS than under CVS, which is already pretty good. Meta-CVS will even restore a file you have been working on, but accidentally deleted with your ``rm'' command or whatnot! That's because it maintains a hard link farm which keeps track of all the documents. If a document is deleted from the sandbox, there is still a link remaining to it in that farm. Meta-CVS provides all the operations needed so that the user doesn't have to deal with the MAP very much. For example, renaming files could be done by hand-editing the markup, and then running the update operation. But of course, a rename command is provided which essentially does the same thing. There are other algorithms in Meta-CVS that make it even more useful. One very nice in Meta-CVS is the grab command, which takes a snapshot of an external tree and brings it into a branch or the main trunk. In doing so, it first checks out the branch and automatically detects renames between the new snapshot and the existing baseline. Thus it is possible to track third-party code that comes from outside of version control, and which contains directory restructuring. You no longer have to tell outside developers to decide on a tree shape and stick with it ``because we are using CVS here''. Meta-CVS also has a ``managed branches'' feature: branching and merging simplified with automated tracking. Users can create branches, switch among them and merge, using simple commands. The CVS tags necessary to track everything are maintained by Meta-CVS. ---- It's also worth mentioning that the repository representation used by Meta-CVS eliminates a whole bunch of nasty bugs related to corner cases in CVS which are simply avoided. For example, suppose one developer tries to commit local changes to a file which meanwhile someone has removed. Or, here is a good one: suppose there once existed a file called "foo" which was deleted. It was a binary type. Of course, the "foo,v" RCS file still exists in the repository. Now someone adds a "foo" file. It's a text document, not binary. Guess what, the same RCS file is used! Oops, bug! How does Meta-CVS prevent problems with these scenarios? With regard to the first one, a file deletion in Meta-CVS does not lead to a "cvs rm". What happens simply is that a file is removed from the MAP. Since it is no longer in the markup document, it disappears from the directory structure. But it still exists! And what's more, local edits are not lost when someone picks up the deletion. The removal can be recovered, and there is a convenience command for doing that which places unlinked files into a lost+found directory in the sandbox from where they can be moved to any desired pathname. With regard to addition, when an "mcvs add" is executed, it generates a 128 bit GUID by which the file will be identified in CVS. Therefore, a new RCS file is generated. So it doesn't matter that there once existed a "foo" file; they are unrelated. If two files are concurrently added under the same pathname, each will get its own RCS file, and there will be a conflict in the directory structure markup document. Meta-CVS will detect and diagnose the duplicate use of the pathname, and not allow the sandbox reshaping to proceed until the problem is resolved. People who are used to broken corner case behavior out of version control will probably be shocked by Meta-CVS. :) ---- Meta-CVS supports nested sandboxes, which CVS doesn't. You can't check out a CVS project into a subdirectory of an existing checkout, because all subdirectories of a CVS sandbox have a CVS/ administrative directory. The new checkout will have to have its own CVS/Entries and other files. Under Meta-CVS, there is no problem, because there is only one administrative directory called MCVS, which is in the sandbox root. So two sandboxes cannot share the same root, but a sandbox can be checked out in a subdirectory of an existing sandbox. The mcvs command even has a feature for selecting which level to work at. For instance ``mcvs --up 1 commit'' means don't do the commit command on this sandbox, but escape up one level and do it there. ---- See RefactoringWithMetaCvs for an example of MetaCvs in use ---- CategoryConfigurationManagement