In this article, I will describe what Subversion is and how to use it. After reading this article, you should understand how to correctly work with Subversion.
- 1 Introduction
- 2 Basic Terms
- 3 Advanced Terms
- 4 Repository Layout
- 5 Creating a Repository
- 6 SVN Workflow
- 7 Conclusion
Subversion is a tool that allows multiple developers to work together on the same project. Subversion is also a Version Control System (VCS) that keeps track of the history of files in the project. Each time a file is edited and submitted to the version control system, a copy of the new file is saved in the version control system. Using Subversion, it is always possible to revert the changed file back to a previous version of that file if somebody on your team made a mistake and that person’s changes need to be undone. Even file deletions can be reverted! If a team member deletes a file from the filesystem, that deletion can simply be undone because files can never be truly purged from the Subversion filesystem.
In this article, I will describe what Subversion is in more detail and how to work with it. In a later article, I will also show you how you can safely use Subversion together with Unity.
Before I can describe Subversion in more detail, I want to define a few terms that are important to know in order to understand Subversion.
Subversion (SVN) is the name given to the project that includes the set of tools and utilities that are required to work with a Subversion repository. Subversion is not a stand-alone product or single piece of software. It is a combination of software tools and utilities that are used to managed and use a Subversion filesystem. There are the client tools that the developer uses to work with a Subversion system and there are several server tools that are used to create, and administer a Subversion filesystem.
The Subversion filesystem is made up of several distinct parts. The files and folders that reside on the Subversion server is called the Subversion repository and the files and folders that reside on the user’s computer (or client) is called the working-copy or working-folder.
The repository is the files and folders that reside on the Subversion server. The user does not work with these files directly. Doing so might corrupt the Subversion filesystem. The repository exists on the Subversion server and it’s more like a database than a filesystem. The Subversion repository keeps track of all of the files in the project starting from the moment the repository was created. That means that all of the additions, deletions, and modifications of files and directories are stored in the repository. When a file is modified and committed to the repository, only the changes (deltas) made to that file are stored in the database. When you get the latest version of the file from the repository, the Subversion server will produce the latest file from all of the changes that were made to that file. By storing only the changes made to the file and not the entire file every time it is modified, it is possible to significantly reduce the amount of storage space that is required to keep all of the different versions of the file in the Subversion repository.
The working-copy (also called the working-folder) is a copy of the repository on the user’s computer. These files can be modified directly without the risk of corrupting the Subversion filesystem. Each person working on a project will have their own working-copy on their development computer(s). Making changes to the working-copy files and folders does not directly modify the files in the Subversion repository until the changes are committed to the repository.
The process of creating a working-copy of the Subversion repository is called a checkout and the process of saving your changes back to the Subversion repository is called a commit.
When you want to create a working-copy of a repository on your computer, you must perform a process called checkout. This process will copy all of the files and folders that exist in the repository to your computer’s hard drive.
After you have created a working-copy of the repository on your local hard drive you can start making changes to the files in the project. When you are finished making changes to the files, you will need to send those changes back to the repository. The process of sending those changes back to the repository is called a commit. You will often hear the words “don’t forget to commit!” from your project lead. It is generally a good idea to commit all of your changes to the repository at the end of the day before you go home for the evening.
Committing is also a good way to be sure that you will not lose all of the modifications that you have made that day. If you don’t commit and your hard drive on your computer suddenly fails, then there is no way to get it back. If you commit, then you know your files are safely stored in the repository.
Committing often is a good way to prevent having to repeat a lot of work in the case of a catastrophic hard drive failure.
The only exception to this rule is if you are working in a private branch and committing breaking changes will not affect anyone else’s working copy.
Each time a modification is committed to the repository, a revision of the repository is created. It is possible to examine the state of the repository at a certain moment in time by referring to the particular revision number. A newly created repository starts at revision 0 and each revision causes the repository’s revision number to increase by 1.
The HEAD revision refers to the newest revision of a file, folder or the entire repository.
The BASE revision refers to the current revision of a file or folder in your working copy. It is possible that the BASE revision of the files and folders in your working copy are not always the same as the HEAD revision.
If you are working in a large team with many people all working on the same repository, it is sometimes necessary to fetch all of the changes that have been committed to the repository by your team members. The process of getting the most recent versions of the files in the repository is called an update. It is generally a good idea to perform an update operation on your working copy every day before you start working for the day. Updating often will ensure that you are working with the latest version of the project and minimizes the amount of merging that you will have to perform later.
A merge occurs when two people have made changes to the same file. For example, Jack and Jill were both working on a file called “PailOfWater.h”. Jill commits the changes she made to “PailOfWater.h” to the repository. Later Jack tries to commit his changes to “PailOfWater.h” but he can’t because Subversion gives a nasty error that says he doesn’t have the latest version of “PailOfWater.h”. Basically, Jack breaks his crown. Now Jack has to go uphill from here and update his working copy to the latest version. Jack performs an update and Subversion says that he has a merge conflict on “PailOfWater.h”. Jack must resolve this merge conflict before he is allowed to commit the changes to the repository. Jack can resolve this conflict in one of 3 ways:
- Resolve conflict using theirs: This means that Jack is willing to lose the changes he made to the file and accept Jill’s changes.
- Resolve conflict using mine: Jack believes that the changes Jill made are insignificant and he wants to overwrite Jill’s changes with his own.
- Edit Conflicts: The best way to resolve a file conflict is by manually inspecting the file and carefully editing the file to fix the conflict. This is the only way to integrate both Jack and Jill’s changes into the file. Editing conflicts in this way is only possible on human-readable files. It is generally not possible to manually merge conflicts that occur in binary files.
Conflicts on binary files (not human readable) can only be resolved by taking one version of the other. There is no way to merge changes made to binary files. It is a good idea to try to avoid creating conflicts on binary files. This usually requires close collaboration with your teammates.
After the file has been edited, it must be marked as “resolved” to inform the Subversion client that the file is safe to commit to the repository.
If Jack is unsure how to proceed, then the best course of action is for both Jack and Jill to come together (face-to-face) to discover the best course of action. You wouldn’t want Jack to accidently overwrite Jill’s changes and have Jill come tumbling after.
Suppose you made some changes to the files in your working folder. You don’t remember exactly what you did but now something is going wrong in your copy of the project. The process to undo any (uncommitted) changes to your working copy is called a revert. Reverting the changes in your working copy will return the files and folders back to the state they were in the last time you performed an update on your working-copy.
A file conflict occurs when two people have made changes to the same file at the same time (described in the Jack and Jill example). Subversion cannot automatically merge these types of conflicts so it will always require the users to fix a file conflict using the method described above.
A tree conflict occurs if two people move, rename or delete the same file or folder. For example, Jack deletes a file named “UpTheHill.cpp” and commits the delete action to the repository. Jill hasn’t updated yet but she has made some changes to the same file that Jack deleted. When Jill updates her working folder, she will get a tree conflict on the file “UpTheHill.cpp” because it was deleted from the repository in Jack’s commit. Subversion won’t automatically delete the modifications that Jill made because that would mean that those changes Jill made would be lost forever. That would be bad so instead Subversion indicates this conflict as a tree conflict.
In a well-run project, tree conflicts should seldom occur. It is more common to have tree conflicts when multiple developers are working in separate branches and after working in isolation for some time, they try to merge their branches into the main trunk.
It can happen that your working copy can become unusable for one reason or another. The most common reason for the working copy to become unusable is when an update or commit operation is interrupted (from a power failure or a network connection error) and the SVN client is not able to unlock all of the files and folders that needed to be locked in order to perform the update or commit operation. If this happens, you will need to perform a cleanup operation on your working folder. The steps to perform a cleanup operation on your working folder will be described later.
The following terms are more advanced and beginning game developer will usually not encounter these terms in small projects.
The trunk of the Subversion repository is usually the most up-to-date (stable) version of the project. Similar to a branch, the trunk is just a folder in the subversion repository. In very large projects, each developer will work in their own personal branches. Changes to the projects need to be merged into a common testing branch. If the testing branch passes all the tests, then the final changes from the testing branch will be merged into the main trunk.
It is possible to copy an entire folder in the repository to a new location. This is useful if you want to work on a specific feature of your project in isolation from the other developers. This allows you to make potentially breaking changes to the project without affecting the rest of the team. The new folder that was copied from another location in the repository is called a branch. Once the new feature has been fully developed, it needs to be integrated into the original folder from whence it came. The process of re-integrating a branch into the original folder is called merging the branch.
Similar to a branch, a tag is a copy of a folder in the the SVN repository at a moment in time. Unlike a branch, a tag does not evolve. That means that a tag in an SVN repository represents the state of the repository at a particular moment in time and that the tag will always represent that state. This is a very important concept in release management because it provides a mechanism to create a specific release of a large software project. It is also a very good way to mark important milestones for your project (Alpha, Beta, and Final, and Master).
Although Subversion itself does not enforce any particle file structure for your Subversion repository, there is an accepted and well-known standard that is used by almost all large-scale subversion hosted projects. At the top-level (the root) of your SVN repository (or project) it is recommended to create the folders “trunk”, “branches”, and “tags”. The screenshot shows the directory layout for the Apache Subversion project itself.
Besides several other folders, they have created the folder called trunk to keep the most recent bleeding-edge (but not necessarily stable) version of the project, and a folder called branches to keep all of the feature branches that are not guaranteed to be stable in any way, and a folder called tags to keep all of the stable release tags or milestone tags. If I’m looking for the latest stable release for the Subversion project, then I would look in the tags folder because I know this folder contains all of the tagged releases of the project.
Creating a Repository
There are a few ways to create an SVN repository: free hosting, paid hosting, or do-it-yourself.
You can use one of the freely available services provided by CloudForge, SourceForge or Google Code. These services offer free accounts but some place restrictions such as limited amount of disk storage or require the project to be Open Source Software (OSS). This is only appropriate for public projects. If you are developing an open-source project, then I recommend one of these services as a place to host your codebase. In this article, I will not go into details about how to setup a Subversion repository on any of these services, but the reader is encouraged to further examine these options on their own.
There are also several paid services that allow you to setup a private SVN repository. Most of these paid services are not practical for an individual who just wants a safe place to host their projects. If you are developing a private project and you have some money to spend, then I would recommend you look at paid solutions.
For a comparison of hosting providers that offer SVN services, see http://www.svnhostingcomparison.com/.
Another option that might be attractive for the ICT nerdy types is to host your own Subversion server. This usually requires dedicated hardware, a dedicated, always-on, high-speed internet connection and a good backup solution. This may not be a solution if you don’t have the resources available. Setting up your own Subversion server is beyond the scope of this article but if you are willing and able to host your own SVN server, then I recommend you read the SVN Book which is available online here: http://svnbook.red-bean.com/.
I now assume that you have access to an SVN repository either free, or paid hosted solution, or your own personal SVN server that you setup. For the remainder of the article, I will describe the general work-flow of working with an SVN repository. For this article, I will be using the Windows program called TortoiseSVN. For the OS X user, although not free I recommend Versions client to manage your SVN working copy. For this article, I will show how to work with TortoiseSVN but the operations that you will perform with another SVN client will be the same but the steps may be different.
For the remainder of this article, I will assume you have and SVN client such as TortoiseSVN installed on your computer.
The first thing you MUST do before you can start working on your project is to perform a Checkout. Even if you just created the repository and it doesn’t contain any data, you should still perform a check-out to the folder you intend to work in.
To do this, navigate to the folder you want to store your working copy and right-click on the folder and select the “SVN Checkout…” option from the pop-up menu that appears.
Paste or type the URL of the repository you want to check-out and specify the check-out directory. TortoiseSVN will automatically fill-in the Checkout directory according to which directory you right-click to perform the checkout. For this example, I will checkout the latest version (as of this writing) of the Boost project which is an open-source project.
Click the “OK” button if the repository URL and Checkout directory are correct.
If everything is okay, you should see the progress of the checkout operation. If your repository was empty, then you should just see something like “Completed At Revision: 0“.
Simply ignore this error and select “Yes”. Then continue to Adding Files to add the files to the repository.
When you have an empty repository, the first thing you will want to do is add some files to it.
To do this, simply select the files and folders (you can select the top-level folders, you do not need to add each file in a folder individually) that you want to add to the repository and right-click and select TortoiseSVN > Add from the pop-up menu that appears.
If you are adding multiple files to the repository, then you will be presented with a confirmation dialog box. You can deselect any files that you don’t want to add to the repository.
If everything was okay, you should see the Add Finished! dialog box.
Adding files to your working copy does not automatically add the files to the repository. Before ANY changes (including additions, modifications, and deletions) are visible in the repository, you must commit them to the repository.
Deleting files from the repository is not as easy as simply deleting the file or folder from your working folder. You must inform Subversion that you intend to delete the file from the repository as well.
To delete a file or folder from the repository, right click the file(s) and/or folders that you wish to remove from the repository and select TortoiseSVN > Delete from the pop-up menu that appears.
This should cause the file or folders to disappear from your working copy. Doing this will not remove the files and folders from the repository until you perform a commit operation.
Copy, Move and Rename Files
Files that are part of a Subversion working copy cannot be simply moved or renamed using the standard methods of moving or renaming files. That is, you should not simply move or rename files in the Windows Explorer (or Finder on OS X). You must use the Subversion client to move or rename files.
To move files to another directory in a Subversion working folder, you should always right-click and drag the files or folders to their new location. When you release the right mouse button, you will see additional options to inform the SVN client that you want to move or rename these files.
Select the correct operation from the pop-up menu that appears.
Renaming files is similar. You shouldn’t just rename the files directly. Doing so will unlink the files from the Subversion repository thus breaking the version history of that folder or file.
To rename a file or folder, right-click the file or folder and select TortoiseSVN > Rename… from the pop-up menu that appears.
Type the new name for the file and press OK to rename the file.
Any changes that you make to your working copy are not automatically visible in the repository. You must always commit any changes you make to the repository.
Although it is possible to perform a commit operation on sub-folders of your project, I always recommend that you always commit changes from the root of your project. This ensures that you commit all of the changed files and folders and you don’t accidentally miss any files or folders.
To commit the changes to the Subversion repository, right-click the root folder of your working copy directory and select SVN Commit… from the pop-up menu that appears.
Make sure you always provide a useful message to describe the changes you have made during this revision. Doing this will make it easier to discover what changes have been made when.
If everything is correct, click the OK button to commit the changes to the repository.
If the commit was successful, you should see a dialog similar to the following image.
Although not strictly part of the SVN workflow, I want to show how it is possible to tell Subversion to ignore files that should never be committed to the SVN repository.
This is necessary if the tools you are using generates temporary files in your working folder.
To tell Subversion to never commit a file or folder in your working folder, right-click the file or folder you want to ignore and select TortoiseSVN > Add to ignore list.
Doing this will make sure that files and folders that should never be committed to the SVN repository don’t appear in the Commit dialog box.
In this article, I gave a brief description of Subversion and how to use it. This is a very basic introduction to Subversion. There are more things you can do with Subversion but for general use, this should get you started.