CVS is a tool that can help you manage a project, but you need to decide how to use CVS with your project to make it work effectively for you and your team. The following sections present some ideas to help you integrate CVS into your working practices.
Decide whether and how you will use tags and branches, and then decide on the format to use for tag and branch names. Branching philosophies, styles, and policies are explained in Section 4.4 section of Chapter 4.
I strongly recommend keeping almost-complete work separate from experimental work. In programming projects, I recommend keeping bug fixes separated from the main body of development by putting either bug corrections or development on a branch.
If you use branches, designate an owner for each branch. The owner should be responsible for seeing that the branch is used for its specified purpose, for maintaining a record of the changes made to that branch, and for managing merges to or from that branch.
I strongly recommend tagging at strategic points in development, at the root of each branch, and at each merge point. See Section 4.1.6 of Chapter 4 for more suggestions for tagging.
Automation can be helpful in ensuring that a project moves smoothly to completion. Generally, automation translates into consistency. When using CVS on a project, you may find the following automation strategies to be helpful:
Use the scripting files in CVSROOT to enforce project standards and assist project communication.
Automate builds to encourage projects to be tested frequently. This also ensures that the entire build process is recorded and performed correctly every time.
Integrate CVS to your change-tracking program, to minimize the effort developers have to put in to do both version control and change tracking.
Keep computer clocks synchronized with each other to ensure that CVS can read accurate last-modified times.
Consider breaking a project into subprojects or using modules so that each developer needs to check out only their part of the project.
In small projects, each sandbox can contain the entire source tree. In larger projects, use symbolic links or other tools to allow the developers to share a central set of standard files. A developer's sandbox should contain only the files he needs to work on, and the build script in his sandbox should include commands to create the necessary symbolic links to the central files. This allows him to compile and test his own code without having to compile files he hasn't changed.
Consider having a central build sandbox that is automatically updated and built on a regular schedule. This sandbox can be used to test the integration of the whole project. If developers fail to commit all their necessary files, the central build usually fails, because the update is unable to retrieve the uncommitted files. This makes it obvious when someone has forgotten to commit a crucial file.
Each task should have its own sandbox. Each developer, tester, and editor should work from her own sandbox, and anyone who is working on multiple branches should work from a different sandbox for each branch. If there is a central build, it should be in its own sandbox. If there is a file server, it should be a separate sandbox.
Use cvs release to remove sandboxes. This helps prevent modified or new files from being forgotten. If the history file is in use, this command records the removal of a sandbox.
Decide whether to use the simultaneous development model or one of the watching files or reserving files models of exclusive development. These models are explained in Chapter 5, which also explains how to use each model in CVS.
Consider using watches, notification emails sent via scripting files, or other tools to keep developers informed of what is happening during a project's development.
Develop strategies for updating and committing sandboxes. Sandboxes and the repository need to be kept synchronized to minimize conflicts and ensure that a project is fully backed-up. Deciding how frequently your users update and commit is a matter of judging the risk of breaking the build with incomplete work versus the benefits of storing data, even when it won't compile.
The most common work pattern for development projects is update-edit-test-commit. In this pattern, your developers update a sandbox first thing in the morning, work on their files, test their files, and commit at the end of the day. Some groups commit at lunchtime and update again after lunch, working on a shorter cycle.
The greatest risk with frequent commits occurs in environments where one person can break something for everyone, such as a programming environment. If a person's code doesn't compile and this broken code is propogated to the entire team, no one can compile until that code is either removed or fixed. For this reason, many programming teams have a rule against committing before your code compiles.
The rule about not committing until your code compiles works well in some situations, but if a person is doing long-term experimental code, the code might not be in the repository for days. If the sandboxes aren't backed up, that's several days of work at risk. In such cases, I recommend letting the person work on an experimental branch and commit to the branch.
Some teams prefer to restrict updates rather than restrict commits. These teams update stable code into their sandbox and work from that stable code base until they have completed a feature. Then they update from a new stable code base. The risk in this case is that the changes one person has made to the code will conflict with changes from a team member in a way that CVS cannot merge, and someone will have to merge those changes by hand. The benefit is that team members are working against a known code base. This system can be duplicated by using a branch to build the feature on, then merging the branch and the new feature to the trunk. Using the branch also provides a way to commit the partially completed feature without affecting other people's sandboxes, which helps protect against mistakes.