aboutsummaryrefslogtreecommitdiff
path: root/doc/rcs/details.mdwn
diff options
context:
space:
mode:
Diffstat (limited to 'doc/rcs/details.mdwn')
-rw-r--r--doc/rcs/details.mdwn292
1 files changed, 292 insertions, 0 deletions
diff --git a/doc/rcs/details.mdwn b/doc/rcs/details.mdwn
new file mode 100644
index 000000000..013ddb745
--- /dev/null
+++ b/doc/rcs/details.mdwn
@@ -0,0 +1,292 @@
+A few bits about the RCS backends
+
+[[!toc ]]
+
+## Terminology
+
+``web-edit'' means that a page is edited by using the web (CGI) interface
+as opposed to using a editor and the RCS interface.
+
+
+## [[svn]]
+
+Subversion was the first RCS to be supported by ikiwiki.
+
+### How does it work internally?
+
+Master repository M.
+
+RCS commits from the outside are installed into M.
+
+There is a working copy of M (a checkout of M): W.
+
+HTML is generated from W. rcs_update() will update from M to W.
+
+CGI operates on W. rcs_commit() will commit from W to M.
+
+For all the gory details of how ikiwiki handles this behind the scenes,
+see [[commit-internals]].
+
+You browse and web-edit the wiki on W.
+
+W "belongs" to ikiwiki and should not be edited directly.
+
+
+## [[darcs]]
+
+Regarding the repository layout: There are two darcs repositories. One is the `srcdir`, the other we'll call `master`.
+
+* HTML is generated from `srcdir`.
+* CGI edits happen in `srcdir`.
+* The backend pulls updates from `master` into `srcdir`, i.e. darcs commits should happen to `master`.
+* `master` calls ikiwiki (through a wrapper) in its apply posthook, i.e. `master/_darcs/prefs/defaults` should look like this:
+
+ apply posthook ikiwrap
+ apply run-posthook
+
+* The backend pushes CGI edits from `srcdir` back into `master` (triggering the apply hook).
+* The working copies in `srcdir` and `master` should *not* be touched by the user, only by the CGI or darcs, respectively.
+
+## [[Git]]
+
+Regarding the Git support, Recai says:
+
+I have been testing it for the past few days and it seems satisfactory. I
+haven't observed any race condition regarding the concurrent blog commits
+and it handles merge conflicts gracefully as far as I can see.
+
+(After about a year, git support is nearly as solid as subversion support --[[Joey]])
+
+As you may notice from the patch size, GIT support is not so trivial to
+implement (for me, at least). It has some drawbacks (especially wrt merge
+which was the hard part). GIT doesn't have a similar functionality like
+'svn merge -rOLD:NEW FILE' (please see the relevant comment in `_merge_past`
+for more details), so I had to invent an ugly hack just for the purpose.
+
+> I was looking at this, and WRT the problem of uncommitted local changes,
+> it seems to me you could just git-stash them now that git-stash exists.
+> I think it didn't when you first added the git support.. --[[Joey]]
+
+
+>> Yes, git-stash had not existed before. What about sth like below? It
+>> seems to work (I haven't given much thought on the specific implementation
+details). --[[roktas]]
+
+>> # create test files
+>> cd /tmp
+>> seq 6 >page
+>> cat page
+>> 1
+>> 2
+>> 3
+>> 4
+>> 5
+>> 6
+>> sed -e 's/2/2ME/' page >page.me # my changes
+>> cat page
+>> 1
+>> 2ME
+>> 3
+>> 4
+>> 5
+>> 6
+>> sed -e 's/5/5SOMEONE/' page >page.someone # someone's changes
+>> cat page
+>> 1
+>> 2
+>> 3
+>> 4
+>> 5SOMEONE
+>> 6
+>>
+>> # create a test repository
+>> mkdir t
+>> cd t
+>> cp ../page .
+>> git init
+>> git add .
+>> git commit -m init
+>>
+>> # save the current HEAD
+>> ME=$(git rev-list HEAD -- page)
+>> $EDITOR page # assume that I'm starting to edit page via web
+>>
+>> # simulates someone's concurrent commit
+>> cp ../page.someone page
+>> git commit -m someone -- page
+>>
+>> # My editing session ended, the resulting content is in page.me
+>> cp ../page.me page
+>> cat page
+>> 1
+>> 2ME
+>> 3
+>> 4
+>> 5
+>> 6
+>>
+>> # let's start to save my uncommitted changes
+>> git stash clear
+>> git stash save "changes by me"
+>> # we've reached a clean state
+>> cat page
+>> 1
+>> 2
+>> 3
+>> 4
+>> 5SOMEONE
+>> 6
+>>
+>> # roll-back to the $ME state
+>> git reset --soft $ME
+>> # now, the file is marked as modified
+>> git stash save "changes by someone"
+>>
+>> # now, we're at the $ME state
+>> cat page
+>> 1
+>> 2
+>> 3
+>> 4
+>> 5
+>> 6
+>> git stash list
+>> stash@{0}: On master: changes by someone
+>> stash@{1}: On master: changes by me
+>>
+>> # first apply my changes
+>> git stash apply stash@{1}
+>> cat page
+>> 1
+>> 2ME
+>> 3
+>> 4
+>> 5
+>> 6
+>> # ... and commit
+>> git commit -m me -- page
+>>
+>> # apply someone's changes
+>> git stash apply stash@{0}
+>> cat page
+>> 1
+>> 2ME
+>> 3
+>> 4
+>> 5SOMEONE
+>> 6
+>> # ... and commit
+>> git commit -m me+someone -- page
+
+By design, Git backend uses a "master-clone" repository pair approach in contrast
+to the single repository approach (here, _clone_ may be considered as the working
+copy of a fictious web user). Even though a single repository implementation is
+possible, it somewhat increases the code complexity of backend (I couldn't figure
+out a uniform method which doesn't depend on the prefered repository model, yet).
+By exploiting the fact that the master repo and _web user_'s repo (`srcdir`) are all
+on the same local machine, I suggest to create the latter with the "`git clone -l -s`"
+command to save disk space.
+
+Note that, as a rule of thumb, you should always put the rcs wrapper (`post-update`)
+into the master repository (`.git/hooks/`).
+
+Here is how a web edit works with ikiwiki and git:
+
+* ikiwiki cgi modifies the page source in the clone
+* git-commit in the clone
+* git push origin master, pushes the commit from the clone to the master repo
+* the master repo's post-update hook notices this update, and runs ikiwiki
+* ikiwiki notices the modifies page source, and compiles it
+
+Here is a how a commit from a remote repository works:
+
+* git-commit in the remote repository
+* git-push, pushes the commit to the master repo on the server
+* (Optionally, the master repo's pre-receive hook runs, and checks that the
+ update only modifies files that the pushing user is allowed to update.
+ If not, it aborts the receive.)
+* the master repo's post-update hook notices this update, and runs ikiwiki
+* ikiwiki notices the modifies page source, and compiles it
+
+## [[Mercurial]]
+
+The Mercurial backend is still in a early phase, so it may not be mature
+enough, but it should be simple to understand and use.
+
+As Mercurial is a distributed RCS, it lacks the distinction between
+repository and working copy (every wc is a repo).
+
+This means that the Mercurial backend uses directly the repository as
+working copy (the master M and the working copy W described in the svn
+example are the same thing).
+
+You only need to specify 'srcdir' (the repository M) and 'destdir' (where
+the HTML will be generated).
+
+Master repository M.
+
+RCS commit from the outside are installed into M.
+
+M is directly used as working copy (M is also W).
+
+HTML is generated from the working copy in M. rcs_update() will update
+to the last committed revision in M (the same as 'hg update').
+If you use an 'update' hook you can generate automatically the HTML
+in the destination directory each time 'hg update' is called.
+
+CGI operates on M. rcs_commit() will commit directly in M.
+
+If you have any question or suggestion about the Mercurial backend
+please refer to [Emanuele](http://nerd.ocracy.org/em/)
+
+## [[tla]]
+
+Nobody really understands how tla works. ;-)
+
+## rcs
+
+There is a patch that needs a bit of work linked to from [[todo/rcs]].
+
+## [[Monotone]]
+
+In normal use, monotone has a local database as well as a workspace/working copy.
+In ikiwiki terms, the local database takes the role of the master repository, and
+the srcdir is the workspace. As all monotone workspaces point to a default
+database, there is no need to tell ikiwiki explicitly about the "master" database. It
+will know.
+
+The backend currently supports normal committing and getting the history of the page.
+To understand the parallel commit approach, you need to understand monotone's
+approach to conflicts:
+
+Monotone allows multiple micro-branches in the database. There is a command,
+`mtn merge`, that takes the heads of all these branches and merges them back together
+(turning the tree of branches into a dag). Conflicts in monotone (at time of writing)
+need to be resolved interactively during this merge process.
+It is important to note that having multiple heads is not an error condition in a
+monotone database. This condition will occur in normal use. In this case
+'update' will choose a head if it can, or complain and tell the user to merge.
+
+For the ikiwiki plugin, the monotone ikiwiki plugin borrows some ideas from the svn ikiwiki plugin.
+On prepedit() we record the revision that this change is based on (I'll refer to this as the prepedit revision). When the web user
+saves the page, we check if that is still the current revision. If it is, then we commit.
+If it isn't then we check to see if there were any changes by anyone else to the file
+we're editing while we've been editing (a diff bewteen the prepedit revision and the current rev).
+If there were no changes to the file we're editing then we commit as normal.
+
+It is only if there have been parallel changes to the file we're trying to commit that
+things get hairy. In this case the current approach is to
+commit the web changes as a branch from the prepedit revision. This
+will leave the repository with multiple heads. At this point, all data is saved.
+The system then tries to merge the heads with a merger that will fail if it cannot
+resolve the conflict. If the merge succeeds then everything is ok.
+
+If that merge failed then there are conflicts. In this case, the current code calls
+merge again with a merger that inserts conflict markers. It commits this new
+revision with conflict markers to the repository. It then returns the text to the
+user for cleanup. This is less neat than it could be, in that a conflict marked
+revision gets committed to the repository.
+
+## [[bzr]]
+
+## [[cvs]]