Chapter 4. Working in Teams

We’ve been programming solo with Eclipse up to this point, but it’s also designed to be used in team environments, and it supports Concurrent Versions System (CVS) to make teamwork go smoothly. Eclipse can be used by any Java developer, and developers often work in teams. This chapter is all about teamwork using Eclipse and CVS.

How Source Control Works

When you work in teams, you have to coordinate. That means discussing and planning, of course, but even with the best of intentions, you can still end up with conflicts. You may have made some brilliant changes to the code—only to find them all wiped out by mistake when another programmer uploads his new version of a file.

Source control stops those kinds of problems by controlling access to code and by maintaining a history of the changes that have been made so things aren’t destroyed unintentionally. Storing a history of your code is very powerful—not only can you compare a new (buggy) file against an older one, you can also revert to a previous version in case things have gone awry.

Source control also gives you the ability to coordinate the simultaneous development of several different versions of your software—for example, you might want to work on both a release version and a new beta version. You can do that using branches, as we’re going to see in this chapter.

Understanding CVS

CVS is an open source project; it started life as a set of Unix shell scripts in 1986 and came into its own with dedicated software in 1989. Support for CVS is available on many operating systems today—Unix, Linux, Windows, and others. For the full CVS story, take a look at http://www.cvshome.org.

The idea behind CVS, as with any repository software, is to manage and record changes to source code. In fact, there are many types of repository software available, and some are more powerful than CVS, but CVS is in the most widespread use (perhaps because you can get it for free).

In CVS, a module is the basic equivalent of an Eclipse project. Modules are represented by directories in CVS. Standard projects correspond to physical modules, while logical or virtual modules are collections of related resources.

The files you share are stored in the CVS repository. When you retrieve a file from the repository, you check the file out. After you’ve modified the file, you commit the changes to check it back in and send those changes to the repository. If you want to refresh your own copy of a file, you update it from the repository.

In general, there are two models for source code repositories:

Pessimistic locking

Only one developer can check out a particular file at once—after the file is checked out, the file is locked. It’s possible for someone else to check out read-only copies of the file, but not to change it. Access is sequential.

Optimistic locking

Developers can check out and modify files freely. When you commit changed files, the repository software merges your changes automatically. If it can’t do that by itself, it’ll notify you that you have to resolve the issue yourself. Access is random.

By default, CVS supports optimistic locking—although some CVS software also supports pessimistic locking. We’ll be using optimistic locking here, which is what Eclipse supports.

Because each file needs to be kept track of, CVS gives each file a version number automatically. Each time a file is committed, its version number is incremented. When you first commit a file, its version number is 1.1; the next time, it’s 1.2, and so on (this can depend on your CVS server; some will start with 1.0). When you commit files to the repository, they’ll get a new version number automatically. We’ll see these version numbers in the various views you work with when using source control.

When you update a file from the repository, your local version of the file is not overridden. Instead, Eclipse will merge your local file and the one in the CVS repository. If there are conflicts, the conflicting lines will be marked with special CVS markup indicating potential problems. You get the chance to modify your code to handle any conflicts that occurred during the merge operation, after which you can commit your new version of the code. Usually, updating goes smoothly, especially if each developer working on the project has her own set area to work in, but sometimes you’ve got to spend time resolving the conflicts that CVS points out to you manually.

CVS also supports development branches. The main development stream of a project is called the head, and CVS has a special tag name called HEAD that corresponds to that stream. Branches are forks from the head, and, in a branch, you can make changes that are independent of the main development stream, such as when you want to work on a beta version of your project. You tag a branch with a name, and CVS will keep track of the branches using their names. We’ll see how all this works later in this chapter.

Finding a CVS Server

To work with CVS, you need access to a CVS server. If you have access to a CVS server already, you’re all set. Otherwise, take a look at the overview that follows.

Most Linux and Unix installations already come with a CVS server built-in. To test if you have a working CVS installation, type cvs --help at the prompt; you should see a list of help items. If you can’t find a CVS server, you can download what you need from http://www.cvshome.org.

In Windows, the story is a little more complex. There are a variety of CVS servers for Windows, such as CVSNT, available for free from http://www.cvsnt.org. To install CVSNT, just download the executable file and run it.

Creating a Repository

You’ll need to create a repository for your source code using the CVS server. In Linux and Unix, you do that with the command cvs -d path init, where path gives the location of the directory you want to use as the repository (the permissions and ownership for path should be set so all members of your development team can access it).

With CVSNT, you click the Repositories tab in the CVSNT control panel, click the Add button, enter the path of the new repository directory, such as c:\repository, and click OK.

Connecting to CVS

In Linux and Unix, you use one of two possible options to reach CVS: SSH (secure shell) or pserver. We’ll use pserver here, but you can use either protocol; just make sure that the correct protocol is running on your machine.

In Windows, CVSNT runs as a Windows service, which means it is accessible to Eclipse as soon as you run it. You can start it from the Start menu by selecting the Service control panel item from whatever program group you’ve added it to, which opens the CVSNT control panel. Click the Start button in both the CVS Service and CVS Lock Service boxes, which will make CVSNT display the message “Running” in both those boxes, as you see in Figure 4-1.

Starting CVSNT
Figure 4-1. Starting CVSNT

With your CVS server running, it’s time to start using CVS with Eclipse.

Adding a Project to the CVS Repository

We’ll start using CVS by seeing how to add a new project, Ch04_01, to the CVS repository. After this project is in the CVS repository, anyone with access to the repository can check it out and work on it. You can see this sample project in Example 4-1; this sample code does nothing more than display the word “Hello”.

Example 4-1. A sample project
package org.eclipsebook.ch04;

public class Ch04_01 {

        public static void main(String[] args) {
                System.out.println("Hello");
        }
}

Creating a Repository Location

After you’ve created a project, how do you add it to the CVS repository? You first have to let Eclipse know about the repository, so select Window Open Perspective Other, and select the CVS Repository Exploring perspective (after you do this the first time, Eclipse will add this perspective to the Window Open Perspective, and will add a shortcut for this perspective to the other perspective shortcuts at the extreme left in Eclipse). When this perspective opens, right-click the blank CVS repositories view that appears at left and select New Repository Location, opening the Add CVS Repository dialog you see in Figure 4-2.

Connecting a CVS repository to Eclipse
Figure 4-2. Connecting a CVS repository to Eclipse

Here, enter the name of the CVS server (usually the name of the computer that hosts the server), the repository path, the username and password, and specify the connection type (here, we’ll be using the pserver protocol). Then click Finish to add the new repository to the CVS Repositories view, as you see in Figure 4-3.

A new repository in the CVS Repositories view
Figure 4-3. A new repository in the CVS Repositories view

Congratulations—now you’ve connected a CVS repository to Eclipse. The next step is to start sharing your new project.

Tip

There’s even a public CVS server for Eclipse and Eclipse code. You can access that server’s repository by creating a repository location for :pserver:anonymous@dev.eclipse.org:/home/eclipse.

Sharing Projects

To add the Ch04_01 project to the CVS repository, you can use the built-in support for CVS in Eclipse. Open the Java perspective, right-click the project you want to share, and select the Team Share Project item. This displays the Share Project with CVS Repository dialog, as you see in Figure 4-4.

Specifying which repository to use
Figure 4-4. Specifying which repository to use

In this dialog, make sure the “Use existing repository location” radio button is selected, and select the repository you’ve already created. Click Finish to add the project to the CVS repository.

Tip

This gives the CVS module the same name as the project. If you want to give the created CVS module a different name, click Next instead of Finish, enter the name of the CVS module you want to create, enter a new module name, and click Finish.

The Share Project operation adds the project to the CVS repository and also opens a Synchronize view that overlaps with the Console view. The Synchronize view lets you synchronize files, but it’s not of much use to us at this point; we’ll see how to work with it later in this chapter when we synchronize our local code with code in the repository that’s been changed by someone else.

Tip

If you want to see what commands Eclipse is sending to the CVS server, you can open the CVS console by selecting Window Show View Other CVS CVS Console. The CVS console will appear overlapping the standard Console view.

Committing Files

So far, we’ve just added the Ch04_01 project to the CVS repository; now we’ve got to start checking in some files. There are two steps here: first, you add the file to CVS (which just notifies CVS of the file but doesn’t actually upload the file), then you commit it (which makes the file appear in the CVS repository so it can be shared).

You can add individual files by right-clicking them and selecting the Team Add to Version Control item. Then you can select the Team Commit menu item to commit them.

However, there’s an easier way. Eclipse gives you a shortcut here—just right-click the project in the Package Explorer, and select Team Commit. When you do, Eclipse will display the Add to CVS Version Control dialog, listing the files that have not yet been added to the CVS repository. Make sure all filenames are checked in this dialog by clicking the Select All button and then clicking the Yes button. Eclipse will prompt you for a comment for the set of files you’re committing, giving you the chance to label that set of files and indicate what makes them different from other files in the repository. In this case, just enter some text, such as Build 1.0, and click OK.

Tip

If you want to check in and check out projects as Eclipse projects, be sure to commit the .project file itself.

To verify that the project is connected to the CVS repository, select Windows Preferences Workbench Label Decorations, select the CVS checkbox, and click OK. This displays a gold cylinder next to files in the CVS repository, as you see in the Package Explorer in Figure 4-5. Files in the repository will also have a CVS version number showing; that version is 1.1 here.

Verifying CVS connections
Figure 4-5. Verifying CVS connections

Switch to the CVS Repository Exploring perspective now, as you see in Figure 4-6. You can see your entire project, now the Ch04_01 CVS module, in the repository’s HEAD section, which is the main development stream. Also note the CVSROOT directory, which holds CVS administrative data, and the Branches node, which will hold any files in other branches of development.

Examining files in the CVS repository
Figure 4-6. Examining files in the CVS repository

Checking Projects Out

How does someone else check out your new CVS module? To check out a module, he’d first create a connection to the repository in the same way as we have—by right-clicking the CVS Repository view, selecting New Repository Location, and entering the name of the CVS server, the location of the repository, username, password, and the type of the connection.

He can then open the Repository view to explore the files in the repository. To check out the Ch04_01 module, right-click the module in the Repository view and select the Check Out As item from the context menu, opening the Check Out dialog you see in Figure 4-7.

Checking out a project
Figure 4-7. Checking out a project

In this case, clicking OK checks out the Ch04_01 project and tries to build it. If you’re sharing an Eclipse project and each CVS module has its own Eclipse .project file, you can simply select the Check Out As Project item from the Repository view’s context menu, which will check out an Eclipse project and build it locally. If your code isn’t in a project of a kind that Eclipse can recognize, it will ask you what type of project to create; select the Java entry, followed by the Java Project entry.

Updating Code

So what if you and other members make changes to the files in the Ch04_01 project and save them? For example, say you change the code from this, where we’re displaying “Hello”:

public class Ch04_01 {

        public static void main(String[] args) {
                System.out.println("Hello");
        }
}

to this, where we’re displaying the message “Hello there”:

public class Ch04_01 {

        public static void main(String[] args) {
                System.out.println("Hello there");
        }
}

When you make these changes and save the file Ch04_01.java, you’ll see a ">" appear in front of various files in the Package Explorer, as you see in Figure 4-8, indicating there are outgoing changes that have yet to be committed.

Changing a file in the CVS repository
Figure 4-8. Changing a file in the CVS repository

You could commit your changes to the CVS repository, but, as a general rule, it’s a good idea to first check and see how your changes will be received. Say, for example, that someone else has already checked out the same code and modified it to display the message “No worries.”:

public class Ch04_01 {

        public static void main(String[] args) {
                System.out.println("No worries.");
        }
}

He’s committed the changes by right-clicking the file in his version of Eclipse and selecting the Commit item, so his version of the file is now version 1.2. With changes like this being made to the code, you can see why it’s a good idea to check what other changes have been made before committing a file. To check on changes that have already been made to the file you’ve checked out, right-click it and select the Team Update menu item. Doing so imports Ch04_01.java version 1.2 into your Eclipse, as you can see in the Package Explorer at left in Figure 4-9. And in this case, it also indicates that there’s a conflict between your code and the code in the repository, as you see in the editor.

Updating a changed file
Figure 4-9. Updating a changed file

If there was no conflict, any changes would simply have been merged into your version of the file. But since both you and the other developer have changed the same line, there is a conflict. The CVS support in Eclipse indicates that there’s a conflict by listing both versions in your code with some added CVS markup:

public class Ch04_01 {

        public static void main(String[] args) {
               <<<<<<< Ch04_01.java
                System.out.println("Hello there");
               =======
                System.out.println("No worries.");
               >>>>>>> 1.2
        }
}

To get more information, right-click the changed file, Ch04_01.java, and select the Team Show in Resource History item. You’ll see the CVS Resource History view appear, as you see in Figure 4-10, and you can see the comments for each version of the code in that view.

Looking at the resource history
Figure 4-10. Looking at the resource history

Comparing Code with Local History

To make it a little clearer as to what CVS-generated changes have been made in longer files, you can check Ch04_01.java against its local history, which is a useful thing to know. To compare a file against its history, right-click that file and select Compare With Local History, opening the Compare with Local History dialog you see in Figure 4-11. This dialog points out in a graphic way the changes that the CVS support in Eclipse added to the code.

Checking a file’s local history
Figure 4-11. Checking a file’s local history

Committing Code

Before you commit a file, it’s up to you to resolve the conflict that the update has revealed. In this case, we’re going to accept the other developer’s version of the code, but with modifications—instead of “No worries.”, we’ll display “No worries at all.”:

public class Ch04_01 {

        public static void main(String[] args) {
                System.out.println("No worries at all.");
        }
}

Now right-click Ch04_01.java and select Team Commit, which opens the Commit dialog you see in Figure 4-12. This dialog asks for a new comment for the file you’re about to commit; in this case, we’ll use the comment “No worries at all version.”

Committing a file
Figure 4-12. Committing a file

Click OK to commit your changes to the CVS repository. Doing so creates version 1.3 of the file. And that’s all you need—now you’ve committed a new version of your code to the CVS repository. We’ve gone through the whole cycle now—checking code in, checking it out, updating code to check on changes made by other developers, and committing it. There’s also another way to update your code if the differences between your version and the repository are fairly extensive: you can synchronize your code.

Synchronizing Code

When the differences between your code and repository code are relatively minor, an update is fine. But when the differences are substantial, it’s better to synchronize. Synchronizing with the repository lets you compare changes that have been made side-by-side in an easier format than the update merge format.

For example, say that someone else works on the same file that you’re working on, Ch04_01.java, and adds a new line of code and then commits her file as version 1.4:

public class Ch04_01 {

        public static void main(String[] args) {
                System.out.println("No worries at all.");
                System.out.println("Got any problems with that?");
        }
}

To synchronize your code (version 1.3) with the new version of Ch04_01.java (now at version 1.4 in the repository), right-click the Ch04_01 project and select Team Synchronize with Repository. You can see the results in Figure 4-13.

Synchronizing a project
Figure 4-13. Synchronizing a project

When you first synchronize with the repository, you’ll see the name of the files where there are differences marked with a stubby red double arrow (which looks almost like a diamond in Figure 4-13) in the Synchronize view. Double-clicking a file so marked opens the full display you see in Figure 4-13, where you can compare the repository version of the file (version 1.4) to your version (version 1.3) directly in the Java Source Compare view at the bottom of the window.

Note, in particular, the line connecting the two code boxes in the Java Source Compare view and the small white box in the middle of that line. If you let the mouse hover over that box, it’ll change into a button with a left-pointing arrow. Clicking that arrow will import the change into your version of the file, making the synchronization process a little easier. After you’ve synchronized your version of the code with that in the repository, commit your changes back to the repository.

In this case, the repository file has been changed since the last time we synchronized/updated with the repository, and the Synchronize view opened in incoming mode (as you can see in this view’s title bar in Figure 4-13), which displays the changes in repository code. There are three such modes in the Synchronize view:

Incoming

Displays those files that have changed in the repository since the last time you synchronized, updated, or committed your code with the repository.

Outgoing

Displays those local files that you have changed since the last time you synchronized, updated, or committed your code with the repository.

Incoming/outgoing

Displays the local or repository files that have changed since the last time you synchronized, updated, or committed your code with the repository.

You can select the Synchronize mode with the buttons you see at right in the Synchronize view’s title bar. In Figure 4-13, Eclipse saw some incoming changes and automatically selected incoming mode, which means the incoming mode button is down. To the right of that button is the outgoing mode button and to the right of that button is the incoming/outgoing mode button.

For example, say that you’ve changed the local version of Ch04_01.java so that instead of displaying the message “No worries at all.”, it displays “No worries at all today!”:

public class Ch04_01 {

        public static void main(String[] args) {
                System.out.println("No worries at all today!");
        }
}

Now when you save these changes locally and synchronize, selecting outgoing mode, you’ll see your local changes compared to the repository version, as in Figure 4-14.

Outgoing mode
Figure 4-14. Outgoing mode

These modes are designed to let you filter the changes that have happened to make synchronizing/updating more tractable. If there are a lot of changes going on, make sure you synchronize/update frequently—although it can feel like an unpleasant task, it’s necessary when you’re working in teams, and, if you wait too long, merging with the repository code can become just about impossible.

Tip

Here’s something else to be careful about: although you can undo changes in a file with Eclipse’s Edit Undo menu item, those changes are local and not necessarily reflected in the code in the CVS repository. So if you update and find that there are too many changes that appear in the merged code, you can select Undo. But Eclipse will treat that Undo operation as a local edit to the file, so when you then synchronize with the repository version of the file, you may be presented with different options than the ones we’ve discussed here. In general, it’s not a big problem, and updating and merging your code is still the best general policy before committing your code. However, if you suspect there may be big changes, either synchronize instead of updating, or back up the file you’re going to update first.

Creating a Patch

Not everyone you deal with is going to have access to your CVS repository. To update those users without changing the version number of the software, you can create a patch. For example, say that you added this line to your example code locally but didn’t change the code in the repository:

public class Ch04_01 {

        public static void main(String[] args) {
                System.out.println("No worries at all.");
                System.out.println("Got any problems with that?");
                System.out.println("Didn't think so.");
        }
}

You can create a patch that will convert the standard code for this version to the new form of the code. When you create a patch, Eclipse will compare your local code to what’s in the repository and create a patch file holding the differences.

To create a patch to let users of your code come up to speed without needing access to the CVS repository, save the modified file locally, right-click it, and select Team Create Patch, opening the dialog you see in Figure 4-15.

Creating a patch
Figure 4-15. Creating a patch

You can save the patch file where you want; in this case, we’ll save it as a file named Ch04_01Patch in the workspace. That’s all you need; click the Finish button to save the patch. This creates the file Ch04_01Patch with these contents—as you can see, this is simple text, suitable even for emailing (note that the new line of code is marked with a +, which means Eclipse will add it to the code you’re patching):

Index: Ch04_01.java
===================================================================
RCS file: c:/repository/Ch04_01/org/eclipsebook/ch04/Ch04_01.java,v
retrieving revision 1.4
diff -u -r1.4 Ch04_01.java
--- Ch04_01.java        28 Oct 2003 21:13:46 -0000        1.4
+++ Ch04_01.java        29 Oct 2003 17:34:54 -0000
@@ -17,5 +17,6 @@
         public static void main(String[] args) {
                 System.out.println("No worries at all.");
                 System.out.println("Got any problems with that?");
+                System.out.println("Didn't think so.");
         }
 }

To apply the new patch to code that has not yet been patched, right-click the file to be updated in Eclipse and select the Team Apply Patch item, opening the dialog you see in Figure 4-16.

Applying a patch
Figure 4-16. Applying a patch

Browse to the patch file and click Next, opening the dialog you see in Figure 4-17. Here, you can review the changes the patch will create in your local version of the file. As you can see, Eclipse is proposing to add the line System.out.println("Didn't think so."); to your code. Click Finish to apply the patch.

Configuring a patch
Figure 4-17. Configuring a patch

Applying the patch adds the new line of code to the local version of the file, as you see in Figure 4-18. The version number of the file wasn’t changed, but your code was. Using Eclipse in this way automates the entire patching mechanism.

The new patch has been applied
Figure 4-18. The new patch has been applied

Tagging Versions

When you create a milestone version of your code, you can tag it with a version label, which will make CVS store that version so that you can access it at will later. To tag a project with a version label, right-click the project and select Team Tag As Version, opening the dialog you see in Figure 4-19.

Tagging a version
Figure 4-19. Tagging a version

In this case, we’re going to tag the current version of the project as FirstSafeBuild, so enter that name and click OK. Version labels must start with a letter, and they may not include spaces or these characters: `$,.:;@|‘. After tagging the current version with this name, you can find it in the Versions node in the CVS Repositories view, as you see in Figure 4-20.

Examining a tagged version
Figure 4-20. Examining a tagged version

You can check out a tagged version of a module by right-clicking it in the CVS Repositories view and selecting context menu items such as Check Out as Project, as with any other CVS module. Alternately, you can right-click a project in the Package Explorer and select the Replace With Another Branch or Version item, opening the dialog you see in Figure 4-21. Select the version you want to replace the current project with and click OK.

Replacing the current project with another version
Figure 4-21. Replacing the current project with another version

Tagging a project with a version label like this is very useful because it lets you store a snapshot of the project that can be retrieved by name later.

Creating Branches

Besides storing versions, you can also create new branches, which act as alternate streams of development. For example, you might want to create an Internet-enabled branch of your software for testing, so you’d split a new branch off from the main development tree to do that.

To create a branch, right-click a project and select Team Branch, opening the Create a new CVS Branch dialog you see in Figure 4-22. Give the new branch a name—we’ll use InternetEnabledBranch here (note that branch names have the same restrictions as version labels). You can also create a new version name that will act as the start of the branch, giving Eclipse a starting point for merging the branch back into the main development stream.

Creating a new branch
Figure 4-22. Creating a new branch

If you leave the “Start working in the branch” checkbox checked, you’ll start working with the branch’s code immediately. Alternately, you can check out a branch from the CVS Repository view, as you see in Figure 4-23.

Exploring branches
Figure 4-23. Exploring branches

If you want to merge a branch back into the main development stream, right-click it in the Package Explorer and select the Team Merge item, opening the Merge dialog. Select the merge starting point (this is the version name you gave when you created the branch) and click Next. In the next pane, select the branch you want to merge from, and click Finish.

This finishes our chapter on teamwork using CVS. A natural part of developing code with Eclipse is to share that development with others in teams, and, as you can see, Eclipse is up to the task.

Get Eclipse now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.