From: joey Date: Fri, 2 Jun 2006 05:32:20 +0000 (+0000) Subject: * Add support for using git instead of subversion as the RCS backend, X-Git-Url: https://sipb.mit.edu/gitweb.cgi/ikiwiki.git/commitdiff_plain/30afedcfe2799bb6cc4bf329bd273ad9d8dd6da3 * Add support for using git instead of subversion as the RCS backend, tremendous thanks to Recai Oktaş for this. * Doc updates for git. --- diff --git a/IkiWiki/Rcs/git.pm b/IkiWiki/Rcs/git.pm new file mode 100644 index 000000000..374904fd3 --- /dev/null +++ b/IkiWiki/Rcs/git.pm @@ -0,0 +1,491 @@ +#!/usr/bin/perl +# Git backend for IkiWiki. +# Copyright 2006 Recai Oktaş +# +# Licensed under the same terms as IkiWiki. + +use warnings; +use strict; +use IkiWiki; + +package IkiWiki; + +my $origin_branch = 'origin'; # Git ref for main repository +my $master_branch = 'master'; # Working branch +my $sha1_pattern = qr/[0-9a-fA-F]{40}/; # pattern to validate Git sha1sums +my $dummy_commit_msg = 'dummy commit'; # will be used in all dummy commits + # and skipped in recent changes list +my $web_commit_msg = qr/^web commit by (\w+):?(.*)/; # pattern for web commits + +sub _safe_git (&@) { #{{{ + # Start a child process safely without resorting /bin/sh. + # Return command output or success state (in scalar context). + + my ($error_handler, @cmdline) = @_; + + my $pid = open my $OUT, "-|"; + + error("Cannot fork: $!") if !defined $pid; + + if (!$pid) { + # In child. + open STDERR, ">&STDOUT" + or error("Cannot dup STDOUT: $!"); + # Git commands want to be in wc. + chdir $config{srcdir} + or error("Cannot chdir to $config{srcdir}: $!"); + exec @cmdline or error("Cannot exec '@cmdline': $!"); + } + # In parent. + + my @lines; + while (<$OUT>) { + chomp; + push @lines, $_; + } + + close $OUT; + + ($error_handler || sub { })->("'@cmdline' failed: $!") if $?; + + return wantarray ? @lines : ($? == 0); +} +# Convenient wrappers. +sub run_or_die ($@) { _safe_git(\&IkiWiki::error, @_) } +sub run_or_cry ($@) { _safe_git(sub { warn @_ }, @_) } +sub run_or_non ($@) { _safe_git(undef, @_) } +#}}} + +sub _merge_past ($$$) { #{{{ + # Unlike with Subversion, Git cannot make a 'svn merge -rN:M file'. + # Git merge commands work with the committed changes, except in the + # implicit case of '-m' of git-checkout(1). So we should invent a + # kludge here. In principle, we need to create a throw-away branch + # in preparing for the merge itself. Since branches are cheap (and + # branching is fast), this shouldn't cost high. + # + # The main problem is the presence of _uncommitted_ local changes. One + # possible approach to get rid of this situation could be that we first + # make a temporary commit in the master branch and later restore the + # initial state (this is possible since Git has the ability to undo a + # commit, i.e. 'git-reset --soft HEAD^'). The method can be summarized + # as follows: + # + # - create a diff of HEAD:current-sha1 + # - dummy commit + # - create a dummy branch and switch to it + # - rewind to past (reset --hard to the current-sha1) + # - apply the diff and commit + # - switch to master and do the merge with the dummy branch + # - make a soft reset (undo the last commit of master) + # + # The above method has some drawbacks: (1) it needs a redundant commit + # just to get rid of local changes, (2) somewhat slow because of the + # required system forks. Until someone points a more straight method + # (which I would be grateful) I have implemented an alternative method. + # In this approach, we hide all the modified files from Git by renaming + # them (using the 'rename' builtin) and later restore those files in + # the throw-away branch (that is, we put the files themselves instead + # of applying a patch). + + my ($sha1, $file, $message) = @_; + + my @undo; # undo stack for cleanup in case of an error + my $conflict; # file content with conflict markers + + eval { + # Hide local changes from Git by renaming the modified file. + # Relative paths must be converted to absolute for renaming. + my ($target, $hidden) = ( + "$config{srcdir}/${file}", "$config{srcdir}/${file}.${sha1}" + ); + rename($target, $hidden) + or error("rename '$target' to '$hidden' failed: $!"); + # Ensure to restore the renamed file on error. + push @undo, sub { + return if ! -e "$hidden"; # already renamed + rename($hidden, $target) + or debug("rename '$hidden' to '$target' failed: $!"); + }; + + my $branch = "throw_away_${sha1}"; # supposed to be unique + + # Create a throw-away branch and rewind backward. + push @undo, sub { run_or_cry('git-branch', '-D', $branch) }; + run_or_die('git-branch', $branch, $sha1); + + # Switch to throw-away branch for the merge operation. + push @undo, sub { + if (!run_or_cry('git-checkout', $master_branch)) { + run_or_cry('git-checkout','-f',$master_branch); + } + }; + run_or_die('git-checkout', $branch); + + # Put the modified file in _this_ branch. + rename($hidden, $target) + or error("rename '$hidden' to '$target' failed: $!"); + + # _Silently_ commit all modifications in the current branch. + run_or_non('git-commit', '-m', $message, '-a'); + # ... and re-switch to master. + run_or_die('git-checkout', $master_branch); + + # Attempt to merge without complaining. + if (!run_or_non('git-pull', '--no-commit', '.', $branch)) { + $conflict = readfile($target); + run_or_die('git-reset', '--hard'); + } + }; + my $failure = $@; + + # Process undo stack (in reverse order). By policy cleanup + # actions should normally print a warning on failure. + while (my $handle = pop @undo) { + $handle->(); + } + + error("Git merge failed!\n$failure\n") if $failure; + + return $conflict; +} #}}} + +sub _parse_diff_tree (@) { #{{{ + # Parse the raw diff tree chunk and return the info hash. + # See git-diff-tree(1) for the syntax. + + my ($dt_ref) = @_; + + # End of stream? + return if !defined @{ $dt_ref } || !length @{ $dt_ref }[0]; + + my %ci; + + # Header line. + HEADER: while (my $line = shift @{ $dt_ref }) { + return if $line !~ m/^diff-tree (\S+)/; + + my $sha1 = $1; + $ci{'sha1'} = $sha1; + last HEADER; + } + + # Identification lines for the commit. + IDENT: while (my $line = shift @{ $dt_ref }) { + # Regexps are semi-stolen from gitweb.cgi. + if ($line =~ m/^tree ([0-9a-fA-F]{40})$/) { + $ci{'tree'} = $1; + } elsif ($line =~ m/^parent ([0-9a-fA-F]{40})$/) { + # XXX: collecting in reverse order + push @{ $ci{'parents'} }, $1; + } elsif ($line =~ m/^(author|committer) (.*) ([0-9]+) (.*)$/) { + my ($who, $name, $epoch, $tz) = + ($1, $2, $3, $4 ); + + $ci{ $who } = $name; + $ci{ "${who}_epoch" } = $epoch; + $ci{ "${who}_tz" } = $tz; + + if ($name =~ m/^([^<]+) <([^@]+)/) { + my ($fullname, $username) = ($1, $2); + $ci{"${who}_fullname"} = $fullname; + $ci{"${who}_username"} = $username; + } else { + $ci{"${who}_fullname"} = + $ci{"${who}_username"} = $name; + } + } elsif ($line =~ m/^$/) { + # Trailing empty line signals next section. + last IDENT; + } + } + + error("No 'tree' or 'parents' seen in diff-tree output") + if !defined $ci{'tree'} || !defined $ci{'parents'}; + + $ci{'parent'} = @{ $ci{'parents'} }[0]; + + # Commit message. + COMMENT: while (my $line = shift @{ $dt_ref }) { + if ($line =~ m/^$/) { + # Trailing empty line signals next section. + last COMMENT; + }; + $line =~ s/^ //; + push @{ $ci{'comment'} }, $line; + } + + # Modified files. + FILE: while (my $line = shift @{ $dt_ref }) { + if ($line =~ m{^ + :([0-7]{6})[ ] # from mode + ([0-7]{6})[ ] # to mode + ([0-9a-fA-F]{40})[ ] # from sha1 + ([0-9a-fA-F]{40})[ ] # to sha1 + (.) # status + ([0-9]{0,3})\t # similarity + (.*) # file + $}xo) { + my ($sha1_from, $sha1_to, $file) = + ($3, $4, $7 ); + + if ($file =~ m/^"(.*)"$/) { + ($file=$1) =~ s/\\([0-7]{1,3})/chr(oct($1))/eg; + } + if (length $file) { + push @{ $ci{'details'} }, { + 'file' => $file, + 'sha1_from' => $sha1_from, + 'sha1_to' => $sha1_to, + }; + } + next FILE; + }; + last FILE; + } + + error("No detail in diff-tree output") if !defined $ci{'details'}; + + return \%ci; +} #}}} + +sub git_commit_info (;$$) { #{{{ + # Return an array of commit info hashes of num commits (default: 1) + # starting from the given sha1sum (default: HEAD). + + my ($sha1, $num) = @_; + + $num ||= 1; + + my @raw_lines = + run_or_die(qq{git-rev-list --max-count=$num $sha1 | + git-diff-tree --stdin --pretty=raw -c -M -r}); + + my @ci; + while (my $parsed = _parse_diff_tree(\@raw_lines)) { + push @ci, $parsed; + } + + return wantarray ? @ci : $ci[0]; +} #}}} + +sub git_sha1 (;$) { #{{{ + # Return head sha1sum (of given file). + + my $file = shift || q{--}; + + my ($sha1) = run_or_die('git-rev-list', '--max-count=1', 'HEAD', $file); + ($sha1) = $sha1 =~ m/($sha1_pattern)/; # sha1sum is untainted now + debug("Empty sha1sum for '$file'.") if !length $sha1; + return $sha1; +} #}}} + +sub rcs_update () { #{{{ + # Update working directory. + + run_or_cry('git-pull', $origin_branch); +} #}}} + +sub rcs_prepedit ($) { #{{{ + # Return the commit sha1sum of the file when editing begins. + # This will be later used in rcs_commit if a merge is required. + + my ($file) = @_; + + my $sha1 = git_sha1($file); + return defined $sha1 ? $sha1 : q{}; +} #}}} + +sub rcs_commit ($$$) { #{{{ + # Try to commit the page; returns undef on _success_ and + # a version of the page with the rcs's conflict markers on + # failure. + + my ($file, $message, $rcstoken) = @_; + + # XXX: Wiki directory is in the unlocked state when starting this + # action. But it takes time for a Git process to finish its job + # (especially if a merge required), so we must re-lock to prevent + # race conditions. Only when the time of the real commit action + # (i.e. git-push(1)) comes, we'll unlock the directory. + lockwiki(); + + # Check to see if the page has been changed by someone else since + # rcs_prepedit was called. + my $cur = git_sha1($file); + my ($prev) = $rcstoken =~ m/^$sha1_pattern$/; # untaint + + if (defined $cur && defined $prev && $cur ne $prev) { + my $conflict = _merge_past($prev, $file, $dummy_commit_msg); + return $conflict if defined $conflict; + } + + # git-commit(1) returns non-zero if file has not been really changed. + # so we should ignore its exit status (hence run_or_non). + if (run_or_non('git-commit', '-m', $message, '-i', $file)) { + unlockwiki(); + run_or_cry('git-push', $origin_branch); + } + + return undef; # success +} #}}} + +sub rcs_add ($) { # {{{ + # Add file to archive. + + my ($file) = @_; + + run_or_cry('git-add', $file); +} #}}} + +sub rcs_recentchanges ($) { #{{{ + # List of recent changes. + + my ($num) = @_; + + eval q{use CGI 'escapeHTML'}; + eval q{use Date::Parse}; + eval q{use Time::Duration}; + + my ($sha1, $type, $when, $diffurl, $user, @pages, @message, @rets); + INFO: foreach my $ci (git_commit_info('HEAD', $num)) { + my $title = @{ $ci->{'comment'} }[0]; + + # Skip redundant commits. + next INFO if ($title eq $dummy_commit_msg); + + $sha1 = $ci->{'sha1'}; + $type = "web"; + $when = concise(ago(time - $ci->{'author_epoch'})); + + foreach my $bit (@{ $ci->{'details'} }) { + my $diffurl = $config{'diffurl'}; + my $file = $bit->{'file'}; + + $diffurl =~ s/\[\[file\]\]/$file/go; + $diffurl =~ s/\[\[sha1_parent\]\]/$ci->{'parent'}/go; + $diffurl =~ s/\[\[sha1_from\]\]/$bit->{'sha1_from'}/go; + $diffurl =~ s/\[\[sha1_to\]\]/$bit->{'sha1_to'}/go; + + push @pages, { + link => htmllink("", pagename($file), 1), + diffurl => $diffurl, + }, + } + + push @message, { line => escapeHTML($title) }; + + if (defined $message[0] && + $message[0]->{line} =~ m/$web_commit_msg/) { + $user = "$1"; + $message[0]->{line} = $2; + } else { + $type ="git"; + $user = $ci->{'author_username'}; + } + + push @rets, { + rev => $sha1, + user => htmllink("", $user, 1), + committype => $type, + when => $when, + message => [@message], + pages => [@pages], + } if @pages; + + $sha1 = $type = $when = $diffurl = $user = undef; + @pages = @message = (); + } + + return @rets; +} #}}} + +sub rcs_notify () { #{{{ + # Send notification mail to subscribed users. + # + # In usual Git usage, hooks/update script is presumed to send + # notification mails (see git-receive-pack(1)). But we prefer + # hooks/post-update to support IkiWiki commits coming from a + # cloned repository (through command line) because post-update + # is called _after_ each ref in repository is updated (update + # hook is called _before_ the repository is updated). Since + # post-update hook does not accept command line arguments, we + # don't have an $ENV variable in this function. + # + # Here, we rely on a simple fact: we can extract all parts of the + # notification content by parsing the "HEAD" commit (which also + # triggers a refresh of IkiWiki pages) and we can obtain the diff + # by comparing HEAD and HEAD^ (the previous commit). + + my $sha1 = 'HEAD'; # the commit which triggers this action + + my $ci = git_commit_info($sha1); + if (!defined $ci) { + warn "Cannot parse info for '$sha1' commit"; + return; + } + + my @changed_pages = map { $_->{'file'} } @{ $ci->{'details'} }; + + my ($user, $message); + if (@{ $ci->{'comment'} }[0] =~ m/$web_commit_msg/) { + $user = "$1"; + $message = $2; + } else { + $user = $ci->{'author_username'}; + $message = join "\n", @{ $ci->{'comment'} }; + } + + require IkiWiki::UserInfo; + my @email_recipients = commit_notify_list($user, @changed_pages); + return if !@email_recipients; + + # TODO: if a commit spans multiple pages, this will send + # subscribers a diff that might contain pages they did not + # sign up for. Should separate the diff per page and + # reassemble into one mail with just the pages subscribed to. + my $diff = join "\n", run_or_die('git-diff', "${sha1}^", $sha1); + + my $subject = "$config{wikiname} update of "; + if (@changed_pages > 2) { + $subject .= "$changed_pages[0] $changed_pages[1] etc"; + } else { + $subject .= join " ", @changed_pages; + } + $subject .= " by $user"; + + my $template = HTML::Template->new( + filename => "$config{templatedir}/notifymail.tmpl" + ); + $template->param( + wikiname => $config{wikiname}, + diff => $diff, + user => $user, + message => $message, + ); + + eval q{use Mail::Sendmail}; + foreach my $email (@email_recipients) { + sendmail( + To => $email, + From => "$config{wikiname} <$config{adminemail}>", + Subject => $subject, + Message => $template->output, + ) or error("Failed to send update notification mail: $!"); + } +} #}}} + +sub rcs_getctime ($) { #{{{ + # Get the ctime of file. + + my ($file) = @_; + + my $sha1 = git_sha1($file); + my $ci = git_commit_info($sha1); + my $ctime = $ci->{'author_epoch'}; + debug("ctime for '$file': ". localtime($ctime) . "\n"); + + return $ctime; +} #}}} + +1 diff --git a/debian/changelog b/debian/changelog index e60eb9a3e..1f1f2a83a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -23,8 +23,11 @@ ikiwiki (1.5) UNRELEASED; urgency=low can be useful when using link-based globbing for page categorisation. * Remove preprocessor directives from inlined pages. * Allow simple preprocessor directive values to be specified w/o quotes. + * Add support for using git instead of subversion as the RCS backend, + tremendous thanks to Recai Oktaş for this. + * Doc updates for git. - -- Joey Hess Thu, 1 Jun 2006 23:47:43 -0400 + -- Joey Hess Fri, 2 Jun 2006 01:13:18 -0400 ikiwiki (1.4) unstable; urgency=low diff --git a/debian/control b/debian/control index bd3921549..a475f69e3 100644 --- a/debian/control +++ b/debian/control @@ -9,17 +9,17 @@ Standards-Version: 3.7.2 Package: ikiwiki Architecture: all Depends: ${perl:Depends}, markdown, libtimedate-perl, libhtml-template-perl, libhtml-scrubber-perl, libcgi-formbuilder-perl (>= 3.02.02), libtime-duration-perl, libcgi-session-perl, libmail-sendmail-perl, gcc | c-compiler, libc6-dev | libc-dev -Recommends: subversion, hyperestraier +Recommends: subversion | git-core, hyperestraier Suggests: viewcvs Description: a wiki compiler ikiwiki converts a directory full of wiki pages into html pages suitable for publishing on a website. Unlike many wikis, ikiwiki does not have its own means of storing page history or its own markup language. Instead it - uses subversion and markdown. + uses subversion (or git) and markdown. . ikiwiki implements all of the other standard features of a wiki, including web-based page editing, user registration and logins, a RecentChanges - page, BackLinks, search, Discussion pages, smart merging and conflict + page, BackLinks, search, Discussion pages, tags, smart merging and conflict resolution, page locking, and commit emails. . It also supports generating RSS feeds and blogging. diff --git a/doc/about_rcs_backends.mdwn b/doc/about_rcs_backends.mdwn index 197f09394..1aafd4a8e 100644 --- a/doc/about_rcs_backends.mdwn +++ b/doc/about_rcs_backends.mdwn @@ -76,9 +76,9 @@ off from R1. (To be continued.) -## [[Git]] (not yet included) +## [[Git]] -A patch with full [Git](http://git.or.cz) support is at . Regarding the patch, Recai says: +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 @@ -90,35 +90,3 @@ bugs. It also 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 mergepast for more details), so I had to invent an ugly hack just for the purpose. - -Some other notes: - -- There are two separate helper packages in git.pm. To keep things self - confined, I haven't split it up. - -- I've used a (mini) Debug.pm during the tests and made it a separate file - for the convenience of others. It relies on the "constant folding" - feature of Perl, so there shouldn't be a runtime penalty (at least this - is what the 'perl -MO=Deparse shows', haven't made a real benchmark). - -- rcs_notify() has not been implemented yet (I have noticed it after I - finished the main work). - -- GIT backend uses the gitweb for repository browsing (the counterpart of - ViewCVS). - -- There might be some subs in GIT name space which you may prefer to move to - the main code. - -- Due to the reasons explained in the code, I've written an rcs_invoke() - wrapper. May be there should be a better approach to reach the same - goal. - -- There are some parts which I may change in future, like using a global - rcs_fatal_error and the ugly error reporting code in _rcs_commit. - -- Documentation is missing. - -It works for me, but of course in the end, the final decision is yours (due -to mostly GIT quirks, the implementation is not clean as SVN). Feel free -to fix/delete/add whatever you want. Hope it doesn't have any serious bug. diff --git a/doc/features.mdwn b/doc/features.mdwn index 30fe5987b..12e9d0528 100644 --- a/doc/features.mdwn +++ b/doc/features.mdwn @@ -3,7 +3,9 @@ Some of ikiwiki's features: * [[Subversion]] Rather than implement its own system for storing page histories etc, - ikiwiki simply uses subversion. (It's also possible to [[plugins/write]] support for other systems.) + ikiwiki simply uses subversion. (It's also possible to [[plugins/write]] + support for other systems, and ikiwiki also includes support for [[Git]] + now.) Instead of editing pages in a stupid web form, you can use vim and commit changes via svn. Or work disconnected using svk and push your changes out diff --git a/doc/index.mdwn b/doc/index.mdwn index 3d10751c6..5cb4ddee3 100644 --- a/doc/index.mdwn +++ b/doc/index.mdwn @@ -2,7 +2,7 @@ ikiwiki is a **wiki compiler**. It converts a directory full of wiki pages into html pages suitable for publishing on a website. Unlike a traditional wiki, ikiwiki does not have its own means of storing page history or its own -markup language. Instead it uses [[Subversion]] and [[MarkDown]]. +markup language. Instead it uses [[Subversion]] (or [[Git]]) and [[MarkDown]]. * [[News]] is a blog (built using ikiwiki) of news items about ikiwiki. It's the best way to find out when there's a new version to [[Download]]. diff --git a/doc/post-commit.mdwn b/doc/post-commit.mdwn index 93d851959..1ce271487 100644 --- a/doc/post-commit.mdwn +++ b/doc/post-commit.mdwn @@ -1,32 +1,19 @@ -A post-commit hook is run every time you commit a change to your subversion -repository. To make the wiki be updated each time a commit is made, it can -be run from (or as) a post-commit hook. +A post-commit hook is run every time you commit a change to your +[[subversion]] (or [[git]]) repository. To make the wiki be updated each +time a commit is made, it can be run from (or as) a post-commit hook. -The best way to run ikiwiki in a [[Subversion]] post-commit hook is using -a wrapper, which can be generated using `ikiwiki --wrapper`. - -First, set up the subversion checkout that ikiwiki will update and compile -into your wiki at each subversion commit. Run ikiwiki a few times by hand -to get a feel for it. Now, generate the wrapper by adding "--wrapper" -to whatever command line you've been using to run ikiwiki. For example: - - ~/wiki-checkout> ikiwiki . ~/public_html/wiki - ~/wiki-checkout> ikiwiki . ~/public_html/wiki --wrapper - successfully generated ikiwiki-wrap +The best way to run ikiwiki in a post-commit hook is using a wrapper, which +ikiwiki is usually configured to generate using a setup file. The generated wrapper is a C program that is designed to safely be made suid if necessary. It's hardcoded to run ikiwiki with the settings specified when you ran --wrapper, and can only be used to update and compile that one checkout into the specified html directory. -Now, put the wrapper somewhere convenient, and create a post-commit hook -script in your subversion repository for the wiki. All the post-commit -hook has to do is run the wrapper (with no parameters). - -Depending on your Subversion setup, the post-commit hook might end up -getting called by users who have write access to subversion, but not to +Depending on your setup, the post-commit hook might end up +getting called by users who have write access to the repository, but not to your wiki checkout and html directory. If so, you can safely make -ikiwiki-wrap suid to a user who can write there (*not* to root!). You might +the wrapper suid to a user who can write there (*not* to root!). You might want to read [[Security]] first. [[setup]] explains setting this up in more detail. diff --git a/doc/recentchanges.mdwn b/doc/recentchanges.mdwn index 56b68273a..a40f396b6 100644 --- a/doc/recentchanges.mdwn +++ b/doc/recentchanges.mdwn @@ -1 +1,3 @@ -ikiwiki generates the list of recent changes by examining the [[Subversion]] commit log. You have to have [[CGI]] set up for this feature to be enabled. \ No newline at end of file +ikiwiki generates the list of recent changes by examining the +[[Subversion]] or [[Git]] commit log. You have to have [[CGI]] set up for +this feature to be enabled. diff --git a/doc/setup.mdwn b/doc/setup.mdwn index 7e4aaecf9..f93f71fe1 100644 --- a/doc/setup.mdwn +++ b/doc/setup.mdwn @@ -1,18 +1,28 @@ So you want to set up your own wiki using ikiwiki? This tutorial will walk -you through setting up a wiki that is stored in [[Subversion]] and that has -optional support for commits from the web. +you through setting up a wiki that is stored in [[Subversion]] or [[Git]], +and that has optional support for commits from the web. 1. [[Install]] ikiwiki. See [[download]] for where to get it. -2. Create the subversion repository for your wiki. +2. Create the master rcs repository for your wiki. + # Subversion svnadmin create /svn/wikirepo svn mkdir file:///svn/wikirepo/trunk -m create + # Git + mkdir /git/wikirepo + cd /git/wikirepo + git init-db + 3. Check out the repository to make the working copy that ikiwiki will use. + # Subversion svn co file:///svn/wikirepo/trunk ~/wikiwc + # Git + git clone /git/wikirepo ~/wikiwc + 4. Build your wiki for the first time. ikiwiki --verbose ~/wikiwc/ ~/public_html/wiki/ \ @@ -25,10 +35,18 @@ optional support for commits from the web. used if you don't have a custom version, so let's start by making a custom version of the wiki's index page: - cp /usr/share/ikiwiki/basewiki/index.mdwn ~/wikiwc - svn add ~/wikiwc/index.mdwn - $EDITOR ~/wikiwc/index.mdwn - svn commit ~/wikiwc/index.mdwn -m customised + cd ~/wikiwc + cp /usr/share/ikiwiki/basewiki/index.mdwn . + $EDITOR index.mdwn + + # Subversion + svn add index.mdwn + svn commit -m customised index.mdwn + + # Git + git add index.mdwn + git commit -m customised index.mdwn + git push origin You can also add any files you like from scratch of course. @@ -46,15 +64,15 @@ optional support for commits from the web. `doc/ikiwiki.setup` in the ikiwiki sources), and edit it. Most of the options, like `wikiname` in the setup file are the same as - ikiwiki's command line options (documented in [[usage]]. `srcdir` - and `destdir` are the two directories you specify when - running ikiwiki by hand. `svnrepo` is the path to your subversion - repository. Make sure that all of these are pointing to the right - directories, and read through and configure the rest of the file to your - liking. + ikiwiki's command line options (documented in [[usage]]. `srcdir` and + `destdir` are the two directories you specify when running ikiwiki by + hand. `rcsrepo` is the path to your master rcs repository. Make sure + that all of these are pointing to the right directories, and read + through and configure the rest of the file to your liking. - Note that the default file has a block to configure a svn wrapper. This - sets up a [[post-commit]] hook to update the wiki. + Note that the default file has a block to configure an Rcs wrapper to + update the wiki. You need to uncomment the related block for whatever + rcs you use and comment out the other rcs blocks. When you're satisfied, run `ikiwiki --setup ikiwiki.setup`, and it will set everything up and update your wiki. @@ -66,12 +84,20 @@ optional support for commits from the web. `ikiwiki --setup ikiwiki.setup`, and you're done! 9. Add [[PageHistory]] links to the top of pages. This requires you to have - setup [[ViewCVS]] or something similar to access your [[Subversion]] - repository. The `historyurl` setting makes ikiwiki add the links, and - in that url, "\[[file]]" is replaced with the name of the file to view. So - edit ikiwiki.setup and set `historyurl` to something like this: + setup a repository browser. For Subversion, you may use [[ViewCVS]] or + something similar to access your [[Subversion]] repository. For Git, + [[Gitweb]] can be used. + + The `historyurl` setting makes ikiwiki add the links, and in that url, + "\[[file]]" is replaced with the name of the file to view. So edit + ikiwiki.setup and set `historyurl` to something like this for + Subversion: `http://svn.host/trunk/\[[file]]?root=wiki` + + Or this for Git: + + `http://git.host/gitweb.cgi?p=wiki.git;a=history;f=[[file]]` Then run `ikiwiki --setup ikiwiki.setup` again. diff --git a/doc/subversion.mdwn b/doc/subversion.mdwn index 51fc5f485..47cdba450 100644 --- a/doc/subversion.mdwn +++ b/doc/subversion.mdwn @@ -1,4 +1,9 @@ Subversion is a revision control system. While ikiwiki is relatively -independant of the underlying revision control system, and can easily be used without one, using it with Subversion is recommended. +independant of the underlying revision control system, and can easily be +used without one, using it with Subversion is recommended since it's how +the author uses it. -Ikiwiki can run as a [[post-commit]] hook to update a wiki whenever commits come in. When running as a [[cgi]] with Subversion, ikiwiki automatically commits edited pages to the subversion repostory, and uses the Subversion log to generate the [[RecentChanges]] page. +Ikiwiki can run as a [[post-commit]] hook to update a wiki whenever commits +come in. When running as a [[cgi]] with Subversion, ikiwiki automatically +commits edited pages to the subversion repostory, and uses the Subversion +log to generate the [[RecentChanges]] page. diff --git a/doc/usage.mdwn b/doc/usage.mdwn index 011cf53a2..eec1856a7 100644 --- a/doc/usage.mdwn +++ b/doc/usage.mdwn @@ -46,7 +46,7 @@ These options control the mode that ikiwiki is operating in. directory. The filename to use for the wrapper is optional. The wrapper is designed to be safely made suid and be run by untrusted - users, as a [[Subversion]] [[post-commit]] hook, or as a [[CGI]]. + users, as a [[post-commit]] hook, or as a [[CGI]]. Note that the generated wrapper will ignore all command line parameters. @@ -88,14 +88,17 @@ These options configure the wiki. * --notify Enable email notification of commits. This should be used when running - ikiwiki as a [[Subversion]] [[post-commit]] hook. + ikiwiki as a [[post-commit]] hook. * --rcs=svn, --no-rcs Enable or disable use of a revision control system. - If you use svn ([[Subversion]]), the `source` directory is assumed to be - a working copy, and is automatically updated before building the wiki. + If you use svn, the `source` directory is assumed to be + a [[Subversion]] working copy. + + If you use git, the `source` directory is assumed to be a clone of the + [[git]] repository. In [[CGI]] mode, with a revision control system enabled pages edited via the web will be committed. Also, the [[RecentChanges]] link will be placed @@ -164,8 +167,8 @@ These options configure the wiki. * --plugin name - Enables the use of the specified plugin in the wiki. See [[plugins]] for - details. Note that plugin names are case sensative. + Enables the use of the specified [[plugin|plugins]] in the wiki. + Note that plugin names are case sensative. * --disable-plugin name diff --git a/doc/whyikiwiki.mdwn b/doc/whyikiwiki.mdwn index a2355d344..2bc1fe416 100644 --- a/doc/whyikiwiki.mdwn +++ b/doc/whyikiwiki.mdwn @@ -3,8 +3,13 @@ this a pretty Iky Wiki, since it's so different from other Wikis. Partly because "ikiwiki" is a nice palindrome. Partly because its design turns the usual design for a Wiki inside-out and backwards. -(BTW, I'm told that "iki" is Finnish for "forever" so ikiwiki is "forever wiki".) +(BTW, I'm told that "iki" is Finnish for "forever" so ikiwiki is "forever +wiki".) -Oh, maybe you wanted to know why you'd want to choose ikiwiki instead of all the other wikis out there? Unless your personal strangeness significantly aligns with [[Joey]]'s, so that keeping everything in subversion, compiling websites to static html, and like design [[features]] appeal to you, you probably won't. +Oh, maybe you wanted to know why you'd want to choose ikiwiki instead of +all the other wikis out there? Unless your personal strangeness +significantly aligns with [[Joey]]'s, so that keeping everything in +subversion, compiling websites to static html, and like design [[features]] +appeal to you, you probably won't. -Hmm, the above paragraph is less true today than it was when I wrote it. \ No newline at end of file +Hmm, the above paragraph is less true today than it was when I wrote it.