« Using Project Builder's 'Source Control Management' Features
by Bob Savage(email)
MacOS X shipped with a Concurrent Versioning System (called in the typically laconic Unix style, "cvs"), and Project Builder includes rudimentary support for "Source Control Management", including a menu called "SCM" that seems perpetually greyed out. This article looks at how to enable that menu, using the underlying "cvs" application that Project Builder relies upon to implement SCM. It is not a complete treatment on using "cvs". If you want to learn more about "cvs" I would recommend that you start here: file:///Developer/Documentation/Commands/cvs/cvs_toc.html.
Note: if you are not familiar with terms like "home directory", or "terminal window" do not take any action based on this article. Read up on the basics of Unix before trusting some random posting on a website about what you should be typing at a command prompt.
By the way, the current release of Project Builder, the one that I am basing all of this on, is v.1.0.1. If you are using a different version of Project Builder I can't be sure that what I describe is still accurate.
// Creating the Repository
There are many ways to use CVS; I'll start with the simplest scenario. Let us assume I am going to do some development work without sharing source with other people and I will never need access to the code base from any computer other than the computer I am on.
First I need to create a "repository" which is a place the CVS software will keep the authoritative version of the code, as well as notes about the changes the code has undergone. Since I am the only one using this repository I can put it anywhere I have write permissions. I'm going to put it in the top level of my "home" directory. I'll need a directory for this, and it doesn't matter what the directory is called. Being an imaginative sort, I'm calling mine "CVS-repository".
[localhost:~] bsavage% mkdir ~/CVS-repository
The cvs application needs to initialize the directory for use as a repository.
[localhost:~] bsavage% cvs -d ~/CVS-repository init [localhost:~] bsavage% ls CVS-repository/ CVSROOT/
As you can see a directory was created for me; it is filled with things needed by the cvs program, and I can safely ignore it for the moment.
// Importing a Project
Now that I have the repository set up I can put it to good use. I have a little project that I started, and before I go to much further I would really like to put it under version control. I just want to do a little clean up first. when I initially import the project into the repository, it will create the basic form of the project that I will be using from now on. I can add and delete files and directories, but it will be a lot easier if I clean up the project's directory now, before putting it under "source control management".
[localhost:~] bsavage% ls ~/FileDemo/build FileDemo* FileDemo.pbxindex/ ProjectHeaders/ intermediates/
Everything looks good, except I've previously built and indexed this project. I don't want the contents of the build directory to be put under version control. I could go into Project Builder and "clean" the project (the broom icon), and then "Remove Project Index" (from the "Project" menu), but I'm just going to delete the entire build directory.
[localhost:~] bsavage% rm -r ~/FileDemo/build/
In the future when I build this project the build directory will reappear, but it and its contents will not be in the project as far as "cvs" is concerned (they would have to be actively added).
The import itself is fairly simple. I change to the directory I want to import, and give the command to import with a log message and a couple of other options: the name of the project as it will appear under cvs, my login, and the word "start".
A few things to keep in mind: You must be in the top level of the directory you are importing when you give the cvs import command. It is important to put the "-d path/to/the/repository" before the word 'import'. The log entry can be anything you want, but be sure to put it in quotes if it contains spaces. It is a good idea to make the name that cvs uses to identify the project one word only.
[localhost:~] bsavage% cd ~/FileDemo/ [localhost:~/FileDemo] bsavage% cvs -d ~/CVS-repository/ import -m "putting existing project under source control management" FileDemo bsavage start N FileDemo/.DS_Store N FileDemo/main.m N FileDemo/TDActionItem.h N FileDemo/TDActionItem.m N FileDemo/TDList.h N FileDemo/TDList.m N FileDemo/TDTask.h N FileDemo/TDTask.m N FileDemo/TDtypes.h cvs import: Importing /Users/bsavage/CVS-repository//FileDemo/FileDemo.pbproj N FileDemo/FileDemo.pbproj/bsavage.pbxuser N FileDemo/FileDemo.pbproj/project.pbxproj No conflicts created by this import.
That went well, but it was not enough to put the ~/FileDemo project under SCM. I used the directory ~/FileDemo as a template for a new project (often called module) in the repository, but there is more to source control management than saving a copy somewhere.
// Checking Out a Working Copy
Since the FileDemo project is highly valuable to me, I am going to prepare for the worst here. I am going to rename my existing directory and keep it around until I have checked out a copy from my new repository, and determined that everything went as well as I thought it did.
[localhost:~] bsavage% cd .. [localhost:~] bsavage% mv FileDemo Old_FileDemo
Now I check out a working copy of the project from the repository.
[localhost:~] bsavage% cvs -d ~/CVS-repository/ checkout FileDemo cvs checkout: Updating FileDemo U FileDemo/.DS_Store U FileDemo/TDActionItem.h U FileDemo/TDActionItem.m U FileDemo/TDList.h U FileDemo/TDList.m U FileDemo/TDTask.h U FileDemo/TDTask.m U FileDemo/TDtypes.h U FileDemo/main.m cvs checkout: Updating FileDemo/FileDemo.pbproj U FileDemo/FileDemo.pbproj/bsavage.pbxuser U FileDemo/FileDemo.pbproj/project.pbxproj
I now have a copy of my project that is under version control! If I take a look at it, I will see that cvs added some things in a "CVS" directory, but I can ignore them and let cvs handle that for me.
// Enabling SCM in Project Builder
Things are going so well that I want to get right back in and code! But before I do that, I need to make sure that everything is set in Project Builder. I open up my project by double-clicking on the "FileDemo.pbproj" file, which opens Project Builder. Now I go to the Project Builder -> Preferences menu item. I scroll all the way over to the right and select "CVS Access" from the toolbar. I just need to make sure "Enable SCM" is checked, and hit "OK".
I'm a little excited about getting this SCM thing going so I click on the "main.m" file, and add a first line that says:
/* Version Control Rules! */
Now when I look at the SCM menu I can see "Refresh Status" is no longer greyed out. When I select it, an 'M' appears to the left of the "main.m" file. That means that "main.m" has been modified in comparison to the most recent revision in the repository. If I take a look at the SCM menu again I can see that even MORE menu items have become active! I immediately select "Compare/Merge with Latest Revision", and a new application pops up. This program "FileMerge" has a fair amount of help available by selecting the Help -> FileMerge Help menu item. I can see immediately that there are no conflicts and the one change is a very good one, so I'm just going to quit FileMerge.
Now that I have a changed project, and I am fairly certain that this is a change I want to keep (I've compiled it and run the test suite, for example), I'm going to commit the change. Do I need to go back into the terminal and issue some more arcane commands? No! I merely select the SCM -> Commit Changes ... menu item. Project Builder thoughtfully provides a sheet with a place for me to enter the log message. I type in "Added some important documentation." and hit the "Commit" button. The 'M' has disappeared from the left most column, and a little message appears at the bottom that the commit has succeeded. If I ever wonder what kind of changes that file went through, I can select it, and then type cmd-I and look at the log messages, dates of revision, and so on.
Great, but what happens when I need to add a new class? I make the files as I normally do, but I see that there is a question mark next to them, and the project as a whole has an 'M' next to it. What I need to do is add the new files to the project in the repository, because it doesn't know about them yet. I select the new files and choose the SCM -> Add to Repository, and now the new files are marked 'A'. This means that I still need to commit the change to permanently add them. I do this as I did before, including adding a relevant log message, but if I only have one selected, I am only performing the SCM operation on that one file. The best thing to do in this circumstance is to select the overall project file and commit all the changes together.
// Hey! Wait a Minute!
What about getting old versions of files, and collaborating with other developers? I'm not going to discuss those things here for a few reasons:
- SCM in Apple's Project Builder is clearly a work in progress, and I don't want to tell people complicated ways of doing things when Apple is developing something to simplify the process.
- The current procedure for doing these things is the same as the way that is thoroughly documented elsewhere. Checking the URL I posted at the beginning of this article would be a good place to start.
- Enough's enough. This simple version will be enough to get some people off the ground, and I think it is more important as a community for us to get moving with these new tools, than to sit around until we are satisfied every little detail has been covered. If I get a chance, I'll write up a second part, describing how to share a repository with others. If you can't wait, research how to do it, write the results up, and post them here so everyone can learn.
Best of luck to all!
Note: Bob Savage is a founding member of Project Steam Weasel.