What is Subversion?
Subversion is a source code versioning tool. This means that every time you change the code or the design on your eZ Publish site, Subversion stores the change as a "version". This enables you to revert changes to your site to previous versions, and also allows you to monitor and audit changes to your site through the log files that Subversion maintains for each file.
(Subversion is also known by the abbreviation "SVN"; both terms are used interchangeably in this article.)
This article is not an in-depth discussion of the Subversion tool. For more information about Subversion, refer to the Subversion documentation at http://svnbook.red-bean.com/en/1.4/index.html.
Why should I use Subversion?
Remember the first line in the developer's ten commandments:
- Use a versioning system
The biggest benefit of using a versioning system is that you can recover from mistakes by reverting to previous code versions. Versioning systems also help with bug hunting and troubleshooting, because you can compare different code versions to discover where the bugs crept in. With a versioning system, everyone's code is stored on a shared server, making back-up simple and preventing losses caused by individual computer failures.
Versioning systems are also very useful for project management. Each time you submit a change to the versioning system, a unique number is assigned to the change. These numbers can be cross-referenced with specific bugs or with project milestones.
When I suggest to people that they use SVN, I often get these responses:
"We do not know Subversion"
If you do not know Subversion, learn how to use it. It is not difficult. In fact, most of your work is done with three simple commands:
If you are learning SVN basics the best thing you can do is to create an SVN repository to use as a sandbox. If you break something, "live" projects will not be affected.
Usually, the SVN repository is stored on a shared computer that is accessible to everyone who works on your eZ Publish projects. Individual developers use local programs ("clients") to access the source code stored on the SVN server.
The Tortoise SVN client is popular among Windows users [ http://tortoisesvn.tigris.org/]. On Mac OS the SvnX client is popular. [ http://www.lachoseinteractive.net/en/community/subversion/svnx/features/] If you are running Linux then you are probably comfortable with the command-line client. (Command-line clients are also available for Windows and Mac.)
In this article, our instructions assume you are using the command-line interface. For example, to commit changes to the repository, we instruct you to use the command "svn commit". Graphical SVN clients (like Tortoise and SvnX) have an equivalent GUI for these commands.
"A Subversion repository takes up too much space on the hard drive"
This is not an excuse. Hard drives are inexpensive. Buy a big hard drive and start using it for all your projects. Losing your work even once due to the lack of good tools will probably cost more than a hard drive.
Creating the SVN repository
To work with SVN, you must first create an SVN repository. This can be done using the "svnadmin" command.
On the server which will host the SVN repository, type this command:
svnadmin create --fs-type fsfs /path/to/the/repository
Note that you can add extra parameters to the svnadmin command. Please refer to the SVN documentation to learn more.
Creating the basic directory structure
After creating the repository, you next create a basic directory structure. If your project is called 'my project' you will have something like this:
myproject
|-- branches
|-- tags
`-- trunk
Putting your eZ Publish instance in SVN
Download the latest eZ Publish version, extract it in the 'trunk' directory and install it on your computer. You will have a result like this:
myproject
|-- branches
|-- tags
`-- trunk</span>
`-- ezpublish-4.0.0
|-- ....
This means that the eZ Publish instance is stored under the 'trunk' directory with all the default configuration for the design and connecting to the database.
Note that there are other ways to store an eZ Publish instance. Some people prefer putting all the eZ Publish code right under the 'trunk' directory. I would not recommend doing this if you plan to work with third-party systems combined with eZ Publish, such as bulletin boards, blog engines, etc.
Once you have this basic directory structure, it is time to import it into SVN. This can be with this command:
svn import -m 'initial import of the eZ Publish instance' path/to/myproject http://url/of/the/repository
This will take a few seconds, depending on your bandwith.
Once the import is finished you can check everything is OK by using the "svn list" command:
svn list http:://url/of/my/svnrepository
You should see the files you just imported.
If everything is OK then you can start working with the source code in the repository. Use the "svn checkout" command to make a local copy of the repository on your system. You now work on (and, if you like, build) your own copy of the code. When your changes are complete, use the "svn commit" command to copy your local changes back to the SVN repository.
(Delete the former local copy which you used to create the SVN repository. You shouldn't use it anymore.)
Note: If you do not want to store certain files (such as kernel, libs, translation, etc) in the repository you can use the "svn:external" property [ http://svnbook.red-bean.com/en/1.0/ch07s03.html].
How do I prevent different versions of eZ Publish cache files and log files from being stored in SVN?
Tell SVN to ignore the directories that contain the files.
You can use the "svn propset" command:
http://svnbook.red-bean.com/en/1.4/svn.ref.svn.c.propset.html
http://svnbook.red-bean.com/en/1.4/svn.advanced.props.special.ignore.html
svn propset svn:ignore "*" var/cache
svn propset svn:ignore "*" var/log
Make sure to delete all the files from the cache and log directories and make sure that the directories are no longer versioned. Do not forget to commit the change using the command "svn commit".
How can I prevent changes to the files in the kernel/ and lib/ directories?
You can either use "svn lock" or a more advanced permission system. Choose the solution that best suits your needs.
http://svnbook.red-bean.com/en/1.4/svn.ref.svn.c.lock.html
http://svnbook.red-bean.com/en/1.2/svn.serverconfig.httpd.html#svn.serverconfig.httpd.authz.perdir
Using locking is faster than using the permission system. However, the locking functionality in SVN is not as flexible as the permission system. Even though it is a littile bit more work to set up, I recommend using permissions, as that system is more powerful and flexible.
Can I use Subversion as a deployment system?
Yes!
A project can be broken down into 3 stages:
- development
- testing
- production
This means you have at least three different hosts that store eachpart of the project. The idea is to reproduce these parts in SVN branches:
myproject
|-- branches
| |-- testing
| `-- production
|-- tags
`-- trunk
`-- ezpublish-4.0.0
Development is done within the 'trunk' directory. Testing is done within the 'branches/testing' directory. Production is done within the 'branches/production' directory.
What if I have to push some new code from 'trunk' to 'testing' and from 'testing' to 'production'?
Subversion gives you a powerful tool for merging changes between branches: "svn merge" [ http://svnbook.red-bean.com/en/1.4/svn.ref.svn.c.merge.html] Let us consider a complete example:
I have developped a new piece of code located in the extension directory. Since the project is in the development phase, this piece of code is only stored in the 'trunk' directory.
Therefore I have something like this:
extension/myextension
`-- classes
`-- myfile.php
What if I want to add this feature to the test version of the project? My changes have to be added to the "testing" branch so that they end up on the test server. First I commit my new extension:
svn commit -m 'my log message' extension/myextension
Second I copy it from "trunk" to "branches/testing":
svn copy ezpublish-4.0.0/extension/myextension ../branches/testing/ezpublish-4.0.0/extension
Third I commit the changes to the 'branches/testing' directory:
svn commit -m 'my log message' ../branches/testing/ezpublish-4.0.0/extension/myextension
In the example above, I am in the "trunk" directory. If your directory structure is different than the one we suggested above, adapt these commands so that the paths resolve correctly.
What if I only want to copy one file (for example myfile.php)?
First I commit my changes:
svn commit -m 'my log message' extension/myextension/myfile.php
Second I merge my changes between the "trunk" directory and the "testing" branch.
svn merge -rX:HEAD /path/to/my/repository/trunk/ezpublish-4.0.0/extension/myextension/classes/myfile.php
... where X is the revision number of the source file and /path/to/my/repository is the URL of the repository http://path/to/my/repository for example.
Here is a complete example of the commands used to merge a file from 'trunk' to 'branches/testing':
cd /path/to/my/repository/trunk/ezpublish-4.0.0/
vi extension/myextension/classes/myfile2.php
<modifying myfile2.php>
svn commit -m 'my log message' extension/myextension/classes/myfile2.php
(the revision number is 51)
cd /path/to/my/repository/branches/testing/ezpublish-4.0.0/extension/myextension/classes/
svn merge -r51:HEAD http://path/to/my/repository/trunk/ezpublish-4.0.0/extension/myextension/classes/myfile2.php
U myfile2.php
And then I commit the changes with "svn commit".
You could also use the '-c X' argument with the "svn merge" command. An example is available in the documentation:
http://svnbook.red-bean.com/en/1.4/svn.branchmerge.copychanges.html
Note that the "svn merge" command may be confusing if you are not used to it. You may find this explanation useful:
http://svnbook.red-bean.com/nightly/en/svn.branchmerge.advanced.html#svn.branchmerge.advanced.advancedsyntax.
I have now ported my changes from the development branch to the testing branch. I can use the same technique to port my changes from testing to production by using the "testing" branch as the source and the "production" branch as the destination.
Be careful when merging. If you forget files it can take a long time to track down the problem. Also note that merging an entire directory from one branch to another can take some time.
Subversion's tag system could also be used in this scenario. (It is described here: http://svnbook.red-bean.com/en/1.4/svn.branchmerge.tags.html.) It is a matter of your own preference. For myself, I like the idea of branching and keeping things clean and separate.
How can I use Subversion and SQL?
Using SVN to version SQL Schema is a great idea. Subversion handles SQL files the same as
any other text-based file.
You can also use SVN to store definitions that cannot be exported from the eZ Publish Administration Interface. This makes sense, for example, for the permission system. If you want to export the entire permission system from one environment to another, you can create a SQL export of the "ezrole" and "ezpolicy_xx" tables and import it in another environment.
However, do not expect SVN to be able to store SQL dumps from a production environnment. Subversion is not a SQL backup tool. If you are looking for this use a replication system.
You will encouter this problem when you are using your own configuration to suit your local development environment. There are three ways to address it.
Ignoring the .ini file(s)
You can ignore a specific file (or a group of files) by using "svn propset svn:ignore". However, your environment will not be updated when ini files are changed in the repository. If the communication between your team is good then you can use this technique:
- Define an ignore flag with "svn propset".
- Do not commit this change (so that this flag is local).
- When your team warns you about an ini change remove your ignore flag (by using "svn propdel") and update the ini file(s).
You may have to deal with occasional conflicts, but this is part of the game. Resolving conflicts with SVN is easy and most conflicts can be resolved very quickly.
If you want to know more about conflict managment with SVN you will find this URL useful:
http://svnbook.red-bean.com/en/1.1/ch03s05.html#svn-ch-3-sect-5.4
Updating the versioned .ini file(s)
Another way to deal with shared .ini files in local environments is to commit and checkout versioned ini file(s), but never committing changes that are specific to an environment. However, in my opinion, this is a less secure method and more prone to error.
Using specific identifiers
When using a new configuration that you know needs to be adapted to each development environment, you can use a specific identifier in the .ini files. To indicate that the file contains environment-specific ini settings, developers append '.specific' to the end of the filename.
For example, if each developer needs to connect to his own database you could rename (using "svn rename") site.ini.append.php to site.ini.append.php.specific.
When a developer does a checkout or update of the project, he will download some .specific ini files. This will tell him that he has to rename them and update them.
Note that you can use a PHP or shell script that will automatically rename .specific files to the correct name.
If I use .specific append files how can I port them to the other branches?
You can use a build system.
Build systems are very common and provide a lot of features. Here is a list of a few build systems you might use for your projects:
Use the tool that best fits your needs.
By using a build tool you can automatically create a specific version of your application based upon the rules you have defined. This is just one example of the functionality available with build tools. It is up to you to define which tasks you want to be done in which context.
Before diving in, take time to define what you really need to build and deploy in your application. Here is a quick checklist you may find useful:
- Checking the projects out
- Giving correct database rigths to be able to create tables
- Creating the basic database schema
- Fixing the rights on this database - you might not need CREATE TABLE anymore ;)
- Fixing rights on the file system (bin/linux/modfix.sh might help you)
- Compiling templates (bin/php/eztc.php might help you)
- ...
I hope I've shown how Subversion can tremendously help you with your eZ Publish projects. The information in this article can also be applied to any other development project. Of course you will have to adapt things to your context but usually the basic concepts still apply.
I have described what I consider best practice to efficiently work with SVN. However there are a lot of different ways to work with Subversion. It is not possible to describe all the possibilities in one article - maybe even a book would not be sufficient. However the simple processes and techniques I have described should be enough to get you going with Subversion and eZ Publish.