.pl 29.7c .nr PO 2.88c .nr LL 17c .nr HM 1.5c .nr FM 1.5c ... .FP Times ... .fp 1 R R.nomath ... .fp 5 CW LucidaSansCW83 .RP .TL vcs: Version Control with a Plan 9 Mindset .AH "Devon H. O'Dell " .SA vcs is a modern version control system providing easily accessible support for software development features that are commonly ignored in current popular version control software. This paper discusses its design, usage and implementation. .SE .SC 10 .NH 1 Introduction .LP vcs is a modern version control system designed to make use of features available in the Plan 9 operating system. vcs is built on top of .CW vac (1), the Venti archival utility. It is designed to easily work in both distributed and centralized software development environments and should scale well in either scenario. .NH 2 Version Control Models .NH 3 ``Push'' and ``Pull'' Models .LP Many modern, popularly used version control systems (such as cvs, Subversion, and Perforce) use centralized development models. In centralized models, a repository is stored on a central server where users with access to write to that repository are able to make changes to that system. This is generally referred to as a ``push'' model. While this model is suitable for many software projects, it does not quite fit in with the distributed design of the Plan 9 OS. .LP Distributed versioning systems do exist as well; software such as arch, darcs and BitKeeper are examples of these. While they do exist, I feel that the design and licenses attached to them are improper for Plan 9. Additionally, they assume a system more alike UNIX than Plan 9 is. In distributed systems, there is generally an ``official'' central repository from which releases are made, managed by one or more maintainers. Developers and maintainers create their own private branches of the ``central'' repository and work on these. When a maintainer feels that a patch in a branch should be incorporated in the official version of the software, the code is retrieved into the ``central'' repository. This is called a ``pull'' model. .LP Both models have specific advantages for different projects. Push models are advantageous in situations where sources are controlled and developed in a controlled environment. Pull models are generally better to work with in projects with an active lead, but loosely knit developer connections. .LP In fact, both the push and pull models operate in a quite similar respect. Many operations and ideas between the two are shared with a reversed order of operation. .NH 3 The ``Slide'' Model .LP vcs couples the push and pull concepts into a new model called ``sliding''. ``Sliding'' is the core concept of vcs. Both push and pull operations can be thought of as slide operations; branching trees is a slide operation. While not inherently different in operation from either the push or pull models, the slide model provides several advantages over both: .IP \(bu Using the same terminology for both models allows for (slightly) more verbose commands, which in turn make it easier for new users to learn the system. .IP \(bu Integrating both models to use the same commands allows for projects to change development models as it is seen fit and for developers to easily work in many projects with differing development models. .IP \(bu Branching code in centralized repositories is often a pain while this concept is vital for the operation of distributed repositories. By combining these two models, each one gains the advantages of the other. .IP \(bu In practice, both models can be used allowing for private, offline development, while still maintaining a central repository and controlled code environment. .NH 2 Goals of vcs .LP vcs is built upon a set of standards from which should never be deviated. .IP \(bu Simplicity of design. vcs should be implemented in a simple and understandable manner. vcs goes about this by simplifying and generalizing the models used in software control. .IP \(bu Ease of use. Nobody wants to spend weeks learning how to use a new version control system. .IP \(bu Speed. It is not a goal to be blazing fast, but vcs should never be unbearably slow. .IP \(bu Security. In controlled, centralized software development environments, security is premium. Security should not become obtuse, however, and where possible should be handled by the underlying system (and administrator). .IP \(bu Flexibility in a sane way. vcs should never overload the user nor administrator with options or features. vcs should never box the user nor administrator into a certain model. .NH 1 Using vcs .LP Before discussing the implementation of vcs, we shall first take a look at how it works in practice. This process will be discussed from the ground up: as it would be done when starting a new project. .NH 2 Deciding on a project model .LP Before beginning a repository, it's a good idea to make sure one understands the differences between the push and pull models and how they relate to the slide model interface provided by vcs. Although the slide model implemented by vcs makes this transparent to the user, understanding the differences in the models will help an administrator guide the contributors of the project. .LP If your project is based upon local developers who will be working on different parts of the project and should be working in a controlled setting, you will want to use a push model. .LP If you work solely or loosely with others on your project, you will want to use a pull model. .LP If your project is comprised of many local and distributed developers and is of a significant size, you can benefit from the hybrid model, which allows for a controlled main repository while allowing any developer the ability to work on side projects separately from the main branch. .LP After a project model has been settled on, it is important to note the differences in local workspaces. A project using the push model will export the repository that developers will push changes to. A project using the pull model will provide read access to everybody; developers create branches of the repository and pull changes into the main repository from their personal branches. The slide model allows for both development methods. .NH 2 Creating a repository .LP The first step any project must take is creating a repository, either empty or initialized from a certain set of sources. One interesting aspect of vcs is that the creation and branching of a repository are essentially the same operation. Repository creation can thus be done in one of several manners. .IP \(bu Initialize a new repository without importing sources. .P1 srv% vcs/newrepo myproject Enter description of project: [Description of project typed in stdin] ^D .P2 .IP \(bu Initialize a new repository and import sources (this is no different than the previous command; it simply illustrates the possibility of an import at creation time). .P1 srv% vcs/newrepo myproject import project_1 project_docs Enter description of project: [Description of project typed in stdin] ^D .P2 .IP \(bu Create a new branch of a repository. .P1 srv% vcs/slide myproject into local_workspace Branch local_workspace does not exist, create a new repository (y/n)? y Enter description of branch: [Description of branch typed in stdin] ^D .P2 .LP As is apparent, there is no inherent difference between a branch and a repository within vcs. Thus, when creating a branch, you retain the history of all branched files. These files are also given a new revision marking the branch with a log containing the branch description. You might wonder what happens if the branch ``repo_name'' already exists -- this will be discussed shortly. .NH 3 Configuring repository behavior .LP To provide flexibility, it is possible to configure the (as yet) only option per-repository, which reflects the repository development model. When unset, the option implies running under the slide model (hybrid mode). A vcs repository can be configured to operate under push and pull modes. For example: .P1 srv% vcs/configure myproject push_only Repository myproject configured as a centralized ("push model") server. srv% vcs/configure myproject pull_only Repository myproject configured as a distributed ("pull model") server. srv% vcs/configure myproject hybrid Repository myproject operating in default hybrid ("slide") mode. .P2 .LP When operating in different modes, vcs provides features specific to the model it is serving. .IP \(bu When operating in push mode, edits are registered with the server. It is thus possible to tell who is editing what files. .IP \(bu When operating in pull mode, a notification model is available that allows remote repositories to notify others of changes and submit patches. For users familiar with Plan 9, this functionality is similar to that of the .CW patch (1) utility. This is achieved by holding a separate repository containing notifications and their corresponding patches. .IP \(bu The default operation allows for both of these features, incorporating both modes of operation. .NH 2 Manipulating files in an existing repository .LP Most of the time spent on a project is in the development and planning stages; making changes to a repository should neither be time consuming nor difficult. Depending on the server model, changing files and incorporating patches is done in different ways. Since vcs operates in hybrid mode by default, examples of modification in both push and pull modes will be demonstrated in a hybrid repository. These examples can also be used when operating in either of the non-hybrid modes. .NH 3 Editing files .LP Depending on the development model being used for a project, editing files will happen in a different way reflecting the mindset behind that model. Developers used to worked under a push model would be surprised to know that modifications under a pull model are done directly in the local branch. This is not possible when developing in a push model*. .FS *While one could feasably edit the files directly in the repository, it is not recommended and measures are taken to ensure that these files are not edited. Modifying these files by hand could break the repository. .FE When working under a push model, files are marked as being edited before they are opened for editing, as illustrated below. .P1 srv% cd myproject/.workspace srv% vcs/edit main.c Opening myproject/main.c for edit. srv% vcs/edit doc/README Opening myproject/doc/README for edit. srv% vcs/edit doc/NOTES Warning: myproject/doc/NOTES is also being edited by user fred Opening myproject/doc/NOTES for edit. .P2 In the final case, it is apparent that the file is being edited by another user. In such a circumstance, both users are allowed to edit the file on a first-finished basis. The first developer to finish editing and pushing the file into the repository will win, no matter who opened the file first. In such a situation, the latter developer will either have to merge changes or arrange that with the other developer. Submitting the changes in the workspace is discussed following the next section. .LP Because the development mindset of the push model differs radically from that of the pull model, the above functionality is missing when working under the pull model. Under this model, files in the local workspace are directly modified. That is to say, work is done within the .workspace directory of the local branch: .P1 srv% cd myproject/.workspace srv% acme main.c .P2 No notification that files are being edited is necessary (every developer should have his or her own local branch; no protection is needed against multiple developers working on the same file). .NH 3 Developing under the pull method .LP If you are not working in a hybrid or pull repository, you can safely skip this section. .LP Creating a local branch of the repository is the first step to working in the repository. As shown above, this process happens as follows: .P1 srv% vcs/slide myproject into local_workspace Branch local_workspace does not exist, create a new repository (y/n)? y Enter description of branch: Local working branch for development of project myproject. ^D .P2 .LP After changes have been made to the necessary files, there are two ways to merge these files back into the head repository. The first method is the notify / pull method. In this case, a notification is sent to the main repository containing a description of the changes, as well as a set of incremental patches containing the history of the changes in the local workspace. .P1 srv% vcs/notify myproject from local_workspace Enter name of notification: spelling_warning_fix Enter description of changes made: Fixed spelling errors in documents and fixed compiler warnings in C code. ^D .P2 .LP After submitting the notification, the changes must still be merged into the repository. This can be done as follows: .P1 srv% vcs/notifications myproject spelling_warning_fix: Fixed spelling errors in documents and ... some_other_fix: Add documentation for frob Q and grob S. srv% vcs/slide myproject.notify.spelling_warning_fix into myproject Merging notification "spelling_warning_fix" into repo_name srv% .P2 .LP The other method is to pull the changes from the local workspace into the main repository. This example illustrates what happens when sliding into an existing branch. .P1 srv% vcs/slide myproject.local_workspace into myproject Merge changes from local_workspace into myproject (y/n)? y Enter description of changes made: Importing changes from local branch local_workspace. ^D .P2 .LP As with merging patches from the notification branch into the main tree, the patches are applied incrementally, giving a full history of the files as they were edited in the developers' local workspace. .LP Since the mindset behind distributed project development with the pull method encourages that patches not be submitted nor imported before they are tested and working and because there may be multiple milestones between the beginning of an initiative and submitting it via notify, it is possible to mark milestones in the development with the snapshot command, as illustrated below: .P1 srv% vcs/snapshot local_workspace Enter milestone: Stage 2 / 5: added several new menu types. Still buggy; this will be fixed in stage 3. ^D .P2 .NH 3 Developing under the push method. .LP As illustrated above, files are modified in the repository's workspace. When changes have been made, these can be committed to the main repository as outlined below: .P1 srv% vcs/slide myproject.workspace into myproject Enter description of changes: Updated documents.. ^D .P2 This process will go through the database of files marked as edit by the submitting user and merge them into the repository. .NH 3 Hybrid development .LP Development in a hybrid environment provides the advantages of both methods, but does have some differences when working under the push method. Namely, remote developers need to have some sort of guarantee that .NH 2 Subscribing to notifications .LP In a distributed environment, users should be able to tell when changes are made to a project. Failing to provide this feature means that projects with distributed developers will need to spend much more time communicating logistics than developing. Thus, vcs provides a notification subscription system so that developers can be kept up to date as to what is going on with remote projects without needing access to the repositories themselves. .NH 3 Setting up subscriptions .NH 3 Remote to local .NH 3 Local to remote ..