Section 8.2. Source Control: Whys and Hows


8.2. Source Control: Whys and Hows

Consider the following scenario: A customer has called with a problem in the software that your development team released over a month ago. Your developers try to reproduce the problem on their systems without success. What version of software is your team running? Well, there has been a lot of development in the last month, a lot has changed. Some new features have been addedhalfway. In other words, it's close but not really the same software. And it's far from being ready to be given to the customer as a fix-release. Well, what's changed since the release was shipped six weeks ago? Can you find or create a set of sources that matches exactly what the customer is running? Can you then provide a modified version that contains only the fix necessary and no other changes?

With such low prices for hard drives these days it is now economically feasible to track your software releases simply by shelving an entire hard drive with each release of your software. It could contain the source code and all the tools in use for that version. But it does make search and comparisons a bit difficult. Still, conceptually, this is almost what you'd liketo be able to access an image of what your source looked like at any given point in time (for example, when released).

Enter cvsthe Concurrent Versioning System. It's a versioning system, allowing you to retrieve copies of the source based on either date parameters (e.g., last Tuesday) or the labels that you create. It's concurrent because it supports multiple simultaneous users.

You may have used a versioning system before that let multiple programmers work with a set of files. Often such systems will "lock" a file while one user is using it, keeping others from modifying it. CVS doesn't work that wayor doesn't have to. Rather it allows users to each modify the same file (truly concurrent), and then reconciles the changes when those changes are made permanent.

To explain all this, it would be best to set down some terminology, as used by CVS.

repository

The master copy of the source.

sandbox

A developer's local copy of the source.

checkout

The process of acquiring a copy of the source (one or more pieces) from the repository.

commit

The process of adding the changes from your sandbox into the repository.

update

The process of revising your sandbox with changes that have occurred in the repository since you last updated or created your sandbox. When you "update" your sandbox, other developers' changes that have been committed to the repository are merged into your source sandbox.

tag

As a noun, is a special label that you create to mark a milestone in your source repository; you can return to that milestone by checking out a copy of the source with that tag.

tag

As a verb, refers to creating a tag in the source repository.

Once a repository has been set up for use by a project, each developer would check out a copy of the source. Thereafter, the typical sequence for a developer would be:

1.

Edit.

1.

Test.

1.

Commit.

1.

Go to step 1.

In some organizations, developers will commit and then test. Others will want to only commit changes that have been tested. Which order you choose is a policy decision by your project, not mandated by CVS.

Tip

We recommend that you test before committing because once you have committed your changes, they become available to all others developers. The more people are working together on a project, the more important it is to keep the source base workable, that is, clean compiling at least, so others can keep working.


Sometimes the developer needs to do an update step before a commit. Such a step is used to integrate other developers' changes into this developer's source. Sometimes this goes smoothly; other times it needs some additional work.

A simple scenario might help explain these steps, too.

Two developers, Ti and Kwan, are working on project Doh. They already have a repository set up with all the source for project Doh. Each developer, on his/her own system, checks out a copy of the source (cvs checkout doh). Now let's say that part of the source is a Java class file called Account.java and it has had several changes made already, so Account.java is now at version 1.7 in CVS.

Let's say that Ti finds a bug in Account.java and makes a change to fix that problem. Ti checks in (commits) the changes to Account.java (cvs commit Account.java) so that the repository now contains Ti's changes, which CVS keeps as version 1.8 of Account.java.

All this time Kwan has been busy modifying Account.java (e.g., adding a new method). Remember that Kwan is working from the 1.7 version. When Kwan goes to commit his modified version of Account.java to the repository, he is notified that Account.java has been changed since his copy was checked out, and the commit attempt fails. So Kwan does an update which merges the 1.8 version of Account.java in with his modified 1.7 version. If all goes well, the resulting file will be a 1.8 version of Account.java which includes Kwan's new changes in the right place(s). Kwan just commits this to the repository, and Account.java then stands at version 1.9.

Note that cautionary phrase "if all goes well." The merge will work if Ti and Kwan have each modified different parts of the same file. If all Kwan did was add a new method, it would merge just fine. But what if they both make changes in the same region of the source file? It is up to the programmer to resolve such conflicts and commit the source once again.

In such a situation, CVS does what it can to help out. There is an example of a merge conflict later in this chapter. But such conflicts require human intervention.

Merging of conflicts is, undoubtedly, a very manual process, but you will be surprised by how infrequently you need to do this. Most changes will be merged clean with no manual intervention required. That's probably because most often, when two or more programmers are modifying the same file, they are modifying different sections of it.

With merging, you have the ability to incorporate other developer's changes into your version of the source without the fear of losing your changes. No one's changes get lost, no one's files get "stepped on."

8.2.1. Setup

Before you can use CVS to track your sources, you need to initialize a repository. You can use this repository for several different projects, so you only need to do this setup once.

There are two different ways to connect to a repositorydirectly on a filesystem, or indirectly over a network. We will use the simpler filesystem mechanism for this discussion. The network connections are described in the references at the end of this chapter.

In order for CVS to know where the repository is located and how to connect to it, it looks for an environment variable called CVSROOT. You can assign a value to CVSROOT from the command line each time you create a CVS project, or for more convenience, you can set it in the shell startup script (e.g., .bashrc) so that its ready all the time. The CVSROOT value is really only used, though, to set up the project. Once a project is established, the information in CVSROOT is kept, along with other data, in a directory of files (called CVS). From that point on, CVSROOT (the environment variable) no longer needs to be set. The CVS commands will always use what is in the local sandbox to determine where the repository is; the value of the environment variable will be ignored.

It is possible to have different repositories for different projects. One repository might be for your personal workrevisions of memos and documents that you create on your local machine and store in a repository also on your local machine. Another repository might be a shared network-based repository, used for a project at work. Still another might be a network-based project for some Open Source work that you do in your spare time. Since the CVS repository keeps track of whence it comes, you needn't set a value for CVSROOT every time you switch projects. Instead, CVS knows from within the sandbox where to go for its updates, commits, and so on.

So let's get started and create a CVS repository on our local Linux system, in our own home directory. We will call the repository srcbank, as it will be the "bank" where we will deposit our source files.

 $ mkdir ${HOME}/srcbank $ export CVSROOOT="${HOME}/srcbank" $ cvs init 

The mkdir creates the directory named srcbank as a subdirectory of our home directory. The export command sets the shell variable CVSROOT to refer to the location of the new directory. The cvs init command initializes the repository with some needed directories and data files.

Before the cvs init command, the srcbank directory is empty. Afterward it contains a directory called CVSROOT (literal name, not the shell variable's value) which contains a variety of administrative filesmost of which you need never worry about.

If your are using a remote repository, that is, one that you connect to over a network (typical when you are sharing a repository amongst team members), then you need one additional stepyou need to log in to the CVS repository's server:

 $ cvs login 

which will prompt you for a password. Having logged in once, you will not need to log in again, even after reboots of your system, as CVS keeps the password (by default; it can be changed) in a file called .cvspass in your home directory. This makes using CVS with a remote repository (once you've logged in as simple as if the repository were local). From here on, the commands will all look the same. If your repository is remote, CVS will use the password from your .cvspass file, without asking you for it.

8.2.2. Import

Are you wanting to use CVS on an existing project? Have you already got your project at least partly underway? Let's look at how to enter all those files into CVS with a single command.

Not every file that is in a working directory needs to be kept under source control. Some, like .class files, are created from the .java source files. Others may be just scratch files that you don't want to keep versioned.

To automatically exclude certain files from ever being included in your repository, CVS uses a file called .cvsignore that lists filename patterns. Any filename matching a pattern will be ignored by all CVS commands.

Here is a .cvsignore file that we recommend for Java developers:

 *.zip *.class 

This will exclude any file whose name ends in .class or .zip. Note that the comparison is strictly based on a name, not the actual contents. CVS doesn't know what a "class" file is; it is only excluding a file based on its name.

Certain files are not really source files and can't be managed as such, but we would still like to keep versions and a history of changes for them. A good example would be an image file. For example, you may have a corporate logo in a file called logo.jpg and at some point you may get a new or revised version of that file. You can use CVS to track such files, but you need to tell CVS that this is a binary file, so that CVS doesn't try to do some special substitutions that it does on check-in and check-out. (More about those substitutions later.)

For now, let's just consider how to tell CVS which files are binary. We can do that on the command line when we create a new file, but for importing a lot of files at once, and to avoid the need to remember doing that each time we add a file, we can put patterns for binary filenames in a CVS file called .cvswrappers.

Here is a .cvswrappers file that we recommend for Java developers:

 # # A recommended .cvswrappers file # # jar files - treat as binary: *.jar -k 'b' # # Image file formats - treat as binary: *.gif -k 'b' *.jpg -k 'b' *.png -k 'b' *.tif -k 'b' # # Document file formats - treat as binary # both MSOffice and OpenOffice.org file formats: *.doc -k 'b' *.ppt -k 'b' *.xls -k 'b' *.sx? -k 'b' 

The format of the file is very UNIX-like. A leading # means that the rest of the line is a comment. The asterisk matches any number of any characters. The question mark matches a single character.

Now we're ready to import. The .cvsignore file should be placed in the topmost directory of the set of files that you want to import. Then, from that directory, issue the command:

 $ cvs import Project YourCo import 

where Project is whatever name you want to use for this project (or module) in CVS, and YourCo is the name of your company or some other designator to differentiate this source from other third-party packages that you may keep in your repository.

Most importantly, execute the cvs import command from within the directory, even though the name of the project is likely (but doesn't have to be) the same as the name of the directory in which you sit.

For example, consider a fragment of the filesystem shown in Figure 8.1. You would want to cd into the directory coolj and then issue the import command:

Figure 8.1. A sample directory structure prior to import


 $ cd coolj $ cvs import coolj GJSinc import 

This will create a module named coolj in the repository, whose contents are all the directories and subdirectories that you see there. But you had to be in the coolj directory, which may seem counter-intuitive.

Now go to some other directory, one that is not part of the coolj part of the tree, and check out a copy of the source. For example:

 $ cd $ mkdir devsrc $ cd devsrc $ cvs checkout coolj 

Note

It is important to check out the source after you've done the import, and before you make any changes, because the part of the filesystem that you imported remains untouched. It has no CVS knowledge, so you can't commit changes from that directory, unless you somehow make it CVS-aware. Since these files are your originals, until you've verified that the cvs import has gone as planned, it's best not to disturb those files. Create a new directory and check out the module there.


What do you see after the checkout? There should be a single directory, coolj, in the directory where you did the checkout (since it was empty when you started). That directory contains a copy of all the files that you checked in, along with a directory named CVS inside that directory and every subdirectory. The CVS directories contain administrative files that help CVS keep track of things for you, which means no CVS tracking information needs to be kept in your source. You should never need to mess with the files in the CVS directory; see the Cederqvist reference in Section 8.6 for more information about these files.

8.2.3. Normal Use

The typical use of CVS occurs after you've made some changes to your source code. At some point, typically after the code compiles cleanly or after the changes have been tested to some extent, you will want to commit your changes to the CVS repository. When you commit one or more files, they become the latest version, the version that others get when they checkout or update the module. To say it another way, when you commit, you make those changes a permanent part of the source repository, available to others.

You can commit a single file at a time, like this:

 $ cvs commit Account.java 

Or you can commit several files at a time, like this:

 $ cvs commit Account.java User.java Xyz.java 

Or you can commit all the changes from a certain point in the filesystem hierarchy (e.g., the current directory) on down, like this:

 $ cvs commit 

(Specifying no files implies the current directory. You can also name a directory explicitly.)

When you commit changes, CVS wants you to provide a bit of commentary to explain what you've changed, to say something about this new version. The comment can be supplied on the command line, with the -m option:

 $ cvs commit -m "bug fix" 

If you don't provide the -m parameter and its argument, CVS will invoke your favorite editor (as specified in the environment variable CVSEDITOR or VISUAL or else EDITOR, in that order of precedence). The default, on Linux systems, is to invoke vi (see Figure 8.2). In the editor, you can type one or more lines of text; when you exit, the commit will continue to completion.

Figure 8.2. CVS asking for commentary as part of a commit


Note

If you quit the editor without writing your changes (in vi, that would be :q!) then CVS will ask if you want to abort the entire commit. If you choose to abort, no changes will be made to the repository. You'll be right back to where you were just before typing the cvs commit command.


You will be able to see the comments associated with each version of the file using the cvs log command (see Section 8.2.6).

As you will want to provide brief but meaningful descriptions in these comments, it may be helpful to remind yourself what in fact has changed. You can see the differences between the version that you checked out and the file as it stands today by using the cvs diff command:

 $ cvs diff Account.java 

Here, as in commit, you can name one or more files, or even a directory. CVS will display what lines you've added, modified, or removed in each file.

Example 8.1. Sample output from cvs diff
 $ cvs diff Account.java albing@cvs.multitool.net's password: Index: Account.java =================================================================== RCS file: /usr/lib/cvs/cvsroot/JavaAppDevLinux/majorApp/net/multitool/core/ Account.java,v retrieving revision 1.10 diff -r1.10 Account.java 31d30 <       this.parent = null; 66a66 >     * returns an iterator 93c92 <       children.put(acct, name); --- >       children.put(name, acct); $ 

In Example 8.1, CVS has found three differencesone line being removed, one line being added, and one line being changed. The < precedes lines from the repository version, and the > precedes lines from the new, that is, changed, version. The 31d30 shows the line numbers from both versions, separated by a single character to indicate what difference action is being described: a for adding lines, d for deleting lines, and c for lines that change.

A typical work sequence might go something like this:

1.

Edit some files.

2.

cvs diff those files.

3.

cvs commit those files.

4.

Go to 1.

The cvs diff command is also quite useful for finding out what changed between some previous version of a file and the current version:

 $ cvs diff -r 1.15 Account.java 

or between two different previous versions:

 $ cvs diff -r 1.12 -r 1.15 Account.java 

or since a certain date:

 $ cvs diff -D 06-Sep-03 Account.java 

8.2.4. Update

If there are other people working on this project with you, they will also be making changes. To bring there changes into your sandbox, run the cvs update command:

 $ cvs update cvs server: Updating . P Account.java M User.java cvs server: Updating subdir 

Here, P indicates CVS has patched in changes to that source file; and M indicates you have modified the file. Note that Xyz.java is not mentioned. That means there were no updates involved.

The subdirectory subdir was also updated, but no changes were made. Had a change been made, you would see the modified files mentioned by name.

You can update a single file at a time by naming that file on the command line, but typically you want to get the changes for all the files in a directory, or even all the changes throughout the project, since a change in one file may be dependent on changes in other files.

Sometimes when you try to commit your changes you will be told that the commit did not succeed because one or more of your files was not up to date. Not to worry; it's easy to bring your files up to date. This leads directly into our next topic. Read on!

8.2.5. Merges

When you commit changes, a new version of each changed file is now part of the repository. If someone else commits changes, that person's changes are now part of the repository as well. But those changes (unlike your own local changes) are yet to appear in your own local copy of the files, that is your sandbox.

The following CVS command will bring your files up to date with all the changes made since you checked out your copy (or last did an update):

 $ cvs update 

With that command all the files from the current working directory on down will be updated with the most recent versions of the files from the repositoryand not just updated: changes that you have made in your local files will be preserved and merged with the new version of the files.

Here's what a successful merge looks like:

 $ cvs update Account.java cvs server: Updating Account.java M Account.java RCS file: /usr/local/srcbank/JavaAppDevLinux/Account.java,v retrieving revision 1.17 retrieving revision 1.18 Merging differences between 1.17 and 1.18 into Account.java M Account.java $ 

Remember our scenario earlier in the chapter? Our two programmers, Ti and Kwan, have each modified the same file. If all Kwan changed was adding a new method, it would merge just fine. But what if they both made changes in the same region of the source file? Well, the first one to check in his changes will be fine. His commit will succeed. But the second person to try to commit changes to the file will find that CVS will report an error:

 $ cvs commit Account.java cvs server: Up-to-date check failed for `Account.java' cvs [server aborted]: correct above errors first! cvs commit: saving log message in /tmp/cvsQ9rk01 

Now, attempting to update will put both versions in your local file, marked up by certain character strings to highlight and separate the sections. It is up to the programmer to resolve those conflicts and commit the source once again.

Here's an example of how a conflict might look in a source file:

 <<<<< ver. 1.7 for (i=0; i<20; i++) {     myData.callSomething(dollars, time); } ====== while (i<20) {       myData.callOtherwise(dollars*(i++), time/60); } >>>>> 

In such a case, the programmer must decide which changes to keep, or how to combine them. After editing the file and removing the dividing lines (i.e., <<<<<, =====, and >>>>>), recompiling and probably a bit of testing, too, the programmer can now do a cvs commit to incorporate his changes in the repository.

8.2.6. Log

With each cvs commit you are prompted for a comment, to describe the changes that you are committing. What happens to these comments? How can you see them again? Use the cvs log command to show the history of a file's revisions and associated comments.

See Example 8.2 for an example of the cvs output command.

Looking down the output of cvs log, you can see

  • The complete filenamein the repositoryof the file whose log we're checking out.

  • The local filename in your sandbox.

  • Which revision is the "head," that is, the front-most or default revision.

  • Which branch, if any.

  • What kind of locking mechanism CVS uses. There are some choices, but most users of CVS leave this as is.

  • The access limitations. CVS can limit who can modify files (see our reference list if you need to use this).

  • A list of all the tags (symbolic names) for this module and to which revision each refers.

  • What kind of keyword substitution happens. For binary files this would be kb.

  • The count of revisions for this file.

    Then comes a description of each of the revisions, showing

  • The revision number.

  • Some stats on the change including the user ID of the user who committed the change.

  • How many lines were added and deleted compared to the previous revision.

    Example 8.2. An example of running the cvs log command
     $ cvs log Account.java RCS file: /usr/local/srcbank/JavaAppDevLinux/Account.java,v Working file: Account.java head: 1.4 branch: locks: strict access list: symbolic names: keyword substitution: kv total revisions: 4; selected revisions: 4 description: ---------------------------- revision 1.4 date: 2003/05/20 11:59:59; author: albing; state: Exp; lines: +80 -5 more comments added ---------------------------- revision 1.3 date: 2003/05/18 15:03:23; author: albing; state: Exp; lines: +3 -2 end case fixed ---------------------------- revision 1.2 date: 2003/05/17 11:05:40; author: albing; state: Exp; lines: +69 -2 actually runs - unit tested ---------------------------- revision 1.1 date: 2003/05/17 10:15:18; author: albing; state: Exp; a rough structure ======================================================================= 

  • The comment that was entered when the user committed the change.

(For a description of state, and why you will almost always see Exp;, see the Cederqvist reference in Section 8.6.)

Do you want less output from cvs log? You can restrict the information to cover only a certain user's changes (-w), to a certain range of revisions (-r), and/or between certain dates (-d).

For example,

 cvs -walbing -r1.2:1.4 -d05-Sep03 -d28-Sep-03 Account.java 

will list only changes committed by user albing, only in the revision range of 1.2 through 1.4, and only between the dates of 05 and 28 September of 2003.

Note: do not put a space between the -w, -r, or -d and its parameter or CVS will think that the parameter is the name of a source module, and you will see a message like this:

 $ cvs log -r 1.2:1.4 Account.java cvs log: nothing known about 1.2:1.4 ... 

which will be followed by output about the Account.java module that CVS does know about.

For more variations on the logging output, type:

 $ cvs log --help 

8.2.7. cvs status

While the cvs log command will tell you about the history of all revisions of a file, you sometimes need to know the status of the current file in your sandbox: Which revision is it? From where did it come? And, most importantly, is it part of the head or part of a branch?

Those questions can be answered with the cvs status command. Its output will show the revision number of the file in your sandbox and any "sticky" tags. But to understand what that means, we need to talk about tags first.

8.2.8. cvs tag

We began this chapter asking: "Can you find or create a set of sources that matches exactly what your customer is running? Can you then provide a modified version that contains only the fix necessary and no other changes?" Part of the answers to these questions will depend on your use of the cvs tag command. With it, you can set down a label across all your source to mark a particular milestone, so that later you can recall that version of the source. For example,

 $ cvs tag Rel_2_4 

will put a tag (that is, a label) called Rel_2_4 on the head revision of all source files from the directory where this command was executed on down through all its subdirectories. If you run this command from the uppermost directory in your project sandbox, it will label your entire project.

A tag can be applied to a single file or group of files by listing them explicitly on the command line.

Note

Certain special characters are not allowed in CVS tags. Specifically, the characters $,.:;@ are not allowed. So you can't use release_2.4 as a tag. Too bad.


Tags cut across the various revisions of the source. While you can specify that a tag goes on the same revision of all sources (e.g., cvs tag -r 1.3 one_dot_three_tag), the more typical use is to tag different revisions of each module, the revisions that you've just been working with and testing.

Figure 8.3 shows a tag (QA) that cuts across the various revisions of the different sources. With such a tag, someone can check out a copy of the sources to get the QA release:

Figure 8.3. A tag across three files


 $ cvs co -r QA project 

Since your project would likely have more than one time in its life that it would be handed off to QA, some people will put date information in the tag, for example, QA_2003_07_15. Others will use a simple tag, such as QA, but such a tag may need to be reused.

If you've put down a tag and decide that you no longer want that tag (for example, your product is preparing for a new QA cycle and you want to reuse last cycle's tag, or maybe you simply misspelled your tag), you can delete it using the -d option.

Warning

Once you delete a tag, it's gone forever. It is not available even when you recall earlier versions. If you reuse a deleted tag, it doesn't remember any history from its first use.


Imagine your project has just reached a milestone, like the hand-off to QA, so you have tagged your source accordingly. Now the QA group finds a bug and you fix it. What do you do with the tag? The tag will be on the unfixed version of source. One thing that you can do, after you commit your changes, is simply to move the label:

 $ cvs commit Account.java ... $ cvs tag -F QA Account.java 

This will "force" the tag on Account.java to move to the current version.

Such a mechanism works fine for the short term, for quick changes that are put in shortly after the tag has been set down. But what if it takes QA several days to find the bug, and what if, during that time, you've been refactoring Account.java, or adding features for a future release? In those cases, what you really need is a branching tag.

8.2.9. Branching Tags

When you use the -b option with a cvs tag command, then the tag you create is a "branching" tag. That means that you now have two paths in your source repository. You can check out source from, and commit changes to, either of those paths. This allows you to keep moving ahead with new development on the head or tip of the source while providing fixes against a previous version.

Figure 8.4 shows a single source file with a single branch. The tag (QA) may have been applied to multiple files, typically to your entire project. The branched version of each file (for example, 1.3.1.1) is not created until the next change is checked in for that file, so many of the files with the tag may still be on their main source branch.

Figure 8.4. A simple branch and merge


Tip

When do you want to create a branching tag? You can do it at any time that you lay down a tag. We have found it best to do it right away when you "release" your software, that is, whenever you hand it off to another group (e.g., QA or customers). This provides a label (the tag) to identify what exactly was handed off, but also puts the possibility for branching in place for fixes that may be needed on that branch.


Let's look briefly at the steps you would take to lay down a branching tag named QA, and then apply a fix to that branch.

In the directory where you have your current source, which is what you just released, set down the branching tag:

 $ cvs tag -b QA 

Note

You have just set down the branching label on the source but you have not changed your current set of sources. If you make changes in the current directory (and subdirectories) and check those changes in, you will be making those changes to the head, not the branch, of the source.


Example 8.3. Checking out a tagged revision
 $ cd $ mkdir fixes $ cd fixes $ cvs co -r QA myproject cvs checkout: Updating myproject ... U myproject/Account.java U myproject/Caltron.java U myproject/Demo.java U myproject/Employee.java U myproject/Person.java ... $ cd myproject $ cvs status Account.java =================================================================== File: Account.java      Status: Up-to-date    Working revision:    1.2     Sat Oct 26 03:32:17 2002    Repository revision: 1.2     /usr/local/srctree/myproject/Account.java,v    Sticky Tag:          QA (branch: 1.2.2)    Sticky Date:         (none)    Sticky Options:      (none) $ 

Now that you have the label set down, you need to check out a copy of that version of the source. Since we are checking out a new copy, be sure that your CVSROOT environment variable is set appropriately (see above). Then find some new directory to put your source and check out a copy with the tag, as shown in Example 8.3.

We did a cvs status after the checkout to show you the important difference between this version and the other versions. These files will all show a Sticky Tag in their status. This is the label used to check out or update this version of the source. When you check in changes to these source files, the changes will be against that branch, and not the head.

From there on, everything is the same. Make your changes and just check files in as usual. CVS will remember (via the files in the CVS directory) that you're on the branch, so when you check things in, they'll go to the branch.

The important thing is to create the tag as a branch tag so that you can commit changes against that branch. The downside, however, is that you now have two different source versions; bug fixes have to be made in both sources, new features have to be added twice, and so on.

The easiest way to deal with that is to keep your number of active branch tags small; you likely don't want to have to apply a fix to 14 different branches. Also, keep the lifespan of the branches briefwhich is, of course, a relative term.

CVS does provide commands to merge a branch back into the source head. But for this, we will refer you to other CVS material. Our job is to give you an overview and a feel for the possibilities. For this sort of task you will want a complete reference manual.

For more variations on cvs tag, type:

 $ cvs tag --help 

8.2.10. cvs export

If you want to produce a copy of your source tree without the CVS subdirectoriesjust the pure sourceyou can use the cvs export command. Like the inverse of import, it will check out a copy of the source, but will not create any of the CVS subdirectories that allow CVS to manage the commits, checkouts, logging, status, tags, and so on. In other words, the exported directories are not a CVS sandboxthey're just a copy of the files.

Note

Changes made to an exported collection of files cannot be committed back to CVS. Of course you can get the changes back into CVS by creating a sandbox with a cvs checkout command, copying all or some of the exported files into that sandbox, and then committing the changes from there. But it's better to think of export as a one-way street.


8.2.11. A Quick Look behind the Scenes

If you are one of those people who worry excessively about efficiency, let us reassure you that CVS is OK. You could think of a CVS repository as saving each revision of a file (for example, versions 1.1, 1.2, and 1.3), but in fact CVS only keeps a single full version of a filethe latest versionand then stores the deltas, that is, changes required to revert back to the previous versions. So it keeps a full version of 1.3, but then only the differences between 1.3 and 1.2 and the differences between 1.2 and 1.1. This means that it is always very efficient to get the latest version of any file. (Other systems have tried keeping the original and the deltas for each revision going forwardbut that gets very expensive to retrieve versions with hundreds of modifications. With CVS, the latest version is always at hand.)

An exception to this are "binary" files, those on which CVS can't do keyword substitutions. The revisions of those files, such as JPEG image files, won't be stored by deltas, but by complete copies of each revision.



    Java Application Development with Linux
    Java Application Development on Linux
    ISBN: 013143697X
    EAN: 2147483647
    Year: 2004
    Pages: 292

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net