All the tools we saw till now were either mirroring, or backup, solutions. It was very clear that one side of the backup was the "source", and that data always moves only one way unless you're restoring from a backup because you lost something.
Unison, the last tool we will look at, is for a slightly different purpose
-- synchronising two directories that may have changes independently made on
them. It is also the only one with a GUI, and a pretty good one at that! And
a GUI is needed when synchronising, because there may be conflicts that need
to be resolved.
Yes -- you can synchronise A to B, then B to C, and back again at regular intervals, and it will have the effect of keeping A and C synchronised. Pretty cool! In this case A is a directory on my work machine, B is my USB flash disk, and C is a directory on my home machine.
Without Unison, the only way to do this easily is to work directly off the USB disk. More convoluted schemes are possible, but could be hazardous to your sanity :-)
I won't describe the batch mode at all, which should tell you how good the GUI is :-) Also, synchronisation ideally should not be batched anyway, since manual intervention may be needed.
However, Unison does have a "profile" concept which you must use in order to get the best out of the tool. The profile is a plain text file, with a fairly simple syntax, and is not at all difficult to understand.
Unison calls the pair of directories you're trying to synchronise the
synchronisation roots, and sub-directories/files within the roots are
called paths. Most of the profile is about including and excluding
paths.
[Come to think of it, this whole include/exclude business is what takes the maximum time to understand in any tool like this!]
Just type in the command. The first time, it will ask you for the names of
two directories to compare, and create a default profile for these two in your
$HOME/.unison/default.prf. If you have a .unison directory with any
.prf files in it, starting unison will give you a screen
listing all your profiles. Pick one, and start synchronising.
Make a couple of test directories in /tmp or something and practice a
little till you get used to the GUI, and the keyboard shortcuts, which are all
conveniently given next to their entries in the GUI's menu system. It's
really very, very, simple! The online help is also pretty good -- all the
documentation is available from within the program.
You can create profiles manually using any editor. I recommend this -- you can control things much better. Let's look at a few profiles now.
This is a simple one meant to transfer files between a directory on my hard disk and a USB disk:
label = sync the a780 flash disk
include default
perms = 0o0400
pretendwin = true
root = /home/sitaram/a780-backup/
root = /mnt/removable
When you start the GUI without any arguments, the label strings of all the
profiles unison found in ~/.unison are listed as choices. So put
in some descriptive text here.
The include is easy to understand. By the way, my default.prf is:
# Unison preferences file
height = 40
diff = gvim -d
This just says that I prefer to use gvim -d to be invoked when I ask the
GUI to show me the differences between two files (for example if they have
conflicting changes).
The perms and pretendwin are needed because the flash disk is a
Windows file system (VFAT) which does not support many Unix file system
semantics. Read the documentation if you want to know more.
The last two lines just say what directories I am synchronising with this profile.
Here's a somewhat more complex one. Note that, unlike rdiff-backup (but like dar), the order of ignore (exclude) and ignorenot (include) does not matter, which I like very much.
label = RC files and other settings
include default
root = /home/sitaram
root = ssh://sitaram@remote.host
# "ignore = Path something/*" works, but "ignore = Path *" doesn't
# (this is documented!)
ignore = Path ?*
ignore = Path .*
ignorenot = Path .*bashrc
ignorenot = Path .darrc
ignorenot = Path .vimrc
ignorenot = Path .sunrise
ignore = Path .sunrise/cache
gvim -d!
ignore = Name {CVS,*.cmo}
:-)
Well, we're really done, actually. However, as a bonus if you made it this far, here's a summary of most of the stuff we've seen so far, which I keep as a quick reference: Summary of tools, syntax, and notes