Learn how Subversion can help you manage versions in a team environment.
By John Stegeman
Published December 2008
In Part 1 of this series, you learned the basics of installing Subversion, setting up a repository, and performing basic operations with Oracle JDeveloper 11g. Here in Part 2, you’ll learn how things work with Oracle JDeveloper and Subversion when you add another developer to the team.
If you’ve been following along since Part 1, you’ll remember that we created two users with access to our Subversion repository, john and josephine. Up to now, John has been the only developer working on the application; let’s see how Josephine can join the team and work on the application.
The first thing Josephine needs to do is check out a copy of the application from the repository. Remember that “checking out” a copy of the application just puts a local copy of the application (together with some housekeeping directories) on the local machine. So that you can tell who is performing actions throughout this article, I have set Josephine’s look-and-feel to “sky pink.”
To check out a copy of the application, Josephine selects Check Out… from JDeveloper’s Versioning menu:
Figure 1 Checking out a copy of the application
Because Josephine doesn’t have a repository connection defined, she fills out the repository information, supplies her credentials, and tests the connection:
Figure 2 Creating a Subversion connection
Because she wants to work on the main development line of code (the “trunk”), she selects the trunk directory and provides a destination on her local hard drive for the checked-out copy:
Figure 3 Specifying the location of the files to check out
Oracle JDeveloper then checks out the latest version of the application code from the repository and opens it. Josephine can now work on the application code.
Now that Josephine is part of the team, she wants to add a new Java source code file to the ViewController project. Just because the team is using Subversion, she does not have to do anything special to create the new .java file and add it to her project; she simply works in Oracle JDeveloper as usual. Josephine creates a new .java file and creates a few methods in it:
Figure 4 The new Hello.java file
When Josephine looks at the new file in the Application Navigator window, she will see a blue x icon overlaid on her file, indicating that the file is not yet associated with the Subversion repository:
Figure 5 Hello.java showing blue x overlay
Furthermore, when she looks at the Pending Changes window ( Versioning -> Subversion -> Pending Changes on the Oracle JDeveloper menu), she’ll see her new Hello.java file listed in the Candidates tab, indicating that she has a file that is a candidate to be added to version control:
Figure 6 Pending changes showing Hello.java as a candidate to be added
To add the new file to version control, she selects the file and uses the “add” button (the plus [ +] icon) in the Pending Changes window:
Figure 7 Adding the candidate file via the Pending Changes window
or right-clicks the file in the Application Navigator window and selects Add...:
Figure 8 Adding the candidate file via the Application Navigator context menu
Both of these methods do the same thing—there’s almost always more than one way to access a function in Oracle JDeveloper. Adding the file will mark it for addition to the repository; note that adding the file does not yet commit the changes to the repository. When Josephine looks at the Outgoing tab of the Pending Changes window, she may be a bit surprised to see that she has five outgoing changes, not just one:
Figure 9 Pending Changes window showing files and directories to be added
The explanation is that Subversion can version directories as well as files; adding a new Java file has created a directory structure as well. Now that Josephine has made her changes, she’s ready to commit them to the repository; until she does so, her changes are just stored on her local hard drive and are not available to the rest of the team. In part 1, John committed his changes by using the Commit Working Copy… action in Oracle JDeveloper; Josephine will do it a slightly different way. She selects all of the items in the Pending Changes window (one file and four directories) and clicks the Commit… button:
Figure 10 Committing changes to the repository
She then supplies a commit message/comment so that others will know what changes she made:
Figure 11 Providing comments for the changes
Oracle JDeveloper then sends the changes to the repository, and Subversion saves them and increments the revision number.
Because John is sitting in the cubicle next to Josephine’s, he talks with her about the project and discovers that she has added a new Java class to the project. He goes back to his desk, opens his copy of the project in Oracle JDeveloper, and cannot find the new file anywhere:
Figure 12 John's application (where is Hello.java?)
Why can’t John see it? Because each developer (John and Josephine) is working on a local copy of the application. When another team member commits changes, they are not automatically copied from the repository to each local working copy; they are copied only when the developer specifically requests his or her working copy to be updated from the repository.
A general best practice is for developers to update their working copy on a regular basis—specifically to update their working copy before beginning a new piece of work. However, without performing the update, how do developers know there are changes for them to update? Let’s go back to John’s work session to demonstrate. When John looks at the Pending Changes window, he notices that there are new files in the Incoming tab:
Figure 13 Incoming changes shown in the Pending Changes window
Normally John should be able to select the incoming changes with which he wishes to update his working copy by selecting them in the Pending Changes window and clicking the Update button, but for some reason, in his copy of Oracle JDeveloper 11 g, the button is disabled, so John uses Update Working Copy... from the Application Navigator window:
Figure 14 Updating the working copy
In the dialog box that appears, he accepts the default values and clicks OK:
Figure 15 Update Working Copy dialog box
After Oracle JDeveloper updates the application from the repository, John now sees Josephine’s newly added file in the Application Navigator window:
Figure 16 John's application showing Hello.java
John then opens Hello.java to see what Josephine has done. The first thing he notices is that the code formatting style doesn’t suit him; instead of the open-braces-on-the-same-line style,
Figure 17 Josephine's coding style
he prefers the open-braces-on-the-next-line style:
Figure 18 John's coding style
So the first thing he does is to use the Reformat command in Oracle JDeveloper to make the file easier to read. However, once he does that, the content of the file is changed, and he now has an outgoing change awaiting commit to the repository. If he commits his change, when Josephine (who prefers the original code style) will reformat the code back to her preferred style when she next updates her working copy. If they don’t agree on a common style, John and Josephine will forever be playing Ping-Pong with their Java code, each reformatting the other’s code ad infinitum.
The moral of this story is that, when working in a team environment with version control, you need to agree on common standards up front to avoid these kinds of problems. Fortunately, Oracle JDeveloper has an option for specifying coding style preferences:
Figure 19 Setting Code Style preferences in Oracle JDeveloper
John’s preferred style is called JDeveloper Classic, whereas Josephine’s is Java Code Conventions. John and Josephine have a quick discussion and agree to use the JDeveloper Classic settings. John then commits his change of Hello.java to Subversion (providing a comment about what changes he made):
Figure 20 Comments for John's changes
Josephine changes her code style preferences, notices the change in the Pending Changes window’s Incoming tab, and updates her working copy with the changes:
Figure 21 Josephine updating her working copy with John's changes
As mentioned before, developers’ working copy is simply a local copy of the application on their local hard drive, so there is the possibility that two developers can work on the same file at the same time. Subversion provides a mechanism for dealing with this type of situation. There are two basic use cases: first, if one developer edits something at the beginning of a file and another developer edits something at the end of the same file, Subversion will be able to merge the changes. Subversion does this by using a simple textual comparison algorithm, so it cannot ensure that the changes are compatible but can ensure only that the changes have not “clobbered” each other by modifying the same lines. In the other use case, if two developers both edit the same lines in the same file, Subversion cannot merge the changes and will rely on the users to manually resolve the conflict. Fortunately, Oracle JDeveloper 11g includes a spiffy visual conflict resolution mechanism.
Let’s have a look at the first use case, using John and Josephine’s Hello.java file. First, John makes a simple change to the sayHello method to make it use more informal English:
Figure 22 John's "informal English" change to Hello.java
while, at the same time, Josephine makes a change to the sayGoodbye method to make it use Swahili:
Figure 23 Josephine's Swahili change to Hello.java
Josephine then commits her change to Subversion:
Figure 24 Josephine committing her Swahili changes
Now for the interesting part—when John tries to commit his change, he receives the following error message:
Figure 25 Error message informing John his copy of Hello.java is out of date
What Subversion is trying to tell him is that the repository’s version of Hello.java has been changed since he last updated it and he must update the file before he is allowed to commit. So John updates his working copy, after which Hello.java looks like this:
Figure 26 Hello.java with Josephine's changes merged into John's working copy
Note that Subversion has merged Josephine’s changes into John’s working copy automatically. Subversion was not able to tell that the changes don’t make sense together (one change is in informal English and the other in Swahili); determining if they make sense together is up to John. Let’s say for now that John thinks the changes are OK; remember that the changes are just in John’s working copy at this point and not in the repository. So John commits the revised Hello.java, providing a comment about his change only:
Figure 27 John committing the merged Hello.java file
Finally, when Josephine updates her working copy, she will have the latest version of Hello.java with both her changes and John’s.
Now let’s look at what happens when two people make changes to the same file and Subversion is not able to merge the changes automatically. Josephine edits Hello.java to look like this:
Figure 28 Josephine makes some big changes to Hello.java
while, at the same time, John edits his working copy to look like this:
Figure 29 John also makes some big changes to Hello.java
This time John commits his changes first. Now if Josephine tries to commit Hello.java, she will get the same error message about her local copy being out of date. However, when she tries to update her working copy, she will notice three things that indicate a problem. First, in the SVN Console - Log window, she will see a note of the conflict:
Figure 30 Conflict during commit shown in the Log
Second, in the Pending Changes window, her copy of the file will be marked as having conflicts:
Figure 31 Pending Changes window showing file in conflict
Finally, in the Structure window, she will notice several extra copies of Hello.java:
Figure 32 Structure window showing additional versions of Hello.java
These are files that Subversion creates to assist with resolving the conflict, but rather than requiring manual resolution of the conflicts, Oracle JDeveloper provides a nice visual merge tool, which Josephine activates by right-clicking Hello.java and selecting Resolve Conflicts:
Figure 33 Starting the visual merge tool
The visual merge tool shows Josephine’s version of the file (called Hello.java.mine) on the left, the current version from the repository (called Hello.java.r<revision number>) on the right, and the result of the merge in the center:
Figure 34 The visual merge tool showing three versions of Hello.java
The conflicting changes are clearly marked in red. To resolve the conflicts, Josephine simply selects which version of each line should appear in the final file and merges it into the center pane by clicking the appropriate green arrow (> or <). For this example, let’s say that Josephine selects her version of sayHello and John’s version of sayGoodbye. The result looks like this:
Figure 35 The visual merge tool after resolving conflicts
Now that all the conflicts have been resolved, she can click the Save and Complete Merge button to complete the operation. Once she refreshes the Application Navigator window, all of the conflict artifacts (extra versions of Hello.java) are removed and she can commit her changes to the repository in the normal way. John can now update his working copy and will see the new version of the file.
The Subversion command-line program has two commands, whimsically called praise and blame, that can be used to identify who was the last person to commit a change to each line of a file. The praise and blame commands each do the same thing; you generally use praise when you want to find out who did something interesting or elegant and blame when you’re trying to find out who introduced a bug.
Oracle JDeveloper exposes this same information in a visual fashion, using “annotations.” To view the praise/blame information, simply right-click in the editor and choose View Annotation from the Versioning submenu:
Figure 36 Showing annotations
Oracle JDeveloper will then display colored bars in the left-hand gutter; as you move your cursor over them, Oracle JDeveloper will display the following information: the developer who last committed a change to that section, the revision number of the commit, and the date of the commit:
Figure 37 Annotation showing that John authored a section of code
Now that you know the basics of how to use Subversion, let’s take a look at another common activity: “tagging.” Tagging is a process that is used to label, or tag, a copy of the source code at a specific point in time. By convention, the tagged copy is never updated and committed again; it is simply a point-in-time reference that enables you to easily get a copy of the code as it existed at that point in time. Tagging is commonly used when a version of the application is released into production so that you can easily find out which version of the code has been deployed.
Going back to our illustrious team of John and Josephine, they are ready to release their code into production after making their modifications and have elected to call this initial release Version 1.0. As part of their release, they want to tag the version of the code as v1.0, so that they know exactly which version of the code is in production and they can check out v1.0 of the code anytime for debugging. A tag in Subversion is simply a copy of the code that is put, by convention, into the “tags” directory. To create the tag, Josephine selects Branch/Tag… from the Versioning menu:
Figure 38 Selecting Branch/Tag
Oracle JDeveloper then displays a dialog box where Josephine can provide the details about the repository location to copy from and to. Josephine wants to tag the code that is her current working copy, so she leaves the default, Working Copy, for the source of the copy. To specify the destination, she specifies a new subdirectory of the tags location in the repository:
Figure 39 Specifying a location for the tag
The Switch to new branch/tag check box, if checked, will switch Josephine’s working copy to point to the tag instead of leaving it pointing to the trunk; because the convention is never to update tags, Josephine wants to leave her working copy pointing to the trunk so that she can continue working, so she does not check Switch to new branch/tag.
After Josephine clicks OK, her working copy is copied to the v1.0 tag directory. If she uses a Web browser to have a look at the repository, she will see that a copy of the code has been tagged as v1.0:
Figure 40 Newly created tag in the Subversion repository
Anytime in the future, a developer can check out a copy of the code for Version 1.0 simply by using the tag’s URL as the checkout location. A point worth noting about Subversion is that a copy of the code like this takes almost no space! Subversion simply stores a pointer to the source of the copy; as long as the copy isn’t updated, it will take almost no space.
Another common Subversion use case arises when a development team needs to create a branch of the code to make changes independently of the trunk. A common situation for creating a branch is when the team is working to stabilize the code in preparation for a production release; part of the team is assigned to find and fix bugs while the rest of the team is off working on new features for the subsequent release. The stabilization team needs to have its own branch of the code for fixing bugs independently of the trunk (which will contain new features not ready for production). As the stabilization team finds and fixes bugs, these bug fixes need to make their way back into the trunk code as well. Once the branched code is ready for production, it is tagged and deployed into production. There are other common use cases for branching that you can read about in the Version Control with Subversion e-book.
Let’s demonstrate the “stabilization for production release” use case, using Oracle JDeveloper, Subversion, and our familiar John-and-Josephine development team. John will be responsible for readying the application for the next production release (Version 1.1) while Josephine will continue developing new features for Version 2.0. The first thing John will do is create a branch called stabilization_1.1. To do so, he uses the same Branch/Tag… command that is used for tagging. There will be two major differences from the tagging use case: first, by convention, branches are placed in the Branches subdirectory in the repository. Second, because John wants to make changes to the branch, he will change his working copy to point to the branch. So, John selects Branch/Tag… and fills in the dialog box as shown here:
Figure 41 Branch/Tag dialog box showing creation of a branch
After John clicks OK, the branch is created in the repository and John’s local working copy is switched to point to the new branch. Note that the branch is just a copy of the code—any other team member can check out a working copy of the branch simply by specifying the proper URL. It’s worth noting that anyone can have multiple working copies on their local system at the same time; John, for example, could check out a copy of the trunk as well (into a new directory), and he would have a working copy pointing to the branch as well as another working copy pointing to the trunk.
Meanwhile, Josephine is off working on the trunk, adding new features for Version 2.0. I’ll not show her work here, but she has made and committed two sets of changes to the Model project. John does not see any of Josephine’s changes in the Pending Changes window, because his working copy points to the stabilization_1.1 branch while Josephine is making changes in the trunk. Now John makes a small fix to the Hello.java file to add punctuation to the messages returned:
Figure 42 John's changes to Hello.java in the stabilization branch
When John commits his changes to the branch, it is important for him to note the version number of his changes, so that he can merge them back into the trunk. Subversion 1.5 includes support for automatic tracking of merges, but Oracle JDeveloper 11g doesn’t yet have support for the Subversion 1.5 client, so John must track merges manually. John commits his working copy and notes the new revision number (17) from the SVN Console - Log window:
Figure 43 Log showing revision number 17
Note that Josephine doesn’t see John’s changes, because they occurred in the branch and Josephine is working on the trunk. For John’s changes to be merged into the trunk, it’s necessary to have a working copy pointing to the trunk. Because Josephine’s working copy already points to the trunk, let’s have her merge John’s changes. John tells Josephine that revision 17 in the branch needs to be merged into the trunk. Josephine then selects Merge… from the Versioning menu:
Figure 44 Selecting Merge
The Merge dialog box can be a bit confusing; what Merge… actually does is determine the differences between two different parts (or revisions) of the repository and apply the differences to the working copy. So to merge John’s changes (revision 17) into the trunk, Josephine needs Subversion to determine the differences between revision 17 and revision 16 (the previous revision) in the branch and apply those differences to her working copy (which points to the trunk). She therefore fills in the Merge dialog box like so:
Figure 45 Specifying options in the Merge dialog box
When she clicks the Test Merge button, Oracle JDeveloper will show her what changes will be made to her working copy (the U means that the file will be updated):
Figure 46 Results of Test Merge
After she clicks OK, John’s changes from the branch will be merged into her working copy and she can commit the changes normally. By convention, Josephine should include some descriptive text in the commit comment so that team members can tell which change or changes were merged into the trunk. Once Oracle JDeveloper supports Subversion 1.5, this tracking will happen automatically:
Figure 47 Providing a comment specifying the changeset being merged
Now, after John has stabilized the branch and it’s ready for production, he will tag the code as previously explained. He will also delete his local working copy (which points to the stabilization_1.1 branch) and check out a fresh copy of the trunk so that he can continue working on the project. A shortcut for doing this is to simply switch his working copy to the branch. He does this by selecting Switch… from the Versioning menu and supplying the location of the trunk:
Figure 48 Switching a working copy back to the trunk
Oracle JDeveloper will then update any files in John’s working copy with changes Josephine has made in the trunk and will switch the pointer in the working copy to point to the trunk. Finally, because the stabilization_1.1 branch is no longer needed, John deletes it from the repository. He does this by displaying the Versioning Navigator window:
Figure 49 Displaying the Versioning Navigator
Then he locates the branch, right-clicks it, and chooses Delete:
Figure 50 Deleting the branch
As always, John supplies a comment when performing this (or any other) operation against the repository:
Figure 51 Comment for deleting the branch
You have now seen how to use Oracle JDeveloper 11g with a Subversion repository to work in a team environment with multiple developers and multiple branches of development. In the third article in the series, you’ll discover some of the “gotchas” that can arise specifically when developers use Oracle Application Development Framework.Go to Part 3 | Back to TOC
John Stegeman ( http://stegemanoracle.wordpress.com) is an Oracle ACE Director (Oracle Fusion Middleware) and the principal architect in the EMEA region for Cambridge Solutions, a global BPO and IT services firm. He has been working with Oracle products since 1990 and with Oracle JDeveloper since Version 3.