text:
Essential CVS/CVS Administration/Project Management
From WikiContent
The team leader responsible for a project needs to know more about the project's tools than most other developers, or he needs to have a team member who knows about the tools. This chapter is for the team leader and the CVS specialist on the team. It concentrates on the files and directories that make up a project and how they are stored and managed in CVS, rather than on managing the development process itself.
The topics covered include initial creation of a project's CVS files, configuring a project as a module, exporting a project, integrating CVS with build systems and bug trackers, and configuring scripts to run when certain CVS commands are used.
This chapter also covers a special type of branch called a vendor branch, and concludes with a discussion of strategies and practices for using CVS that you may find helpful.
Creating a Project
A project is any group of files and directories that exist beneath one project root directory. Every project must include at least one directory, because CVS needs to be able to create a subdirectory to store metadata about the project.
Most often, a project represents one program, one set of related configuration files, or one web site. Sometimes, a project is a collection of related items. For instance, I store all my articles for http://www.oreillynet.com/ in one project, with each topic grouped under a subdirectory. Sometimes a project is a subsection of something larger.
If you want to create a project right now with default settings and minimal reading, read Section 2.3 in Chapter 2. That section walks you through the process of importing a project.
Preparing a Project
To create a project in CVS, you need to have a copy of the files and directories you want to import, or an idea of which files and directories you want to make. You may modify this copy of the project, so make a copy in a temporary directory to use for importing.
If you have an existing set of files and directories, check whether you have files that can be generated from other files, such as compiled code. Files that can be generated easily do not usually need to be stored in CVS and can be removed from the copy of the project. It is good practice to store the commands that generate these files in CVS as part of the project, usually as a build script or as part of the installation document.
If you have a set of files stored in another version control system and want to save their revision history, see Section 7.1.5 in this chapter. If you don't need to retain their revision history, export the files from the other system using a command that gives you a clean copy of the project with no administrative files, and use that copy to import from.
If you don't have any existing files, you can import a single directory with the project name. If you are more comfortable with a structure to work from, create an initial directory structure for your project and import that.
If you cannot easily fit the task you are trying to accomplish into a single project, you can use the modules feature of CVS to give each development team a smaller section to work from, or you can create several projects and use a module to combine projects into a larger unit when needed. Modules are explained in Section 7.3.3 and Section 7.6.3.
Once you have at least one directory ready to add to the repository, you need to decide how you will add it. There are two methods, which are explained in Section 7.1.2 and Section 7.1.4.
Importing a Project
The cvs import command is used for both creating a new project and updating the vendor branch. Vendor branches are explained in Section 7.1.3 of this chapter.
To create a new project, make your initial directory structure and place in it the initial files for your project, or set out your existing code that is ready for importing, as described in Section 7.1.1. Run the cvs import command from within the root directory of that structure. CVS takes the files and directories from the initial directory structure and copies them into the repository. The syntax for cvs import is:
cvs [cvs-options] import [command-options] project_name vendor_tag release_tag
cvs import requires a log message and calls an editor if it is not invoked with the -m option. You'll then be able to type a message into the editor to record the purpose of the import. See Chapter 2 for more information about the log message.
Check out a sandbox to test whether the import command has worked. If the files are in the sandbox correctly, you can remove or store the original files or directories as you see fit; CVS no longer needs them. cvs import doesn't change the files it imported from, and doesn't convert them into a sandbox.
Example 7-1 shows how to import a project and create an initial project sandbox. The ellipsis indicates where CVS calls the editor so you can enter a log message. Note that I change directories before checking out the test sandbox.
Example III-18. Importing with cvs import
bash-2.05a$ cvs -d cvs:/var/lib/cvs import wizzard wizzard ver_1-0 . . . "/tmp/cvsfaQoRz" 5L, 287C written N wizzard/Makefile N wizzard/README N wizzard/TODO No conflicts created by this import bash-2.05a$ cd ~/cvs bash-2.05a$ cvs -d cvs:/var/lib/cvs checkout wizzard cvs server: Updating wizzard
cvs import saves the data from the files to both the project trunk and to the special branch known as the vendor branch. Unless specified otherwise with -b, the vendor branch is given the ID 1.1.1. The vendor tag parameter is used for the branch tag, and the release tag tags the branch at the current (just-imported) revision. These tags can consist of only alphanumeric characters, hyphens, and underscores.
If you need to import binary files or other files that are not plain text, see the information on binary files in Chapter 3 before adding them to the repository.
The cvs import command honors cvsignore and cvswrappers files and recognizes the standard -k, -I, and -W options (also used by cvs checkout and cvs update) explained in Chapter 3 and Chapter 10. The -d option causes CVS to record the time of import based on a file's last modification time, rather than the current time.
Like cvs update, cvs import reports on the status of files it adds to the repository. These are the output codes for cvs import:
- C file
- The file already exists in the repository and has been modified locally. A conflict must be resolved.
This code is usually seen when a project is reimported (see Section 7.1.3).
- I file
- The file has matched a cvsignore pattern and has been ignored.
- L file
- The file is a symbolic link and has been ignored.
- N file
- The file is new and has been added to the repository.
- U file
- The file already exists in the repository and has not been locally modified. A new revision has been created.
This code is usually seen when a project is reimported (see Section 7.1.3).
Vendor Branches
A vendor branch'is a special type of branch that CVS creates automatically when you cvs import a project. If your project is based on code external to the project itself, such as in-house patches to a vendor's code base, the vendor branch provides a way to merge updates from the external source with your own code.
If you intend to use vendor branches, use cvs import to create your project in CVS, using the vendor's code as the initial directory for the project. Make your changes on the main trunk and run the project normally; the vendor'branch is used only when the vendor releases a new set of code.
When the vendor provides a new release, use the cvs import command to add the new code to the same CVS project with the same vendor'tag and a new release'tag. In effect, this is a special cvs commit to the vendor'branch.
Example 7-2 shows a vendor-branch import to the wizzard project. Note the new release'tag. The project name and vendor'tag remain the same as in Example 7-1.
Example III-19. Importing a vendor branch
bash-2.05a$ cvs -d cvs:/var/lib/cvs import wizzard wizzard ver_2-0 C wizzard/TODOf" 5L, 270C written C wizzard/README C wizzard/Makefile C wizzard/INSTALL . . . C wizzard/doc/design/Specification.rtf C wizzard/doc/design/Requirements.doc C wizzard/doc/design/Design.rtf C wizzard/doc/design/Analysis.rtf C wizzard/doc/design/AcceptanceTest.doc 17 conflicts created by this import. Use the following command to help the merge: cvs -d cvs:/var/lib/cvs checkout -j<prev_rel_tag> -jver_2-0 wizzard
If a file is changed on the vendor'branch and the local file has not changed, CVS sets the trunk revision of the file to the new vendor-branch revision.
If both the vendor-branch copy and the local copy of a file have changes, CVS reports this as a conflict with the message N conflicts created by this import, where Nis the number of conflicts. CVS also provides a suggested variant of cvs checkout to help you resolve all the conflicts, using two -j command options to merge the vendor branch with the trunk.
CVS 1.11.5 tries to provide the exact cvs checkout command you can use to find the differences between the previous release and the current release of the vendor branch and merge those differences to the trunk. If your version doesn't do this, try the following command:
cvs checkout -j previous_release_tag -j current_release_tag projectname
You may also need to include the -d repository_path CVS option if you run this command from outside the sandbox, where CVS can't find the repository path in the sandbox administrative files.
Section 4.3.6 of Chapter 4 explains how the -j option works and how to resolve any conflicts that arise from this type of merge. Tag the vendor branch once these conflicts have been resolved, and use that tag as the previous_release_tag when you next merge changes from a vendor branch.
If the vendor branch contains binary files or files with keywords, use the keyword (-k)'and wrappers (-W) command options to cvs import. Keywords and wrappers are discussed in Chapter 3.
If you have more than one external source for a project, you can use the -b command option to run cvs import on an arbitrary branch number. This creates an additional vendor branch with the specified branch number. Create a separate vendor branch for each separate code source for your project, to help you keep track of which changes came from which vendor.
When selecting a branch to use as a new vendor branch for a new code source, determine that there is no preexisting branch with the number you choose. When updating an existing vendor branch (other than the default branch), use the -b option with the numeric ID of the branch, to specify the target branch for the current import.
Be careful when using -b, as CVS doesn't check whether the branch number corresponds to the vendor tag given in the import command. You can accidentally overwrite one vendor branch with another branch's files.
Alternatives to Importing
If your project does not contain files provided outside the project, it is unlikely you will need to use vendor branches. If this is the case, you can bypass cvs import. To do so, create a new project by adding a new subdirectory to the repository root directory, either by editing the repository directly or by checking out the repository root directory and then using cvs add in that sandbox.
If you do not need the vendor-branch capability of cvs import, the choice between cvs import and the combination of cvs checkout and cvs add is a matter of personal taste. However, I recommend that you use either of those methods — using CVS commands to create a new project — rather than editing the repository directly.
Creating a project with cvs add
To create a project with CVS commands other than cvs import, you need to check out a sandbox that contains only the repository root directory, create the new project root directory, and add that directory with cvs add.
To check out the repository root directory, use a period (.) as the project name. Use the -d name command option to give the sandbox a directory name. To avoid including subdirectories, use the -l command option to cvs checkout.
Example 7-3 shows how to create a project and an initial project sandbox by checking out the repository root directory and using cvs add.
Example III-20. Importing without cvs import
bash-2.05a$ cvs -d cvs:/var/lib/cvs checkout -l -d cvsroot . cvs server: Updating cvsroot bash-2.05a$ cd cvsroot bash-2.05a$ mkdir wizzard bash-2.05a$ cvs add wizzard Directory /var/lib/cvs/wizzard added to the repository bash-2.05a$ cd ~/cvs bash-2.05a$ cvs -d cvs:/var/lib/cvs checkout wizzard cvs server: Updating wizzard
These are the steps for this method:
- Check out the entire top level-directory of the repository, renaming the sandbox root directory with a name such as cvsroot, as shown in Example 7-3.
- Change directory into cvsroot and create the new project root directory. In Example 7-3, the project directory is wizzard.
- If you have existing files or directories to import, copy them into your newly created directory.
- Use cvs add to add the new files and directories to the repository. If you add files as well as directories, you also need to use cvs commit. Example 7-3 shows directory addition only.
As explained in Chapter 3, the cvs add command adds directories immediately, but files are added to the repository only after the next cvs commit.
- Change directories to a working directory and check out the new project to test whether the import worked successfully, as shown in Example 7-3.
- Use cvs release to remove the repository root sandbox you checked out in step 1. Remove any temporary files you created when preparing to import the project.
Creating a project by editing the repository
The second way to create a new project and bypass cvs import is to edit the repository directly. Editing the repository always involves the risk of making a minor typing error and affecting other projects (or your own), so I suggest you back up the repository before editing it.
To create a new project by editing the repository:
- Log in to the repository computer with any user that has write access to the repository root directory.
- Change directory into the repository root directory.
- Use mkdir project_root_name to create the project root directory.
The rest of this process is optional, and is needed only if you have existing files to add to the project:
- Log in to a workstation computer.
- Use cvs -d repository_path checkout project_root_name to check out a sandbox.
- Copy any existing project files and directories into the new sandbox.
- Use cvs add to add the new files and directories to the repository. If you add files as well as directories, you also need to use cvs commit.
Importing from Other Version Control Systems
You might want to import a project, including the project's history, from a different version control system into CVS.
If the other version control system can export files into RCS format, use the following steps to install the RCS files into CVS:
- Ensure that the latest revision in each RCS file isn't locked, the access list is empty, and the file-locking type is set to strict, using the tools available in your version control system if possible.
If your version control system doesn't have tools to do these things and you have RCS installed, you can use rcs -elL filenameto set locking and access appropriately.
If RCS isn't available, you can proceed to steps 2 and 3; then, once the files are in the repository, use cvs admin commands to set locking and access.
- Create the project's directory structure in CVS using cvs import or one of the alternative methods described earlier.
- Copy the RCS files directly into the appropriate directories in the repository.
If the other version control system can't make RCS files, write a script to check out each revision of each file from the other system and commit it into CVS, or create an RCS file with the RCS ci command and use ci to add each revision of the original file to the RCS file. If you create RCS files, you can install them to CVS as described earlier.
The contrib directory in the CVS source contains scripts that convert SCCS and PVCS files to files CVS can use. These scripts can be used as templates for scripts to convert files from other version control systems. Appendix B contains more information about the sccs2rcs and pvcs2rcs scripts.
Distributing Files
All project leads need to distribute completed work at various stages of a project. When working with some projects, such as content management of web sites, you need to distribute files frequently with small changes. With others, such as large programming projects, you need to distribute files less often and with larger changes.
checkout and update
One way to distribute files is to use the cvs checkout command to produce a set of files for distribution. Another way is to use the cvs update command on an existing set of files.
The checkout and update commands are designed to produce a sandbox suitable for editing the files being checked out or updated. The commands create administrative files in the sandbox that most project leads don't want in a public distribution, so you may need to remove the administrative files in the CVS subdirectory from each of the checked-out directories.
There is a benefit to using checkout and update to distribute files. When you use either command on an existing sandbox, CVS sends only the differences between the revisions currently in the sandbox and the revisions requested from the repository. This uses less bandwidth than the export command, which retrieves entire files.
Exporting Files
While cvs checkout creates a sandbox suitable for editing copies of a project's files, cvs export creates a release of the project's files that is suitable for publication. This command uses most of the same internal code as cvs checkout, but cvs export does not create any CVS subdirectories or CVS administrative files.
cvs export requires that you use a date or tag command option. The -D now or -r HEAD options export the latest revisions of all files in a project.
If you don't have any binary files in your project, you can export with -kv to set the keyword-substitution mode to values only, so that the string$keyword: value$ shows in each exported file as value. This can be an advantage when you are publishing a completed release of your project. For example, the string $Revision: 1.5 $ displays as 5.7 and the string $Author: jenn$ displays as jenn. Keywords are commonly used in "About this program" displays.
The syntax for cvs export is:
cvs [cvs-options] export [command-options] project_name
cvs export uses a subset of the options available with cvs checkout. It accepts the -D date, -r revision, and -r tagoptions to specify the revision to be exported. You can also use the -foption, which instructs CVS to use the HEAD revision if the specified revision is not available.
The -l and -R options specify local or recursive operation, and the -k mode option is used to set the keyword-expansion mode. Use the -n option to prevent CVS from running an export program specified in the modules scripting file.
The -d directory option provides a directory name for CVS to export the files to. Otherwise, CVS exports the files and subdirectories to a directory named for the module, or for the project root directory.
If you are exporting only one file from a subdirectory, CVS removes intermediate directories. Use-N with-d to prevent CVS from removing intermediate directories.
Example 7-4 shows an export of the wizzard project.
Example III-21. Using cvs export
bash-2.05a$ cvs -d cvs:/var/lib/cvs export -D now wizzard cvs export: Updating wizzard U wizzard/Changelog U wizzard/INSTALL U wizzard/Makefile U wizzard/README U wizzard/TODO cvs export: Updating wizzard/doc cvs export: Updating wizzard/doc/design U wizzard/doc/design/AcceptanceTest.doc U wizzard/doc/design/Analysis.rtf U wizzard/doc/design/Requirements.doc U wizzard/doc/design/Specification.rtf cvs export: Updating wizzard/doc/plan U wizzard/doc/plan/Schedule.rtf cvs export: Updating wizzard/lib cvs export: Updating wizzard/man cvs export: Updating wizzard/src U wizzard/src/config.h U wizzard/src/handheld.c U wizzard/src/server.c U wizzard/src/wizzard.c
If you are using CVS to manage a web server, FTP site, or other publication system, you may want to ensure that the latest revisions of the project files are in your publication directory. You can do this by automatically exporting the files on a regular basis using cvs export, cvs checkout, or cvs update.
cvs export attempts to write the full revision of each file, and it will not export a file if an existing file of the same name is in the directory it is trying to write to. If you want to overwrite an existing copy of the project or if you want to transmit only changes, cvs checkout or cvs update may be more useful. See Section 7.2.1 of this chapter.
You may need to set up permissions, create symbolic links, or move files after they have been exported. A build tool such as make can be useful for this.
Example 7-5 shows a simple script that exports a project, tests whether the export worked, and then runs an installation script using the make utility. The script in the example could be called from cron or any other Unix or Linux scheduler.
Example III-22. Export cron script
cd /ftp/internal /bin/rm -r wizzard /usr/bin/cvs export -D now wizzard if [ $? -eq 0 ]; then cd wizzard /usr/bin/make install else /bin/cat "Export failed with return code $?" | /usr/bin/mail wizmanager -s \ fi
You can also run a script similar to the one in Example 7-5 to export your project whenever a file has been changed, using the loginfoadministrative file or the -i option in the modules file. These files are explained in the following section.
Running Scripts
In the repository's CVSROOT directory, there are several scripting files that allow you to run scripts while a project is being committed, tagged, updated, or modified in other ways. The scripts called from scripting files are often used to interact with other programs or to enforce standards.
Example 7-6 shows a commitinfo scripting file that runs a layout-testing program called indent-tester on the wizzard project files. CVS calls scripts in commitinfo before files are committed.
Example III-23. Sample commitinfo file
^wizzard/src\(/\|$\) /var/lib/cvs/CVSROOT/indent-tester -gnu
When a project file is committed, CVS searches the commitinfo file for rules that match the project file's path; if CVS finds a rule, it runs the script given in that rule. The rule in Example 7-6 matches all files in the src directory (and its subdirectories) of the wizzard project and tells CVS to run the indent-tester script on those files. Later in this chapter, Example 7-8 shows the indent-testerscript that can be used to enforce indentation standards for a project.
CVS processes the scripting files separately for each directory that is affected by a command, and it calls the script in the scripting file once for each directory it matches. If you run cvs commit wizzard, CVS checks commitinfo for patterns that match wizzard and runs the script once for the files in the wizzard directory, then does the same for each subdirectory, checking for patterns that match wizzard/doc and processing its files, followed by wizzard/lib and wizzard/src.
Working with Scripting Files
The scripting files are all stored in your repository's CVSROOT directory. The purpose of each file is described in the section of this chapter named for that file. Most of these files use a common syntax.
Some files don't use the common syntax. In such cases, the syntax is described in the same section as the file.
The common syntax is rule-based, one line per rule, and each rule consists of a pattern to be matched and an action to be taken. When CVS reads a scripting file, it tries to match the pattern to project files. If the pattern matches, CVS runs the action. The action is usually a pathname to a script and parameters for that script. The common syntax is described in the next section.
To edit any of the scripting files, check out the file with the following command:
cvs -d repository_path checkout CVSROOT/filename
Edit the file with any text editor; then commit the file with cvs commit. CVS stores these files in the CVSROOT directory in plain-text and RCS formats and updates both types of files every time a file is committed.
You can also store the scripts you call from these files in your repository's CVSROOT directory or a subdirectory of CVSROOT. Add such scripts to the checkoutlist file in CVSROOT, so they are automatically exported to the CVSROOT directory when they're committed. The checkoutlist file is described in Chapter 6.
It is tempting to store scripts called by the scripting files in the project or module they are called for. Resist this temptation, as CVS then tries to call such a script when the script is itself being committed. Also be aware that if you store scripts in a project or module, they'll be stored on the repository machine in RCS format only; scripts can't be run from that format.
Do not attempt to interact with the user from scripts called from the scripting files. Some remote-access methods do not support such interaction at all, and other methods can be affected by having unexpected data go through their socket. Users other than the one involved in the interaction may also be left waiting on the first user until the interaction is complete.
If any script contains a CVS command, be aware that the command that calls the script will not finish until the script does. You may find that some directories have been locked by the original command, which can't finish and release them until the script is finished, but the script can't finish because the second command can't run until those same locks are released. This situation can be prevented by having your script call any CVS commands in the background or by simply calling the script in the background.
Scripts called from all files except the modules file are run on the computer that hosts the repository. Two of the modules scripts run on the sandbox computer; the others run on the repository computer.
If you do not provide a full path for a script, CVS searches the user's PATH environment variable. To prevent the wrong script from being called, I recommend using the full path in all scripting files.
Your repository administrator may limit your access to the scripting files for security reasons. Work with the repository administrator; you are asking for permission to run arbitrary scripts, so try to address her concerns.
Common Syntax
Most of the scripting files'in CVSROOT --including commitinfo, loginfo, editinfo, rcsinfo, and verifymsg — share a common syntax. The modules file does not use the common syntax.
Each line of a file using the common syntax should contain the following items:
name_pattern action
name_pattern should match a directory in the repository, and this pattern applies to all files in that directory. The pattern used is a regular expression, described in Chapter 11. The directory path that is tested against the pattern is the relative path, starting at the repository root directory.
action is a command-line template or the address of a script, plus any parameters required for that script or template. For most files, the script or the command must expect to read from the standard input (stdin). When CVS runs actions from some of the scripting files, it appends parameters to all actions run from those files. These parameters are often a list of the paths to the project files and metadata for copies of the project files that CVS has matched the rule to.
Lines in scripting files that start with the hash symbol (# ) are comments, which CVS ignores.
When CVS processes a scripting file, it searches the scripting file from top to bottom and runs the action on the first line with a directory name pattern that matches the directory that contains the project file it is trying to match. CVS runs the script on the first matching rule and ignores other rules that match. In addition, if there are any ALL rules, CVS runs the scripts associated with them.
There are two special patterns, ALL and DEFAULT. A script designated with the ALL pattern is used on files in any directory, even if another line anywhere in the file matches the directory pattern. A script designated with the DEFAULT pattern is used if no other patterns (excluding ALL) match.
The actions in scripting files can use any of the variables CVS recognizes and expands. Chapter 6 explains variable expansion in administrative and scripting files.
The modules File
The modules file is used to define CVS modules. While a project is defined by the project root directory and contains all files and subdirectories, a module can be an arbitrary set of directories and files. Once a module is defined, the files and directories it describes can be checked out into a sandbox by either the module name or the name of the repository directory (or directories) it represents.
The modules file can also specify scripts to run when CVS acts on a file within a module.
Each module definition needs to be on a line of its own. When adding directories to module definitions, use relative paths from the repository root directory.
Example 7-7 shows a modules file. The lines in the file are explained in the following sections on module definition.
Example III-24. CVSROOT/modules
# wizzard project. Project lead: jenn. Module type: regular. wiz -s development wizzard # singer project. Project lead: doppel. Module type: alias. singer -a music/descant !chorus/tenor !chorus/bass chorus # wizsinger project. Project lead: doppel. Module type: regular wizsinger -i /var/lib/cvs/CVSROOT/export &wiz &singer #wizmake project: retrieves just the Makefile from wizzard. wizmake wizzard Makefile # wizhandheld project: retrieves just the handheld.c file. wiztest wizzard/src handheld.c
Alias modules
An alias module can be used to group files and directories into a single module, regardless of where they are stored in the repository tree. The syntax for an alias module definition is:
module-name -a path [path...]
The path may be an existing module, a pathname to a file, or a directory path, and there may be any number of paths. If the path leads to a directory, the directory and all subdirectories and files are included in the module.
If you wish to exclude a subdirectory in an alias module, use an exclamation mark (!) in front of the directory name.
Alias modules cannot have options, nor can you specify scripts to run for them. If you need to use options or scripts, you can define an alias module as part of a regular module, or you can simply use a regular module instead.
Alias modules are easier to use than regular modules(described in the next section). You define alias modules with a space-separated list of all the items you want in the module, while regular modules have a more complicated syntax. You can also add multiple directories, files, and modules in an alias module; a regular module allows only one directory.
The singer project in Example 7-7 defines an alias module that includes all files and directories in the chorus directory, except those under the subdirectories tenor and bass. This project also includes the descant file from the music directory.
When you use an alias module's name in any CVS command, CVS treats the module name as if the list of items in the path were used instead. When you use an alias module in the checkout command, CVS creates a separate sandbox for each item in the path.
Regular modules
A regular module is used to define options for a project. It can also be used to define subsets of a project or to group modules together. If you have a particularly complex project, you may need to define your project with a combination of alias and regular modules.
Using alias modules in a complex definition allows you to add multiple directories with one alias, and the regular module allows you to define options to use when calling that module.
The syntax to define a regular module is:
module-name [options] [directory [filename|subdir...]] [&module...]
The directory should be a path relative to the repository root directory. If filenames or subdirectory names are included, they should refer to files or subdirectories in the directory. The module definition then applies only to those files or subdirectories. Note that you need a space between the directory and the files within the directory, and you can define only one directory within a regular module.
You can include an existing module in a regular module by prefixing the existing module name with an ampersand (&) and listing it in the regular module definition. The existing module can be an alias or a regular module. If it is not defined in the modules file, it must be a directory path relative to the repository's root directory. This rule is illustrated in the wizsinger module definition in Example 7-7, which includes two existing modules. The sequence of the module definitions doesn't matter; you can include a module in an earlier line than the module's own definition.
Module options and scripts
Most of the options for a regular module define scripts to run immediately after a CVS command on the files in the module. Here is the full list of options:
- -d directory_name
- Use directory_name rather than the module name as the name of the sandbox root directory.
- -e script
- Run the specified script whenever the module is exported. This script is given the module name as an argument.
- -i script
- Run the specified script whenever the module is committed. This script is given the full pathname of the relevant repository directory as an argument.
This option may be removed in CVS 1.11.6 and later, for security reasons.
- -o script
- Run the specified script whenever the module is checked out. This script is given the module name as an argument.
- -s status
- Provide a status for the module. This has no meaning internal to CVS, but when the command cvs checkout -s runs, the display output is sorted in ascending order by status. You can use the status string for anything; examples include the name of the person responsible for the module or whether the module is in active development.
CVS allocates an 11-character space for the status string when it is displayed, but the string is not truncated if it is longer than 11 characters.
- -t script
- Run the specified script whenever rtag is used on the module. This script does not run when tag is used. The taginfo file is a better way to run a script when files are tagged. This script is given two arguments: the module name and the name of the tag.
- -u script
- Run the specified script whenever the module is updated. This script is given the full pathname of the affected repository directory as an argument.
This option may be removed in CVS 1.11.6 and later, for security reasons.
The scripts designated in the modules file run after their respective processes have been completed.
If the repository is not on the same computer as the client, CVS stores the scripts for the -i and -uoptions in the Checkin.prog and Update.prog files in the CVS subdirectories in the sandbox. These scripts will run on the client computer. All other scripts called from the modules file run on the repository server computer.
The behavior of Checkin.prog and Update.prog will change in CVS 1.11.6 for security reasons. Check the documentation with your version of CVS for details.
The sandbox copies of the Checkin.prog and Update.prog files are not changed when the modules file or the repository computer's copies of the scripts are changed. If you change a module definition or the commit or update scripts for your project, you will need to have your users release and recreate their sandboxes.
The commitinfo File
The commitinfo file is processed before a file is committed and is usually used to enforce project standards for file format or content. It runs very early in the commit, during the tests to determine which files have changed.
commitinfo uses the syntax described in the Section 7.3.2 earlier in this chapter, with one rule per line and each rule consisting of the following elements:
name_pattern action
If a name_pattern matches the name and path of the directory or module parameter to cvs commit, CVS calls the action and appends as parameters the full path of the repository and the filenames of all files to be committed.
If you run cvs commit from a sandbox directory without specifying a project, CVS tries to match the repository path that corresponds to your current sandbox directory with a rule in commitinfo. If you run cvs commit with a file or directory parameter, CVS tries to match the repository path that corresponds to that parameter.
CVS makes a set of normal-format files from the data it receives from the CVS client and stores them in a temporary directory to allow the action to read a normal file rather than an RCS file. If CVS is running in client/server mode, the script or command in the action runs on the repository computer in a directory that is a copy of the sandbox directory being committed. If this script returns a nonzero value, the commit does not proceed. The script cannot change the file that is being checked; so, while you can use a layout-testing program, you cannot successfully use one that modifies the layout.
Example 7-8 shows an indentation tester that can be used with the commitinfo file in Example 7-6. Note that this tester assumes that all files it is called for can be tested validly with indent.
Example III-25. Indentation tester
INDENTOPTS=$1 shift while test "$1" != "" do FILENAME=$1 TMPFILE="$TMP/id.$$" cat $FILENAME | indent $INDENTOPTS > $TMPFILE diff $FILENAME $TMPFILE 2>/dev/null >/dev/null if [ $? -ne 0 ]; then return 1 shift done return 0
The loginfo File
The loginfo file is processed after files have been committed to the repository. loginfo uses the syntax described in Section 7.3.2 of this chapter, with one rule per line and each rule consisting of the following elements:
name_pattern action
If a name_pattern matches the name and path of the directory parameter to cvs commit, CVS calls the action and passes it the log message from the commit on the standard input. CVS also passes the repository path being committed to, followed by an expanded format string. The action can consist of a script, a shell command, or a group of shell commands that will run as one command. If the repository is not on the same computer as the client, the script or command in the action runs on the repository computer.
The format string is stored in the loginfo file, and it controls the information that CVS passes to the script or command. The string consists of a % , followed by a space, a single variable, or a set of variables enclosed in braces ({ }). These are the variables:
- s
- Expands to the name of the current file being processed.
- Expands to the file's revision number prior to the commit.
- v
- Expands to the file's revision number after the commit.
When CVS process the format string, the output is in the form:
"variable_expansion [variable_expansion...]"
The output includes a variable expansion for each file that was committed. The variable expansion is a comma-separated set of strings, such that %{sV} could be expanded to a string like main.c,1.3. Dollar signs ($), backticks (`), backslashes (\),'and quotation marks (") in the repository path or filename are escaped with backslashes.
If you run cvs commit from a sandbox directory, CVS tries to match the repository path that corresponds to your current sandbox directory with a rule in loginfo. If you run cvs commit with a file or directory parameter, CVS tries to match the repository path that corresponds to that parameter.
The loginfo file is usually used to control where (aside from the repository) the log information from cvs commit is sent. It can also be used to trigger actions, such as notifying all developers of changes, maintaining a file that logs a record of changes, or exporting the changed files to a file server.
Example 7-9 shows a loginfo file that emails the log message for every change to the user cvsadmin. This file also runs the changelog script that is stored in CVSROOT for every file that is committed to the wizzard project. The line for theteppic project demonstrates a way to call an export script in the background.
Example III-26. A loginfo file
^wizzard\(/\|$\) /var/lib/cvs/CVSROOT/changelog %{sv} ^teppic\(/\|$\) /var/lib/cvs/CVSROOT/export & ALL mail -s "CVS commit" cvsadmin
The rcsinfo File
The rcsinfo file is processed before a file is committed. It uses the syntax described in Section 7.3.2 of this chapter. The action in each rule of an rcsinfo file should not be a path to a script; it should be a path to a template file that will be displayed when CVS asks the user for a log message during a cvs commitoperation.
If you run cvs commit from a sandbox directory, CVS tries to match the repository path that corresponds to your current sandbox directory with a rule in rcsinfo. If you run cvs commit with a file, directory, or module parameter, CVS tries to match the repository path that corresponds to that parameter. The DEFAULT and ALL rules described in Section 7.3.2 are honored.
If CVS finds a match, it displays the contents of the template file when it opens an editor to receive a log message. If there is a matching rule and an ALL rule in rcsinfo, CVS displays the contents of the file each rule refers to (that is, it displays the contents of two files). Subject to any editing you do when you commit, the contents of the template file (or files) are stored as part of the log message.
If you use -m message or -f file as options to cvs commit, the rcsinfo file is ignored.
If CVS is running in client/server mode, it stores a copy of the template file in the Template file in the CVS subdirectory of the sandbox when the sandbox is checked out. This file is not updated with other sandbox files, so if the rcsinfo file or the templates it refers to are changed, your users should release and recreate their sandboxes.
The taginfo File
The taginfo file is processed before a file is tagged using either the tag or the rtag commands. taginfo uses the syntax described in Section 7.3.2 of this chapter, with one rule per line and each rule consisting of the following elements:
name_pattern action
If a name_pattern matches the name and path of the directory or module parameter to cvs tag or cvs rtag, CVS calls the script or command in the action and appends a parameter string. The parameter string has the following format:
tagname operation repository_path file_revision_pair [file_revision_pair...]
The parameters are provided to enable the script you specify in the action to check that the tag name meets standards, interact with other programs, or log tag operations.
The file_revision_pair is a space-separated pair of filename and revision number, and there is a pair for each file to be tagged.
The operations CVS provides are add, mov, and del. The mov operation is provided when tag or rtag is called with the tag-moving option -F, and del is provided when tag or rtag are called with the tag-deletion option -d. The add operation is provided when a new tag is added.
If CVS is running in client/server mode, the script given in the action runs on the repository computer. If the script exits with a nonzero exit status, the tag or rtag operation does not proceed.
The taginfo file is often used to enforce tag-name standards in a project. Example 7-10 shows the first part of a parser that returns1 if a tag name doesn't fit the project's standards and 0 if it does.
Example III-27. Parsing tag names
$TAGNAME=$ARGV[0]; $OPERATION=$ARGV[1]; $REP_PATH=$ARGV[2]; %FILE_REV=splice(@ARGV,3); @tagfields=split('-',$TAGNAME) if (!is_in(('prealpha','alpha','beta','stable'),$tagfields[1])) { return 1; } . . . return 0;.
The verifymsg File
The verifymsg file is processed before a file is committed and after you enter the cvs commit log message, either in the editor that CVS opens or by using the -m message or -F fileoptions to cvs commit.
verifymsg uses the syntax described in Section 7.3.2 of this chapter, with one rule per line and each rule consisting of the following elements:
name_pattern action
If a name_pattern matches the name and path of the directory or module parameter to cvs commit, CVS calls the action and passes it the path to a temporary file containing the cvs commitlog message, and a copy of the log message on standard input (stdin). If the repository is not on the same computer as the client, the script given in the action runs on the repository computer. If the script returns a nonzero value, the commit does not proceed.
The verifymsg file is usually used to enforce project standards for commit log messages, and the script often either checks or modifies the log message you enter when you commit files
The script can modify the log message, and the RereadLogAfterVerify option in the config file in the repository's CVSROOT directory determines whether the original or the modified log message is used. (If the log message is reread, CVS reads it from the temporary file.) See Chapter 6 for information on the config file.
The ALL keyword is not supported for use in the verifymsg file.
Interfacing with External Programs
CVS is rarely used alone. There are a number of project-management tools available, each used to perform a different set of tasks. The scripting files can be used to connect CVS to other project-management tools, such as bug trackers and build scripts.
Interfacing with Bug Trackers
Interfacing with a bug tracker is easiest if the tracker accepts input from standard input or via an email form. Use the rcsinfo file to have the cvs commit editor screen include the template your bug tracker requires, and use the verifymsg file to ensure that all fields are filled in appropriately. Then have a script in verifymsg or loginfo mail the log data to your bug tracker.
Example 7-11 and Example 7-12 show how to integrate with the Bugzilla bug-tracking tool, available at http://bugzilla.mozilla.org/. These examples assume that the Bugzilla email gateway has been enabled. The @resolution field in the message template allows you to change a project's status and is supported directly by Bugzilla.
Use the verifymsg script in Example 7-11 to separate out the bug ID so it can be used in the mail subject (which must have the format [Bug XXXX]). The rest of the log message can be sent as the mail body. The script uses the read command to get the bug ID from the first line of the log message, checks that the first line it reads uses the format it expects, and then mails the bug ID and the rest of the stdin input to the user bugzilla on the same computer. The script returns 1 if the format was wrong and 0 if it succeeds in mailing everything to Bugzilla.
Example III-28. Interfacing with Bugzilla, verifymsg
#! /bin/bash read prompt bugid if [ $prompt != '@bugid' ]; then return 1 else mail -s "[Bug $bugid]" bugzilla fi return 0
Example 7-12 shows an rcsinfo template file that contains the @bugid string that Example 7-11 expects and the @resolution and @message strings that Bugzilla supports. You should enter the bug ID, resolution status, and a log message to the right of each of these prompts.
Example III-29. Interfacing with Bugzilla, message template
@bugid @resolution @message
A more complete verifymsg script than the one shown in Example 7-11 would include a facility to strip comments out of the template file, and the template file would have comments explaining what to write beside each prompt. (CVS strips lines that start with the string CVS:, so you can use that mechanism instead of your own comment-stripping code.)
Example 7-13 shows the lines in the verifymsg and rcsinfo files that would call these scripts for the wizzard project, if the scripts were called bugzilla-mail and bugzilla-template.
Example III-30. Interfacing with Bugzilla, scripting files
# In verifymsg, call the script bugzilla-mail ^wizzard\(/\|$\) /var/lib/cvsroot/CVSROOT/scripts/bugzilla-mail # In rcsinfo, call bugzilla-template ^wizzard\(/\|$\) /var/lib/cvsroot/CVSROOT/scripts/bugzilla-template
Interfacing with Build Scripts
A build for publication should be slightly different from a build for development. During development, your developers want to start with a recent sandbox, build from that sandbox, make their changes, and then test only those changes. However, a build for testing or publication should be taken from a known set of revisions, frequently the most up-to-date revisions.
Fortunately, both building for incremental testing and building for a major release can be done using the same build script. If the script is included in the project files and designed to be able to be run from a sandbox, the developers can run their test builds from their sandboxes and the project lead can run testing or publication builds from an exported copy of the project files. Note that it's good practice to tag the project's files just before a testing or publication build, so that the exact revisions can be easily retrieved later.
If your developers are sharing a central set of files and have only a partial set of the project's files in their sandboxes, you can have the build script set up symbolic links to the shared files from their sandboxes or call files from a central location.
If your developers are changing copies of a set of files but will eventually want to distribute your project's files across several unrelated directories, it is best to develop the project to build under a single root directory, then distribute the files across multiple directories as part of the installation script.
Example 7-14 is a script for the wizzard project that tags the head revisions of all files, then builds and installs the project (assuming the Makefile is properly configured). To create a build of this script for development, produce a smaller script that contains only the make and make install commands and run the miniscript from a developer's sandbox. To create a build of the project for testing or publication, run the full script given in Example 7-14 from any directory.
Example III-31. Building for testing or publication
/usr/bin/cvs -d cvs:/var/lib/cvs rtag -r HEAD $1 wizzard if [ $? -eq 0 ]; then cd /tmp /usr/bin/cvs -d cvs:/var/lib/cvs export -r $1 wizzard if [ $? -eq 0 ]; then cd wizzard /usr/bin/make /usr/bin/make install else echo "Export failed." fi else echo "Tag failed." fi
Enforcing Standards
The different scripting files can be used in the following ways to enforce project standards:
- commitinfo
- Can be used to run a program through a layout checker, run a system configuration file through a syntax checker, or run a documentation file through a spelling and grammar checker. If the checker returns a nonzero exit status, the file is not committed and the commit fails for all files in that commit.
- verifymsg
- Can be used to ensure that log messages meet the project's standards and contain the correct fields. This file can also be used to generate fields and include them in the log message.
- taginfo
- Can be used to enforce a standard format for tag names.
Project administrators should be aware of the CVS commands described in Chapter 3 and Chapter 5. You may also want to read Chapter 4 and Chapter 6.
In addition to the commands described in those chapters, there are two commands that are particularly useful to project administrators: cvs admin and cvs history. cvs admin allows you to use RCS-like commands on files stored in the repository. cvs history provides a record of the actions performed on a project's files and is similar to cvs log or cvs annotate.
The cvs admin Command
The cvs admin command is used to edit the RCS files directly in the repository. It is more accurately thought of as a set of commands than a single command, as it provides many of the commands that RCS would make available, though not all of these commands are usable or have an effect that matters to CVS. These commands are present mostly for historic reasons and backward compatibility with early versions of CVS.
If there is a system group called cvsadmin on the repository server, only users in that group can use the cvs admin command. If this group does not exist, any user can use the cvs admin commands on any repository files they have permission to change. Consider using the cvsadmin system group, as some of the cvs admin commands can prevent CVS from using the affected file or files.
There is a new option in the config file of CVS 1.12.1 and later. The UserAdminCommands option allows the system administrator to set cvs admin options that users who are not in the cvsadmin group can run.
The syntax for cvs admin is as follows:
cvs [cvs-options] admin command-options [filename...]
I strongly recommend always stating the filenames you wish cvs admin to act on, as some of the cvs admin commands can be difficult or impossible to recover from if you accidentally use them on the wrong file. If you do not specify a filename, cvs admin operates on all files in the current sandbox directory and moves recursively down its subdirectories.
Each of the RCS commands that cvs admin provides is represented by a command option to cvs admin. RCS commands that are obsolete or meaningless when used with CVS are not listed in this chapter. For many of the commands, there can be no space between an option and its argument. See Chapter 10 for the full list of cvs admin command options.
The most commonly used cvs admin option is the -k option, which sets the default keyword-substitution mode for a file. This option is explained in the Section 3.11 of Chapter 3. If you forget to set the -kb keyword-substitution mode of a binary file when you add it to the repository, you can use cvs admin -kb filename to correct the mistake.
If you use the rcslock script to reserve development of files, as described in Chapter 5, you use cvs admin -l filename and cvs admin -u filename to lock and unlock the file you are reserving.
The -o option is used in one of the methods of moving files, as described in Chapter 6. This option allows you to remove old revisions of a file, effectively collapsing the changes from those revisions into a single revision. It cannot be reversed once it is done, so be very careful and test it on a copy of the repository first. The full syntax of the -ooption is provided in Chapter 10.
The -m option allows you to replace a log message. The -s option is used to set the state of a file. The state is shown in cvs log output and in the results of the Logkeyword. The -toption is used to set a description of the file, which is also shown in cvs log output.
The -U option to cvs admin sets file locking to nonstrict, which prevents CVS from working with a file effectively. The-L option repairs this problem by setting the file locking to strict. The -U and -L options should not be used, but if someone accidentally uses -U while trying to use -u, you now know you can use -L to repair the damage.
The cvs history Command
The cvs history command reports on the history of actions performed on the files in a repository. This command is a variation of the cvs log command explained in Chapter 5. The cvs log command displays only commit actions; cvs history can display most types of actions.
The history file
cvs history uses the history file in a repository's CVSROOT directory as a database and displays only events that have occurred while the file is present and writable. The cvs init command creates the history file by default. Note that CVS will not report an error if the history file is removed.
The history file must be writable by all users. Since it never causes a script to be executed, this is not a security issue. The actions that are logged to the history file are controlled by the LogHistory setting in the configfile in the repository's CVSROOT directory.
cvs history output
The format of the output of the cvs history command varies, depending on the options chosen. The basic format of each line of the history output is:
type date timezone user {revision|path|branch} {module|directory|tag|filename} [module|project-root-directory] access_type
The type is a single letter, representing one of the types given in the list at the end of this section. The timezone is +0000 (i.e., UTC) if not specified otherwise. The access type is remote or local; if it is local, it shows the directory the sandbox was in when the command recorded in the history file was run.
Example 7-15 shows an example of most of the output types for cvs history. Whitespace has been removed to prevent the output from wrapping.
Example III-32. cvs history command output
bash-2.05a$ cvs history -e -zUTC O 2002-08-22 05:42 UTC jenn wizzard =wizzard= <remote>/* O 2002-10-03 08:38 UTC jenn wizzard =wizmake= /tmp/* O 2002-10-03 08:38 UTC jenn wizzard/src =wiztest= /tmp/* M 2002-08-22 08:00 UTC jenn 1.8 1-introduction.sxw cvsbook = = <remote> A 2002-08-29 12:17 UTC jenn 1.1 Z-copiesto cvsbook = = <remote> W 2002-09-12 04:36 UTC jenn wizzard.h wizzard/src = = <remote>/src C 2002-09-12 05:32 UTC jenn 1.2 main.c wizzard/src = = <remote> G 2002-09-12 05:32 UTC jenn 1.4 wizzard.h wizzard/src = = <remote> R 2002-09-12 06:07 UTC jenn 1.3 main.c wizzard/src = = <remote> T 2002-09-13 04:04 UTC jenn wizzard [pre_alpha_0-2:HEAD] T 2002-09-13 04:04 UTC jenn wizzard [pre_alpha_0-2:2002.09.13.04.04.22] T 2002-09-13 07:12 UTC jenn wizzard [beta_0-1_branch:beta_0-1_branch_root] E 2002-10-01 07:00 UTC jenn [2002.10.01] wizzard =wizzard= <remote>/* F 2002-10-02 17:48 UTC jenn =wizzard= <remote>/*
Using the cvs history command
The syntax for the cvs history command is
cvs [cvs-options] history [command-options] [filenames...]
The options to cvs history modify how much of the history is shown for which users and modules. The -T, -c, and -o options display the records for tags, commits, and checkouts, respectively. The -e option displays all record types. The -z timezoneoption converts times and displays them in the specified time zone.
CVS does not allow you to combine the -T, -c, -o, -x, and -e options. If you wish to display multiple action types, use the -x option with a type letter.
The types shown in the history output are designated by letters, which can also be used with the-x option to specify the types of events you wish to display. Multiple types can be specified. These are the types:
- Report on records of files added to the repository (a committed add).
- Report on records showing files that would have been updated in a sandbox, but that needed to be merged and for which there were conflicts in the merge (compare with G and U).
- Report on records of files being exported.
- Report on records of files being released.
- Report on records of a file being updated in a sandbox with a successful merge (compare withC and U).
- Report on records of a file being modified (a successful commit of a sandbox revision).
- Report on records of files being checked out.
- Report on records of files being removed from the active part of the repository (a committed remove).
- Report on records of files being tagged or rtagged.
- Report on records of a file being updated in a sandbox with no merge required (compare with C and G).
- Report on records of a file being deleted from a sandbox during an update because it is no longer active in the repository.
The full list of command options for cvs history is provided in Chapter 10.
Strategies and Practices
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.
Tag and Branch Strategies
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 Strategies
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.
Project Structure and Sandboxes
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.
Practices for Development
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.


text:
Only a few years ago, Diana Rambo learned a distant relative had served on the USS Monitor, the warship that elementary school lessons had taught her played a pivotal role in the Civil War.
Soon, the Fresno, Calif., resident was consuming family stories of ironclad ships battling 150 year ago. And on Friday, she witnessed the Navy's commitment to bringing its fallen home as it buried the remains of two unidentified sailors from that ship.
"It's just such a tremendous piece of history," Rambo said. "How proud it makes us of our country. The ceremony, the ritual, the fact that the Navy would do this."
Rambo and about 15 members of her extended family were among about 100 descendants of Monitor crewmen who gathered Friday afternoon at Arlington National Cemetery. After a chapel ceremony, the Navy lay to rest two of the 16 sailors who died when the craft sank in a storm off the coast of North Carolina in 1862.
They are likely the last Civil War sailors who will ever be buried, Secretary of the Navy Ray Mabus said in a statement.
At the burial Friday, hundreds of people watched a military band and honor guard procession, followed by the two flag-draped caskets pulled on horse-drawn carts. With careful, measured steps, Navy sailors carried each casket and lowered it to the ground, then held the flags taught as a prayer was read. A lone bugle sounded off a slow, haunting Taps, and the sailors folded their flags.
Amid the crowd, several women in long hoop skirts and shawls strode arm in arm with tophatted men, all National Park Service volunteers from the Arlington House – the former home of Confederate Gen. Robert E. Lee that overlooks the cemetery – hoping to lend a sense of gravity to the long overdue burial.
In an unprecedented clash 151 years ago Saturday, the Union's Monitor and the Confederacy's Merrimac became the first ironclad ships to grapple at sea, battling to a draw off the coast of Virginia.
About 10 months after the battle, Rambo's ancestor – a crewman named Jacob Nicklis – was worried about the ship, she said. Nicklis had re-enlisted so he could be with his "mates," Rambo said; letters home hinted at the worsening conditions onboard the Monitor.
"He said something about, 'I hope it'll make it, I hope it'll stand up,'" Rambo said. "There was some fear, and I'm just thinking now about the people who are in the line of fire and what they go through to serve our country."
Navy researchers found the skeletal remains of two sailors when they lifted the 150-year-old turret from the sea in 2002; the Navy is still working to conclusively identify both sailors' remains. There's been no trace of the 14 other men who died on the Monitor.
Andrew Bryan of Holden, Maine, said he stumbled on the history of his ancestor while researching his family's Scottish roots. His great-great-great uncle, William Bryan, a first class fireman on the ship, moved to the United States after serving in the British navy at age 12, said another relative, James Bryan of Chapel Hill, N.C.
Months of research uncovered another twist, Andrew Bryan said. Before William Bryan died on the Monitor, the war already had splintered his family, as his brother fought and eventually died for the South.
Andrew Bryan added that he's been thankful for the Navy's continued commitment to bringing closure to the stories of those who served and died for their country.
"Even though it's 150 years later, it's not just old bones. It's people," he said. "If it's not him, I'm OK with that. He'd been on the sea for 17 years and maybe that's where he wanted to be."

subset: commoncrawl


text:
The indie game Papers, Please may come to Vita. Creator Lucas Pope says he'd like to put the game on Sony's handheld, but isn't sure whether he should field it directly or pass it off to someone else to port.
"A lot of people offered to just, 'send me over the assets and codes and I'll kick out all your localised versions, you'll be set', but I wanted to do it myself because it was a little bit fun and because I'm a control freak," Pope told VG247. "For a Vita version, I'm 50 percent I want to do it myself and 50 percent I should just hand it off to somebody who knows what they're doing and can take it over for me."
He did note that the Vita version would come with its own special considerations, and as a developer he'd prefer to solve them personally. "I do want to do a Vita version, but the thing is there's a lot of kind of interesting UI challenges to make it work well on Vita: much smaller screen, much smaller hit targets. So that kind of stuff interests me to try to figure out how to make it work well on Vita."
He also said he'd like to make a "quick, short free game" on PC before going back to developing an iPad version of Papers, Please.
Papers, Please was a critical success with generally positive reviews. It tasks the player with screening immigrant passports in a dangerous and oppressive regime.


text: mid-15c., from Middle French lascivieux or directly from Late Latin lasciviosus (used in a scolding sense by Isidore and other early Church writers), from Latin lascivia "lewdness, playfulness, frolicsomeness, jolity," from lascivus "lewd, playful, frolicsome, wanton," from PIE *las-ko-, from *las- "to be eager, wanton, or unruly" (cf. Sanskrit -lasati "yearns," lasati "plays, frolics," Hittite ilaliya- "to desire, covet," Greek laste "harlot," Old Church Slavonic laska "flattery," Slovak laska "love," Old Irish lainn "greedy," Gothic lustus, Old English lust "lust"). Related: Lasciviously; lasciviousness. In 17c. also with a verbal form, lasciviate.


text:
Walter C. "Charlie" Neilson
Walter C. "Charlie" Neilson, age 71, of 424 Water Street Ext., Johnsonburg, formerly of Horner Road, Wilcox, died Saturday morning, Nov. 27, 2010, at UPMC Presbyterian Hospital in Pittsburgh following an illness of several days.He was born Feb. 22, 1939, in Johnsonburg, son of Walter and Mary Heindl Neilson. He married Mary Detsch in 1981; she died May 21, 1986.Formerly of Wilcox, he attended Johnsonburg schools, resided in Johnsonburg for the past five years and was a member of Holy Rosary Church.He was a Vietnam veteran having served overseas in the Army as an SP 4 with the Hospital Co., 1st Army where he received the National Defense Service Medal, a letter of commendation, Vietnam Service Medal, Combat Infantry Badge, Air Medal, a Silver Star and the Purple Heart. He was a former member of the Pennsylvania National Guard.He was employed by GTE Sylvania for 30 years before retiring in 2001.He is survived by two brothers, Robert V. "Bobby" Neilson and Rhonda Proulx of Coventry, R.I., and John "Jack" Neilson and wife Juanita of Johnsonburg; a sister-in-law, Virginia "Ginny" Neilson of Johnsonburg; several nieces and nephews; and by a close friend, Tara Button.He was predeceased by his parents; wife; and a brother, James "Jiggs" Neilson.A Memorial Service for Walter C. "Charlie" Neilson will be conducted at the Anthony F. Ferragine Funeral Home in Johnsonburg on Friday, Dec. 3, 2010, at 10 a.m. Officiating will be Rev. David J. Wilson, pastor of Holy Rosary Church in Johnsonburg. Interment will be in Parklawn Memorial Gardens in Ridgway.Arrangements are under the direction of the Anthony F. Ferragine Funeral Home, 401 Chestnut St., Johnsonburg. There will be no visitation, Friends and family are invited to attend the Memorial Service on Friday morning at 10 a.m.Military Honors will be accorded by the Johnsonburg-Wilcox Servicemen's Detail. Detail members are asked to assemble at the funeral home Friday morning at 9:30 a.m.


text:
Plans to introduce fan voting as part of the Hall of Fame election have been abandoned for this year. Officials say they expect to implement the idea for the Class of 2014.
"We absolutely hope to do it in the future," said John Doleva, the CEO and president of the Springfield, Mass., basketball museum. "It's a big priority for the Hall of Fame and for chairman [Jerry] Colangelo. It was just a little more complicated than we thought in terms of execution and getting ready and getting ramped up."
Officials lined up a media partner, ESPN, to promote the concept. But the Hall did not have important sponsorships in place, prompting the decision to postpone.
"We would love to find a corporation to get behind this and support it through their media and help them sell product," Doleva said. "It's one of those things when you think about it, they'd be able to impact the vote and to get chatter going back and forth about the finalists and 'Should this person be in? Should that person be in?' I think there's a lot of value there. We're hoping to, in 2014, definitely do that."
Under the working plan, the anonymous voters selected by the Hall — basketball officials, former players and/or coaches, athletic directors, media — would still decide the finalists. Mass participation would begin once that list is revealed at All-Star weekend in February, with fans part of the second layer of balloting that decides enshrinement later that summer. The top three finishers would get one additional vote toward the final decision, providing a 25th chance to get the 18 votes needed for induction rather than the current model of 18 from 24 electors.
That Hall proposal would give fans a strong voice, possibly the difference between election and disappointment, without the level of influence some consider would turn the process into a popularity contest along the lines of choosing the All-Star starters. The public could not have a great impact without a sizable support from basketball insiders.


text:
During the high school scramble to find a college, I found myself drawn to Oglethorpe for three reasons: it looked like Hogwarts, it was obsessed with community service, and it offered the Core curriculum.
The Core, which strives to enrich student experiences with a challenging, cross-disciplinary education, has led to some amazing opportunities for students. Recently, Rebekka Strom '13 and Samantha Flynn '13 were among only 40 students accepted to present their papers at the Association for Core Texts and Courses (ACTC) student conference at Shimer College in Chicago.
ACTC is an international, professional association that seeks to advance liberal arts education by developing and promoting liberal arts education programs (and other programs) which integrate core text courses with the most advanced developments in administration, curriculum, student support services, faculty support, and general education assessment and review.
The ACTC conference gave students the chance to share their papers, which reflected upon and integrated various Core texts, with a group of faculty members and fellow students. Rebekka was able to put her English degree to use in a formal environment, and "to see how Core transcends the classroom setting." Similarly, Samantha was given the experience of a "dry run at academia," which is her ultimate career goal.
"What really struck me during the conference was the outstanding quality of an Oglethorpe education," enthused Samantha. "Other participants in the conference were from Great Books schools and top-tier university names, and yet Oglethorpe's Core had prepared me to understand, discuss, and critique their papers on a wide variety of subjects. When people met me and asked where I was from, almost no one had heard of Oglethorpe, and yet, by the end of the conference, I had several participants inquire about the nature of Oglethorpe's Core program because they were convinced it must be a Great Books school."
"The (conference) solidified my choice in selecting and pursuing a liberal arts education," added Rebekka. "I was able to interact with like-minded undergraduate students and their support faculty members about core texts and their relevance in 21st century higher education—from Aristotle and Plato to Hobbes and Locke… it was an exciting experience to network with colleges and universities that strive to keep the liberal arts alive."
Rebekka's paper, "Remember the Ladies: Individuality, Community, and Equality of Early and Modern Women," was written for her COR-302 class.
"In [class], we talk a lot about modernity," she said. "I (looked at) the women of these time periods and contrasted them with what it means to be a modern working woman in 2013."
Samantha's essay, "Libido Dominandi: Fulfilling the Presence of the Absence of a Reality," was written for Dr. Orme's Human Nature and the Social Order class.
"(My topic) was something I saw in a lot of texts…'The Lust for Power,' 'The Will for Power… I tried to link all these (phrases) and make them part of the same dialogue."
For anyone interested in a similar opportunity, Samantha had the following advice: "Take Core seriously… It was one of the main reasons I came to OU, and this is an example of Core paying off."
Samantha was extremely thankful to have had this opportunity, and feels indebted to Dr. Knippenberg for sponsoring her and to Dr. Orme and Professor M. Smith for advising her on the content of her paper. Likewise, Rebekka expressed gratitude towards Dr. Knippenberg, Dr. Baube, and the entire Core Committee, as well as to her academic advisors Dr. Chandler and Dr. Hornback. Without their support, and without the Core program, Samantha and Rebekka could not have had this experience.


text:
Share Thread:
Vintage Card Story
03-08-2012, 01:28 PM (This post was last modified: 03-08-2012 01:31 PM by JeffreyQ.)
Post: #1
Vintage Card Story
I'm sure this sort of thing gets posted a lot... but here goes...
After 35+ years I recently cracked open my old footlocker that was stored in my parents' basement behind an old pinball machine-- and looked at the 20 or so shoeboxes and 5 or so double-drawer "punch card" boxes I used back in 1975 to store my card collection.
The cards have not been handled or looked at in 35+ years.
Between 1969 and 1975, as a 10 year old kid, I can remember walking down to the Pharmacy in Cedar Grove NJ, plucking down a $10 bill, and walking away with 100 individual packs of 10 cards each-- Each pack 10¢.
I did this literally hundreds of times between 1970 and 1975.
I bought Baseball, Football, Hockey, Wacky Packages (which my sister got to and ruined at some point), Harlem Globetrotters, Planet of The Apes, Star Wars… you name it. I have had literally 10s of thousands of cards all wrapped up for 35 years.
I can remember sitting with my father on the kitchen table when I was 14 or 15 and sorting the sports cards into two complete sets for each year of Baseball (Topps 69-75) and Hockey (Topps 72-73) Plus one complete set each of each Football (Topps 73-74), and Basketball (Topps 70-71)-- PLUS literally thousands of the "triples" (duplicate cards) just thrown into the "punch card" boxes.
All that, plus at that time, my father gave me what was left of his old Baseball Card collection (Bowman 50-51)-- Almost complete sets PLUS hundreds of doubles.
After about 1978 I simply bought complete Topps baseball sets from a friend for about 5-6 years until I gave the hobby up when I went away to school.
Now, I always had in the back of my mind that "someday" I would complete my Topps Baseball sets from 1960-1980 by selling the "triples" plus the duplicate Baseball and Hockey complete sets.
I guess that time is "NOW" as my wife and I are looking to buy a new home.
Any suggestions where I should start in Sorting? Grading? Selling?
Post: #2
RE: Vintage Card Story
I would start with the oldest and go up from there. If you want to make big money make sure they are in good shape. If you have any Cubs stuff you want to sell shoot me a message!
I envy you, I have somewhere in the range of 10,000 singles from my childhood but, they are all from 1986 to 1992. Most of them aren't worth the stock they are printed on lol.
Post: #3
RE: Vintage Card Story
I guess just about the time collectors were able to buy complete sets-- around '77 or '78 as I remember-- the "hobby" really became a "business," and cards were printed in such numbers that their values are materially less than earlier years.
I was born in the "right" year, '61, and was the "right" age, to have to had collected by buying individual packs.
In any case, I thought about trying to trade my complete sets for other complete sets-- but the Grading issue will eventually bight me in the a**-- as it will simply be too tough to trade a complete series of 800 or so cards for another series of 800 or so cards.
It'll be easier to simply grade the stars and try and sell the sets for cash money. Then buy nice sets.
In my day we traded. But its all too complicated now.
I know that may sound obvious to people, but the hobby has changed so much since I looked at these cards, I'm really thinking about the process from square one.
Do they still print series of Baseball cards in 800+ card series like they did in the early 70s?
Post: #4
RE: Vintage Card Story
Base sets from Topps and Bowman are in the 600-700 card range. There are so many subsets and parallels now though that it is really hard to keep up with it all. I like the Heritage stuff and have recently gotten hooked on Topps Finest, I just really like how the cards look.
You are right about how it's changed though, most people aren't interested in the base cards. They are all on a quest for the autographs and ultra rare 1 of 1's and things like that.
03-08-2012, 03:12 PM (This post was last modified: 03-09-2012 07:35 AM by JeffreyQ.)
Post: #5
RE: Vintage Card Story
The other thing is, to me, they've made the Grading process, much, much, too complicated. There are far too many grades-- its simply far too complicated for the average collector.
I mean, if you look on eBay, for cards under $25, unless the cards are "professionally" graded by one of the top three firms-- you have absolutely no idea what you are buying or selling.
There's so much room for error. One guys "near mint" is another guys "very good."
Fewer classifications would make it easier to home-grade-- so at least cards could circulate and get into the right collections at a reasonable price-- then once the've found a "home" in a similarly "rough" graded collection, then get a pro grade for posterity or resale purposes.
Is there such thing as a "rough-grade" grading system?
The same thing happened in the coin-collection area (which I assume the card grading industry is based on.)
There are so many phony graded coins out there the field is a joke.
Post: #6
RE: Vintage Card Story
Sounds like you made some excellent decisions at a child. Do you have any unopened packs?
« Next Oldest | Next Newest »
User(s) browsing this thread: 1 Guest(s)


text:
The Cat in the Hat
by Dr. Seuss
One wet, rainy day while mother is out, a boy and a girl sit dejectedly in their chairs, watching the rain beat against the window. They're bored. Suddenly, in bursts a large cat in a tall striped hat, ready to play — and not just ordinary games, oh no! This cat likes to create mischief and mayhem, and to aid him, he brings Thing One and Thing Two. These two small fuzzy blue imps race around the house, wreaking havoc. Who's going to clean up this mess?
This most famous of all the Beginner Books has been beloved by readers young and old since 1957.
- Ages
- 4, 5, 6, 7
- Interest Level
- Grades PreK - 2
- Lexile Measure
- 16
- Guided Reading
- Publisher
- Random House Books for Young Readers
- Book Type
- Beginning Reader Book
- Number of Pages
- 72
- Genre
- Classics, Comedy and Humor
About the Author
Dr. Seuss Dr. Seuss was born Theodor Geisel in Springfield, Massachusetts on March 2, 1904. After attending Dartmouth College and Oxford University, he began a career in advertising. Brilliant, playful, and always respectful of children, Dr. Seuss charmed his way into the consciousness of four generations of youngsters and parents. In the process, he helped kids learn to read.
The Reading Toolkit
Shop From Scholastic
Sponsor Spotlight


text:
Current statistics online
South Australian statistical information is found at the Australian Bureau of Statistics and other agencies such as:
Health - statistics reports on a range of areas from SA Heath
Office of Crime Statistics & Research (OCSAR) - includes publications and statistics page
Road Safety - statistics from the South Australian Police
You can also search for statistics on the relevant South Australian Government websites, such as Forestry SA and Tourism
Print resources in the National Library
- select the Browse alphabetically tab
- choose subjects from the drop-down list
- Type your keywords in the search bar
Example: South Australia -- Statistics
- South Australian year book 1966 - 1997
- South Australia : a statistical profile - also available online
Case Study
Causes of death in South Australia
I am looking for data on deaths related to food in South Australia over the past 10 years.
The Catalogue shows an ABS journal with a complete list of causes of death available in the National Library in Canberra and I am in Adelaide. Can I read the relevant documents online?
You have found the item titled Deaths, South Australia, which appears to contain all the information needed. However, when we check the dates available, we find only the years 1969-1993 are covered, so will not conatain data from 2000 onwards.
The record shows the 'later title' was Demography, South Australia with data up to 2001. You can read these statistics (up to 2001) online at the ABS page Demography, South Australia. Use the 'Past & future releases' tab for data back to 1993. When you have chosen a year, click on the "Downloads" tab to open the report.
For data after 2001, we need to use the publication, Causes of death, Australia. This can also be downloaded from the ABS website. Again, use the 'Past & Future Releases' tab.
In the 'Downloads' tab, we can find 'Underlying causes of death (South Australia)'.


text:
Mexican Fondue Recipe
4.5 1 2
A handful of items and a few moments of prep work are all you'll need for this festive fondue. Not only does it take advantage of canned goods and other convenience items, but the slow cooker does all the work. —Nella Parker, Hersey, Michigan
Featured In: 25 Slow Cooker Dip Recipes for Worry-Free Appetizers
VERIFIED BY Taste of Home Test Kitchen
Popular Videos
- 1 can (14-3/4 ounces) cream-style corn
- 1 can (14-1/2 ounces) diced tomatoes, drained
- 3 tablespoons chopped green chilies
- 1 teaspoon chili powder
- 1 package (16 ounces) process cheese (Velveeta), cubed
- French bread cubes
- In a small bowl, combine the corn, tomatoes, green chilies and chili powder. Stir in cheese. Pour mixture into a 1-1/2-qt. slow cooker coated with cooking spray.
- Cover and cook on high for 1-1/2 hours, stirring every 30 minutes or until cheese is melted. Serve warm with bread cubes. Yield: 4-1/2 cups.
Originally published as Mexican Fondue in Taste of Home Everyday Slow Cooker & One Dish Recipes Annual 2008, p107
Reviews forMexican Fondue
My Review
Click stars to rate
Any changes to your rating or review will appear where you originally posted your review
Average Rating
Reviewed Sep. 19, 2013
"This was yummy! I made it for dinner, and it was more than enough for myself and my two teens. My son was skeptical, which was a surprise, because he pretty much eats anything. He never asked what was in it, just ate it, and then commented at one point 'this is really good'. Considering he picks a large portion of chunks of tomatoes out of things, he never seemed to notice them in this. I will make this again, and it will probably be a stand-by for open house type parties - so much better than any prepared Mexican style warm cheese dip, much more economical as well, and it makes a lot!"


text:
Did you read today's front page stories & breaking news?
From the Wires
Launch of First Good Cents Grocery + More Brings Fresh Approach to Value-Priced Grocery in Pittsburgh
New McKnight Road location delivers cent-sationally low prices on fresh produce, meat, cheese, deli and national brands
By: PR Newswire
Nov. 4, 2012 11:30 AM
PITTSBURGH, Nov. 4, 2012 /PRNewswire/ -- Multi-format food and fuel retailer Giant Eagle, Inc. is launching its first Good Cents Grocery + More store on Sunday, November 4, at 7215 McKnight Road in Pittsburgh's North Hills, bringing a uniquely fresh approach to value-priced grocery shopping in Pittsburgh.
(Logo: http://photos.prnewswire.com/prnh/20121104/NE05594LOGO-a)
Providing extremely low prices on produce, deli, meat, cheese and grocery items, the Pittsburgh-based company's 46,000 square-foot store will feature a 3,800 square-foot produce section offering more than 230 conventional and organic produce items, a cheese department with more than 60 specialty items, a full-service deli and a fully-stocked meat department featuring meat cut and ground fresh in-store.
The new Good Cents Grocery + More will also offer groceries with a popular mix of name brand national and regional brands alongside Food Club and Valu Time store brands.
"This is the format people have been waiting for," said Good Cents Senior Vice President John Tedesco. "Think of it as the missing link between discount stores and supermarkets.
"Good Cents reflects the real fresh, not real fancy experience for customers who know how to recognize a great deal on high quality products," Tedesco added. "Good Cents comes to Pittsburgh at the perfect time, as families continue to struggle through a sluggish economy and rising food and commodity costs."
Spending Less Makes Cents
Good Cents Grocery + More will open with cent-sationally low everyday prices on items such as:
"While today's shoppers are certainly looking to stretch their food budgets through affordable-priced shopping, they shouldn't have to sacrifice quality and freshness," said Tedesco. "Our unique Good Cents format offers customers outstanding fresh produce, meat, deli and cheese items at prices that make 'cents.'"
The store will celebrate its opening on Sunday with a ribbon cutting at 8 a.m. and donations made to the Ross Township Police Department, Berkeley Hills Fire Company and North Hills Community Outreach. The McKnight Road Good Cents will employ 100 Team Members and will offer more than 7,000 items. Store hours are daily from 7 a.m. to 11 p.m. Good Cents Grocery + More accepts all major credit cards (Visa, MasterCard, American Express and Discover), as well as cash, debit cards, EBT and WIC. The store also accepts manufacturer coupons.
To keep prices low, Good Cents focuses on lower operating costs, without compromising quality or a clean and safe shopping environment. To that end, Good Cents does not accept checks as a form of tender, and also encourages customers to bring their own traditional and reusable bags. Customers may also purchase grocery bags for a nominal fee.
About Good Cents Grocery + More
Good Cents Grocery + More is a customer- and value-focused grocery store with the mission of providing quality foods at cent-sationally low prices. The store offers a mix of popular national and regional brands alongside store brands such as Valu Time and Food Club, along with departments featuring cheese, deli, meat and a wide selection of conventional and organic produce. Good Cents customers enjoy thousands of quality grocery items in a safe and clean shopping environment where they do not have to sacrifice conveniences such as access to shopping carts without a required deposit, the opportunity to redeem manufacturer coupons or the ability to pay with a major credit card.
SOURCE Giant Eagle, Inc.
Latest Cloud Developer Stories
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
SYS-CON Featured Whitepapers
Most Read This Week


text:
The folders pictured here contain voluminous prison records and court documents held at the California State Archives in Sacramento regarding Donald K. Bashor, my third cousin once removed. In the mid 1950s, the newspapers named him the "barefoot burglar" because he removed his shoes before illegally entering a residence. He stole money found during the burglaries to finance his education at the University of Southern California. For two of his burglaries, the residents were actually at home and saw him so he brutally took their lives to avoid getting caught. He was captured by police soon after the second murder in 1956. He eventually pleaded guilty to two counts of first-degree murder. In 1957, California Attorney General Edmund G. Brown affirmed the denial of a new trial. Donald was executed at San Quentin shortly thereafter.
Posted by Denise Richmond


text:
Ginger Orange Squash Recipe
3.5 2 2
Bursting with citrus flavor, this tender side dish complements special autumn dinners and weeknight suppers alike. Our home economists developed the five-ingredient recipe so you can spend less time in the kitchen and more time with family.
Recommended: Baking with Squash
VERIFIED BY Taste of Home Test Kitchen
Popular Videos
- 2 butternut squash (2 pounds each), peeled and cut into 1-1/2-inch cubes
- 1 cup thawed orange juice concentrate
- 3 tablespoons coarsely chopped fresh gingerroot
- 1/2 teaspoon pepper
- 4 teaspoons butter, melted
- Line a 15x10x1-in. baking pan with foil and coat with cooking spray; set aside. In a large bowl, toss the squash, orange juice concentrate, ginger and pepper. Arrange in a single layer in prepared pan.
- Bake at 375° for 50-55 minutes or until squash is tender, stirring twice. Stir in butter before serving. Yield: 10 servings.
Originally published as Ginger Orange Squash in Light & Tasty October 2005, p50
Reviews forGinger Orange Squash
My Review
Click stars to rate
Any changes to your rating or review will appear where you originally posted your review
Average Rating
Reviewed Dec. 29, 2013 Edited Oct. 2, 2014
"I'm the butternut squash lover, but the orange juice concentrate was too tangy, so I rinsed some of it off; then it was fine. Try just orange juice."
Reviewed Oct. 15, 2009
"This recipe was delicious. The color ads to thepresence of the dish. I loved the tangy ginger and orange flavor. I thought it was very easy to make. It's an attractive and tasty dish.I loved the outcome."


text:
We knew this game was hot from the start -- and we're not talking about the noon kickoff.
The University of Miami has announced that "following an unprecedented surge in ticket sales, all seats allotted for single-game purchases for the September 7 game vs. Florida are now sold out. The only remaining opportunity to buy a ticket to the Florida game is via a season ticket."
Season tickets begin at $20 per game for the least expensive package, according to UM.
The seven home games: FAU in the season opener at 8 p.m. on Friday, Aug. 30; the Gators at noon Sept. 7; Savannah State on Sept. 21; Georgia Tech (the Atlantic Coast Conference opener) on Oct. 5; Wake Forest on Oct. 26; Virginia Tech on Nov. 9; and Virginia on Nov. 23.
Tickets are still available on a single-game basis for all other home games, according to HurricaneSports.com. "Hurricane Club members may purchase seats now through their online account. Season-ticket holders may first purchase single-game tickets on Monday, July 29. Seats become available to the general public on Monday, August 5."
For more information or to order by phone, call the UM ticket office at 305-284-2263.