Tutorial to synchronize org files with unison
[worg.git] / org-tutorials / unison-sync.org
1 #+TITLE:     Synchronizing org files with Unison
2 #+AUTHOR:     Alan Schmitt
3 #+EMAIL:      alan.schmitt@polytechnique.org
4 #+STARTUP:    align fold nodlcheck hidestars oddeven lognotestate
5 #+SEQ_TODO:   TODO(t) INPROGRESS(i) WAITING(w@) | DONE(d) CANCELED(c@)
6 #+TAGS:       Write(w) Update(u) Fix(f) Check(c) 
7 #+LANGUAGE:   en
8 #+PRIORITIES: A C B
9 #+CATEGORY:   worg
10 #+OPTIONS:    H:3 num:nil toc:t \n:nil @:t ::t |:t ^:t -:t f:t *:t TeX:t LaTeX:t skip:nil d:(HIDE) tags:not-in-toc
11
12 * Introduction.
13
14 This describes how to synchronize org files using the [[http://www.cis.upenn.edu/~bcpierce/unison/][Unison file synchronizer]],
15 as well as how to configure it to use an external tool to merge conflicting
16 edits.
17
18 * Prerequisites.
19
20 You should have Unison up and running. Binaries can be found [[http://www.cis.upenn.edu/~bcpierce/unison/download.html][here]] and the
21 documentation is [[http://www.cis.upenn.edu/~bcpierce/unison/download/releases/stable/unison-manual.html][here]].
22
23 * Synchronization.
24
25 Unison is a file synchronizer, thus it may be used to synchronize org files. To
26 configure Unison, one uses a /profile/ which states where the things to
27 synchronize are as well as some options. Assuming I want to synchronize the
28 files in ~/Users/schmitta/dir1~ and ~/Users/schmitta/dir2~, the profile would
29 look like this
30
31 #+BEGIN_EXAMPLE
32 root = /Users/schmitta/dir1
33 root = /Users/schmitta/dir2
34 #+END_EXAMPLE
35
36 In most cases Unison will be used with a remote machine. The local machine is
37 called the /client/ and the remote one the /server/. For such remote
38 synchronization, the ~unison~ binary must be installed in the server as
39 well. The simplest way to connect to the machine is using ssh. One should check
40 that unison can be found there by doing ~ssh user@remote unison -version~. If
41 ~unison~ cannot be found in the path, one may set the ~servercmd~ option as
42 indicated in the next example.
43
44 (Please see the [[http://www.cis.upenn.edu/~bcpierce/unison/download/releases/stable/unison-manual.html#roots][manual section on roots]] for further details.)
45
46 #+BEGIN_EXAMPLE
47 root = /Users/schmitta/dir1
48 root = ssh://user@remote/relative/path/to/dir2
49
50 servercmd = /usr/bin/unison
51 #+END_EXAMPLE
52
53 * Merging.
54
55 As Unison works on the level of files, it will trigger a /conflict/ if both
56 files have changed since the last synchronization. In that case one can only
57 choose which file to keep, which is not satisfactory. Unison offers the
58 possibility to use external tools to merge the files. There is an [[http://www.cis.upenn.edu/~bcpierce/unison/download/releases/stable/unison-manual.html#merge][extensive
59 manual section]] regarding this, we'll just describe how to use emacs and ediff to
60 do it.
61
62 For better merging, we will ask unison to keep the last synchronized version of
63 every org file on the client; this way we can use ediff with ancestor. These
64 ~currentbackup~ files may live alongside the synchronized files (with names of
65 the form ~.bak.version.name~, which is configurable) or in a central location.
66
67 Here is the modified configuration file.
68
69 #+BEGIN_EXAMPLE
70 root = /Users/schmitta/dir1
71 root = ssh://user@remote/relative/path/to/dir2
72
73 servercmd = /usr/bin/unison
74
75 backupcurrent = Name *.org
76 backuplocation = local
77 maxbackups = 0
78
79 merge = Name *.org -> emacsclient -c --eval '(ediff-merge-files-with-ancestor "CURRENT1" "CURRENT2" "CURRENTARCH" nil "NEW")'
80
81 #+END_EXAMPLE
82
83 The ~backupcurrent~ option tells unison to keep a backup of the last
84 synchronized version of every file with an ~org~ extension. The location of the
85 backup should be local (alongside the file). Finally, no other backup should be
86 created.
87
88 Next follows the merge command. For every org file in conflict, use the command
89 that launches a new emacs frame calling the ediff with ancestor function. The
90 ~CURRENT1~, ~CURRENT2~, and ~CURRENTARCH~ strings are  replaced with the file
91 from the first root, the file from the second root, and the last synchronized
92 version. The ~NEW~ file is where Unison expects the file to be saved (which will
93 be done by the ediff session).
94
95 Thus, when an org file has been modified on both hosts, an ediff session will be
96 launched in a new frame. Closing the frame will make Unison commit the merge (it
97 waits until the command has finished).
98
99 If one does not want to use backups, it's possible to use the simpler ediff
100 (without ancestor) command as follows.
101
102 #+BEGIN_EXAMPLE
103 root = /Users/schmitta/dir1
104 root = ssh://user@remote/relative/path/to/dir2
105
106 servercmd = /usr/bin/unison
107
108 merge = Name *.org -> emacsclient -c --eval '(ediff-merge-files "CURRENT1" "CURRENT2" nil "NEW")'
109
110 #+END_EXAMPLE