|Table of contents|
What is Subversion?
Subversion is a centralized system for sharing information. At its core is a repository, which is a central store of data. The repository stores information in the form of a filesystem tree—a typical hierarchy of files and directories. Any number of clients connect to the repository, and then read or write to these files. By writing data, a client makes the information available to others; by reading data, the client receives information from others.
Subversion, and software similar to it (CVS, arch, etc) are typically used to software projects to provide a central location for software developers to share their code while working on it. A developer will "check out" the latest updates to a project, work on the source code locally, then "commit" his changes back into the repository. A complete history of every modification of every file is kept onhand.
Typically, a repository is organized into directories called trunks, branches, and tags.
- A trunk, in terms of a software project, is where the "main project" lives.
- A branch, is a "fork" of a trunk. A single developer may create a branch to play with ideas without having his work affect the main trunk. When a developer is satisified with his changes, he/she can then "merge" those changes back into the trunk.
- A tag, is a snapshot of a branch or trunk on a specific day or time. With software, this may correspond to a "1.0 or 2.0" version of a product.
Of course, you don't need to organize your home directory repository into directories like this. Instead of "trunk" you could create a directory called common, and instead of branches, you could create hosts for example. In fact, I encourage the latter format when using SVN with your home directories. It just seems to make the most sense.
Benefits of SVN Homedirs
Keeping your home directory in subversion provides quite a few advantages.
- Synchronization: SVN allows you to easily synchronize common files between computers or accounts. Subversion is not the only tool for this, but is the most appropriate for some types of use, such as $HOME.
- Backups: SVN acts as a distributed backup mechanism. The best backup systems have three properties: They are easy, so you actually do the backups regularly. They are spread across several machines or locations, so a given disaster doesn't knock them out. And they are tested on a regular basis, to make sure the backup works. You will get all three, as a side effect of using subversion. Just make sure to "svn commit" every day, and you can sleep safely with the assurance that you won't lose your data. You should still probably back up the repository, so you won't lose your history, but that is merely an extra precaution.
- History: SVN provides revision control so you can retrieve older versions. This can be useful for the same reasons it helps with source code, but mostly I find I use it to "safely" delete files without worrying that I might need them again someday. If I change my mind later, I can still get the file back. It helps me keep my $HOME clean.
- Organization: Keeping your data in a repository forces you to think about how your data is organized. For example, without subversion my homedirectory becomes something of a mess quickly. While subversion won't force you to clean up your act, it becomes a nightmare to administer if you haphazardly leave files around cluttering your computer. Every file you create, or modification you make eventually becomes annotated, so you end up thinking about it's proper home. It's a good way to work.
Additionally, the approach outlined here attacks a common problem. Though you will have a lot of common files on different machines, you will also have files unique to each machine. This makes matters much more complicated. You may have a large set of files on your primary desktop, with a subset of those on your notebook, and even fewer on machines owned by clients. So, you will need a way to specify which of the common files you want on each machine. Also, each machine may have configuration which is completely unique, and you will need a way to store that sort of data.
Organizing your Homedir
There are many ways of organizing your data. I'll outline how I do it. If you think of a method superior to what I use, feel free to add it to this wiki or send me an email. While it is possible to keep your entire $home in one repository, breaking things up allows for more flexibility. My workstation at home has a layout which looks like this:
bin/ docs/ src/ temp/ .hidden/ .common/ .local/
my server has a similar layout:
bin/ html/ src/ temp/ .hidden/ .common/ .local/
Much of the above is self explanatory, but for the sake of completeness:
- docs src and html are each seperate repositories, each with a simple layout.
- .hidden is a repository that is not publicly viewable (ie: on the web). I keep config files with passwords, ssh keys, etc in here.
- .common is a repository with configuration files shared among every machine. It contains bin as well.
- .local is a repository with configuation files unique to each host.
The relationship between .hidden, .common, and .local can be a little confusing. The idea behind it is to allow configuration files to either be shared, or kept unique. What ties all of them together is the a collection of Symbolic Links, or a Symlink Farm.
The Symlink Farm
In order to make this work, most of your (dot) config files need to be symlinked to the actual file which will be kept in .common or .local. It takes a little while to do this, and requires that some tweakege. The following simple example shows a how .common and .local relate and how this works.
- First, create $HOME/.common/bash/ and copy $HOME/.bash_profile into $HOME/.common/bash/bash_profile
- Now create a symlink. (ln -s $HOME/.common/bash/bash_profile $HOME/.bash_profile
- Edit $HOME/.common/bash/bash_profile and add simple conditional test to the end of the script... eg:
if [ -f $HOME/.local/bash/bash_profile ]; then $HOME/.local/bash/bash_profile fi
As you can see, when you login, bash reads it's configuration on login in .common, and if a local configuration exists, it executes it as well. This allows you to setup a configuration environment suitable for every machine you login to - yet retain the individual settings that make your life easy on your workstation, laptop, server, etc by storing those configuration files in .local
Most programs allow you to perform tests like this, or execute include commands. In the event that this is impossible, or the configuration is only suitable for a specefic machine, simply link the config to it's place in .local.
Exeception: files you run
Most default distribution bash profiles will add $HOME/bin to your path if it exists. It's nice sometimes to be able to store scripts and binaries themselves into svn that are specific to a host or are common to all machines. The workaround I use was to make $HOME/bin a symlink to $HOME/.common/bin . I then also created $HOME/local/bin and created a symbolic link to it INSIDE of the common bin as local. So for practial purposes, $HOME/bin is my common binary directory, and $HOME/bin/local (which symlinks to $HOME/.local/bin) is my host specific binary directory.
Now that we've (hopefully) organized our homedirectories so their neat and tidy. It's time to setup subversion itself. SVN has a variety of ways of allowing access to check in and out files. You can reference a repository somewhere else on your filesystem, access subversion via apache with webdav+svn modules, access subversion repos using SSH, or simply setup subversion as a daemon without encryption and contact the service directly. I suggest using SSH.
One thing to remember though, is that if you want to use both apache and ssh, your going to have play around with permissions quite a bit in order to make things work. Various workarounds are listed at the end of this document in Tips and Tricks.
- The first step is to setup a repository on a subversion server. This is VERY easy. SSH (as yourself) into your server, create a directory for the repos. (Note: Since I keep my repos available online, I setup two directories for repos. public for web accessable data, and private for data only accessable via SSH. If your using SSH only, you can probably drop the public/private notation completely.)
- Run the following command to create a repository.
svnadmin create --fs-type fsfs /home/svn/public/homedir
- At this point, you probably need to create an initial layout for your repository with trunks, branches and tags (or common and hosts directories). You can do this manually, or simply create a dummy filestructure on your home workstation that looks like
~/tmp/homedir/common ~/tmp/homedir/hosts/ ~/tmp/homedir/hosts/host1, etc.
- Now import this tree into the repository.
cd ~/tmp/homedir ; svn import . svn+ssh://user@host:/home/svn/public/homedir
- Now nuke ~/tmp/homedir with an rm -rf, it's no longer needed.
- Import your initial set of configuration files into the repository.
svn import . svn+ssh://user@host:/home/svn/homedir/common
The procedure for setting up local configurations is almost identical. Just remember to point at svn+ssh://user@host:/home/svn/homedir/host/hostname instead of ..homedir/common.
Daily Use (One Work Cycle)
Using SVN on a daily basis is pretty simple. Just remember:
- Right after logging in, perform a "svn up" to update your repositories from subversion to your workstation before beginning work. This step is usually completely painless and quick - requiring no interaction (unless you've been naughty and haven't been performing updates).
- When you complete working on a file, add it to the repository if it's new. "svn add filename" is usually enough to the trick. If you've modified an existing file, you don't have to do anything if it's allready being tracked. You can always check that status of varying files by executing a "svn status filename (or directory)." It will show you a list of pending additions and modifications.
- At the end of the day or the work session. Execute a "svn ci". If you have made any changes, a text editor will pop up asking you to document your changes. Type in a comment, save the file and your changes will be committed to the repository.
Pretty simple! Things can become more confusing if your not dilligent about keeping everything syncronized on your machines. At that point you'll need to resolve any "conflicts" manually.