Table of Contents
Checking Out and Updating
How do I check out the OOFEM Subversion repository?
Note: the repository at https://www.oofem.org/svn/ is only for OOFEM developers. Non-developers should use http://www.oofem.org/svn/ instead. For browsing the repository with a web browser, use http://www.oofem.org/websvn/.
To check out the OOFEM repository, you do the following:
svn co https://www.oofem.org/svn/trunk
That will check out the whole OOFEM trunk and store it in local directory trunk.
How do I check out a specific tag?
To check out a specific tag or branch, you do:
svn co https://www.oofem.org/svn/tags/rel-1.8
This will check out the rel-1.8 release
To find out which tags and branches are available you can browse the repository via the web interface http://www.oofem.org/websvn/ or using:
svn ls https://www.oofem.org/svn/tags
How do I update my checked out version?
To update your working dir, all you have to do is run:
svn update
from inside it, just as you did with CVS.
Now that I have the source, how do I build OOFEM?
Have a look at the installation guide.
Editing Files and Committing
Editing files
Editing files with Subversion is no different than doing so with CVS.
To see which files you've edited do:
svn status
This is a very fast operation as it does not contact the remote repository (and does not bring the repository to the HEAD level).
Committing changes
The only difference you should know about is that Subversion does atomic commits, and you are encouraged to make your commits complete.
In other words, suppose you add a new file to Subversion and you update element.h. You should first svn add the new file, and then commit both it and element.h, in one go. That way, anyone doing a checkout cannot possibly get a revision in which one change had happened but not the other. To commit just do:
svn commit
Renaming and copying files and directories
One of the advantages of Subversion over CVS is that you can rename and copy files and directories without loosing the history. You simple do:
svn mv oldname.h newname.h svn commit newname.h
Reverting changes
If you want to undo some changes you've made but not yet committed, try this command:
svn revert
If you did commit your changes, you can do this:
svn merge -r COMMITTED:PREV
(type COMMITTED and PREV, in capitals, as shown).
Correcting commit log messages
If for some reason when you commit a change you don't put the proper (or complete) information into the commit log message, you can correct it. Get the revision number of the commit with the incorrect message (for example, 9915), and then:
svn propedit svn:log --revprop -r 9915 https://www.oofem.org/svn/
This will open an editor window (using $EDITOR) and let you correct your mistakes, and then commit the change. Keep in mind that these properties are unversioned, meaning once you change it, the original version is gone.
Resolving conflicts
It might happen that an svn update will update a file you just edited and that the conflicts could not be automatically resolved. In that case the file will contain conflict markers “«««<” and “»»»>” and you have to edit the file to remove the conflict. Before being able to commit this file you first have to tell svn that the conflict has been resolved:
svn resolved myfile.C
Only then can you proceed to commit the file.
Branching and Tagging
What's the difference between branches and tags in Subversion?
There are no differences between branches and tags in Subversion. In fact, Subversion doesn't even know the concept of branches or tags: everything is a file or a directory for it.
A branch or a tag is nothing more than a copy of your files under a different path. It is an O(1) operation in time and disk space, so there's no harm copying everything.
How does the OOFEM repository do branches and tags?
OOFEM uses the following scheme for its branches and tags:
- /branches: contains development, temporary branches. This is where unstable features are developed before they are merged into /trunk.
- /tags: contains all official tags. That is, when a public release is make a tag here to mark the revision in which it happened.
In /branches and /tags, the naming convention used is like this:
- /branches/branchname, (example /branches/iga-branch)
- /tags/releaseversion (example: /tags/rel-1.8)
/branches has no naming convention, but we ask you to give your branches meaningful names. Names like “my-cool-branch” aren't very descriptive, whereas “new-schema-evolution” is. Please remember to erase your work branches after you're done.
So, how do I create a branch or copy of my work?
In order to create a branch or a tag, you must have /branches or /tags checked out, even if not recursing (-N).
If your dev's directory doesn't exist yet, create it:
svn mkdir branches/mybranch
Now copy the trunk:
svn cp trunk branches/mybranch
Of course, this will include the full OOFEM, but there's no harm in doing so. Subversion's repository has a special design. When you copy a directory, you don't need to worry about the repository growing huge—Subversion doesn't actually duplicate any data.
You can also create the branch directly without having a checked-out working copy:
svn cp https://www.oofem.org/svn/trunk \ https://www.oofem.org/svn/branches/mybranch
The branch is now a identical copy of trunk, and you can check out mybranch. When you are done, you can merge the changes back to trunk. If your work takes a long time, you can easily merge changes from trunk into your working branch to stay in sync with the current development on trunk. This will also make merging your changes back to trunk much easier, as the only differences between trunk and your branch are the actual changes you have done to the branch.
You can read more about branching and merging in the book “Version Control with Subversion” in chapter four at http://svnbook.red-bean.com/en/1.4/svn.branchmerge.html.
Working with Branches
Getting information about the working directory
Where am I? I am about to check in my local files - will they end up on my branch or destroy the trunk?
You can ask your current directory what part of the subversion repository it corresponds to. svn info will tell you the directory's URL, the current revision, and when the last change occurred within the current directory:
$ svn info Path: . URL: https://www.oofem.org/svn/branches/mybranch Repository UUID: 27541ba8-7e3a-0410-8455-c3a389f83636 Revision: 19995 Node Kind: directory Schedule: normal Last Changed Author: rdm Last Changed Rev: 19824 Last Changed Date: 2007-09-19 21:46:41 +0200 (Wed, 19 Sep 2007) Properties Last Updated: 2007-09-21 17:42:53 +0200 (Fri, 21 Sep 2007)
Synchronizing a branch with the trunk
How do I merge the latest patches added to the trunk in my development branch?
First, always remember to do your merge into a working copy that has no local edits and has been recently updated. If your working copy isn't “clean” in these ways, you can run into some headaches. Assuming your working copy is tidy, merging isn't a particularly high-risk operation. If you get the merge wrong the first time, simply svn revert the changes and try again. If you've merged into a working copy that already has local modifications, the changes applied by a merge will be mixed with your pre-existing ones, and running svn revert is no longer an option. The two sets of changes may be impossible to separate.
It's time to use the svn merge command. This command, it turns out, is a very close cousin to the svn diff command (which you read about in Chapter 2, Basic Usage). Both commands are able to compare any two objects in the repository and describe the differences. The svn merge command is almost exactly the same. Instead of printing the differences to your terminal, however, it applies them directly to your working copy as local modifications.
But which two trees should be compared? At first glance, the answer may seem obvious: just compare the latest trunk tree with your latest branch tree. But beware—this assumption is wrong, and has burned many a new user! Since svn merge operates like svn diff, comparing the latest trunk and branch trees will not merely describe the set of changes you made to your branch. Such a comparison shows too many changes: it would not only show the addition of your branch changes, but also the removal of trunk changes that never happened on your branch.
To express only the changes that happened on your branch, you need to compare the initial state of your branch to its final state. Using svn log on your branch, you can see that your branch was created in revision 341. And the final state of your branch is simply a matter of using the HEAD revision. That means you want to compare revisions 341 and HEAD of your branch directory, and apply those differences to a working copy of the trunk.
A nice way of finding the revision in which a branch was created (the “base” of the branch) is to use the –stop-on-copy option to svn log. The log subcommand will normally show every change ever made to the branch, including tracing back through the copy which created the branch. So normally, you'll see history from the trunk as well. The –stop-on-copy will halt log output as soon as svn log detects that its target was copied or renamed.
So in our continuing example,
$ svn log -v --stop-on-copy \ http://www.oofem.org/svn/branches/my-branch … ------------------------------------------------------------------------ r341 | user | 2002-11-03 15:27:56 -0600 (Thu, 07 Nov 2002) | 2 lines Changed paths: A /branches/my-branch (from /trunk:340) $
As expected, the final revision printed by this command is the revision in which my-branch was created by copying. Here's the final merging procedure, then:
$ cd my-branch $ svn update At revision 405. $ svn merge -r 341:405 http://www.oofem.org/svn/trunk U integer.c U button.c U Makefile $ svn status M integer.c M button.c M Makefile # ...examine the diffs, compile, test, etc... $ svn commit -m "Merged trunk changes r341:405 into the my-branch." Sending integer.c Sending button.c Sending Makefile Transmitting file data ... Committed revision 406.
Notice that the commit log message very specifically mentions the range of changes that was merged into the trunk. Always remember to do this, because it's critical information you'll need later on. For example, suppose you decide to keep working on your branch for another week, in order to complete an enhancement to your original feature or bug fix. The repository's HEAD revision is now 480, and you're ready to do another merge from your private branch to the trunk. But as discussed in the section called “Best Practices for Merging”, you don't want to merge the changes you've already merged before; you only want to merge everything “new” on your branch since the last time you merged. The trick is to figure out what's new.
The first step is to run svn log on the trunk, and look for a log message about the last time you merged from the branch:
$ cd my-branch $ svn log … ------------------------------------------------------------------------ r406 | user | 2004-02-08 11:17:26 -0600 (Sun, 08 Feb 2004) | 1 line Merged my-branch changes r341:405 into the trunk. ------------------------------------------------------------------------ …
Aha! Since all branch-changes that happened between revisions 341 and 405 were previously merged to the trunk as revision 406, you now know that you want to merge only the branch changes after that—by comparing revisions 406 and HEAD.
$ cd my-branch $ svn update At revision 480.
# We notice that HEAD is currently 480, so we use it to do the merge:
$ svn merge -r 406:480 http://www.oofem.trunk/svn/trunk U integer.c U button.c U Makefile $ svn commit -m "Merged trunk changes r406:480 into the my-branch." Sending integer.c Sending button.c Sending Makefile Transmitting file data ... Committed revision 481.
Now the trunk contains the complete second wave of changes made to the branch. At this point, you can either delete your branch (we'll discuss this later on), or continue working on your branch and repeat this procedure for subsequent merges.
Merging a branch to the trunk
At some point, you'll be ready to merge the “synchronized” feature branch back to the trunk. To do this, begin by doing a final merge of the latest trunk changes to the branch. When that's done, the latest versions of branch and trunk will be absolutely identical except for your branch changes. So in this special case, you would merge by comparing the branch with the trunk:
$ cd trunk-working-copy $ svn update At revision 1910. $ svn merge http://www.oofem.org/svn/trunk@1910 \ http://www.oofem.org/svn/branches/my-branch@1910 U real.c U integer.c A newdirectory A newdirectory/newfile …
By comparing the HEAD revision of the trunk with the HEAD revision of the branch, you're defining a delta that describes only the changes you made to the branch; both lines of development already have all of the trunk changes.
Displaying differences
How can I check what are the differences between my working copy of a file and revision 20474?
This is simply obtained using svn diff:
$ svn diff -r 20474 src/oofemlib/element.h Index: src/oofemlib/element.h =================================================================== --- src/oofemlib/element.h (revision 20474) +++ src/oofemlib/element.h (working copy) @@ -76,8 +76,9 @@ .... #ifdef __PARALLEL_MODE +#ifndef __ENABLE_COMPONENT_LABELS globalNumber = 0; IR_GIVE_OPTIONAL_FIELD(ir, globalNumber, IFT_Element_globnum, "globnum"); // Macro +#endif
Miscellaneous
What's this PREV, HEAD, etc. stuff?
Those are symbolic revision names for Subversion, just like the normal numeric ones. They mean the following:
- HEAD: latest (youngest) revision in the server
- BASE: the revision your checkout was last updated against
- COMMITTED: last revision a file or directory was changed
- PREV: the last revision the file or directory was changed immediately before COMMITTED
Maybe this is better explained with an example:
1. You check out trunk at revision 200 2. You make a change to trunk/a_file and commit it: revision 201 is created 3. A day later, you update your working dir and find out it's now revision 208 4. You make another modification and commit: revision 209 5. One day later, you update again, this time to revision 212 6. The following day, before updating, the server has progressed to revision 218
Under those circumstances, here's what each one of those 4 mean:
- HEAD = 218
- BASE = 212
- COMMITTED (for a_file) = 209
- PREV (for a_file) = 201
When you run “svn update”, you bring BASE up to HEAD.
How do I track changes?
There are three convenient ways to track changes:
- http://www.oofem.org/websvn/rss.php?repname=oofem&path=%2F&isdir=1, real-time RSS feed of last 20 check-ins
- http://www.oofem.org/websvn/, real-time browsing of revisions
Where to get the svn client for my machine?
Subversion is by default installed on most recent Linux distributions. On Mac OS X 10.4 you can get it from Fink or from a .dmg containing pre-built binaries. On Mac OS X 10.5 svn is part of the system. On Windows you can get it from cygwin. For all other platforms see http://subversion.tigris.org/project_packages.html.
Where to find more on Subversion?
The definite information can be found on the Subversion project page http://subversion.tigris.org/ and in the online Subversion book http://svnbook.red-bean.com/. The oofem svn repository server is based on version 1.4, the corresponding version of svn book can be found here http://svnbook.red-bean.com/en/1.4