Git_Server.mdwn 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. Web editing works now, but the only way to make changes via git is to push to
  2. the local repository stored in the ikiwiki user's home directory. We are going
  3. to decouple the git repository from ikiwiki's clone - regardless of whether they
  4. are physically on the same machine or not. Moving them around later will be
  5. easy, because the setup doesn't rely on them being on the same machine, and
  6. doesn't require them to be remote.
  7. By default, the bare master repository uses a post-update git hook, which causes
  8. it to update ikiwiki's clone whenever someone pushes an update. Ikiwiki's clone
  9. is configured to use the bare repo as its remote "origin", i.e. when a change is
  10. made via the web interface, it is pushed to the bare repo.
  11. In our new setup, the bare repo will not touch ikiwiki's clone: Instead, it will
  12. send an HTTP ping, which will cause ikiwiki to pull updates from the bare repo
  13. and regenerate HTML. And ikiwiki will access the bare repo using SSH, rather
  14. than directly using a file-based URI. Settings domain names to "localhost"
  15. allows this setup to work for a single machine setup, while remaining very
  16. flexible.
  17. I assume you already have a git server. If you don't, see the git server
  18. tutorial. I will also assume both repsitories are on the same machine, so the
  19. domain name used is 'localhost'. If you use separate remote machines, replace
  20. 'localhost' with your IP addresses or domain names. A special case is I2P:
  21. You'll need to create tunnels for it, so use 'localhost' anyway. I will use my
  22. tunnel ports here:
  23. - `localhost:8950` is a client tunnel for SSH, pointing to the SSH server on the
  24. machine where the git server is
  25. - `localhost:8951` is a client tunnel for the git protocol, pointing to the git
  26. daemon on the machine where the git server is
  27. If you don't use I2P, use your domain name (e.g.
  28. ssh://git@git.hello-world.net/wiki.git) for SSH (the port will be 22, but it's
  29. the default so you don't need to specify it) and the same (e.g.
  30. git://git.hello-world.net/wiki.git) for git daemon (the port will be 9418, but
  31. it's the default so you don't need to specify it). The domain in this example is
  32. "git.hello-world.net" but can also be "localhost" if ikiwiki and the git server
  33. are on the same machine.
  34. First, we will need to give the ikiwiki user an SSH key, with which it will pull
  35. and push to the bare repository located on the git server:
  36. # su - ikiwiki
  37. $ ssh-keygen -t rsa
  38. It will ask several questions. Use the default name for the key. Also it is
  39. __important that you use a blank password__, i.e. just press Enter when asked
  40. for a password. It is required because the key will be used from a script.
  41. Now create a new bare repository on the git server. The git server tutorial
  42. explains how to do it with Gitolite. Assume we call the new repository 'wiki'.
  43. Give the admin user RW+ access to it. You can give R access to 'daemon' and
  44. provide a description, so that it is accessible via git:// protocol and appears
  45. on Gitweb. Commit the push the change to the git server.
  46. The next step is to add the ikiwiki user. First, copy ikiwiki's public SSH key
  47. (`/home/ikiwiki/.ssh/id_rsa.pub`) to the git server, i.e. add a new user with
  48. key 'ikiwiki.pub'. The git server tutorial explains exactly how. In the same
  49. commit we will also give it the access it needs: Give user 'ikiwiki' RW access
  50. to the 'wiki' repo. Now commit and push.
  51. Now we need to tell ikiwiki to use 'wiki' as its remote origin, instead of
  52. MyWiki.git which ikiwiki generated as a default. As the ikiwiki user, open file
  53. `/home/ikiwiki/MyWiki/.git/config`. It should look more or less like this:
  54. [core]
  55. repositoryformatversion = 0
  56. filemode = true
  57. bare = false
  58. logallrefupdates = true
  59. [remote "origin"]
  60. url = /home/ikiwiki/MyWiki.git
  61. fetch = +refs/heads/*:refs/remotes/origin/*
  62. [branch "master"]
  63. merge = refs/heads/master
  64. remote = origin
  65. See the 'url' setting? We need to change it to point to the new repository we
  66. created on the git server. In my case, with I2P as described earlier, the new
  67. value is `ssh://git@localhost:8950/wiki.git`. 'git' is the name of the git user
  68. on the git server, 'localhost' is used because I have a local client tunnel
  69. pointing to the git server, 8950 is the port of the local tunnel and 'wiki.git'
  70. is there because we called the new repository 'wiki'. Gitolite appends '.git' to
  71. the names of repositories (this is a convention for bare repositories).
  72. After changing the 'url' and saving the file, it's time to test the
  73. configuration. We're not done yet, but let's make sure ikiwiki can pull and push
  74. to the new repository.
  75. As the ikiwiki user, `cd` to the srcdir repo - in our case
  76. `/home/ikiwiki/MyWiki` - and try to `git push origin master`. You will probably
  77. be asked about the authenticity of the SSH server - check the fingerprint if you
  78. want ([[TODO|TODO/OPEN]] how?). Once you accept the SSH server, the push operation
  79. should work. A new 'master' branch will be created on the 'wiki' repo.
  80. # su - ikiwiki
  81. $ cd MyWiki
  82. $ git push origin master
  83. Now try pulling. It should say "everything is up to date". On your personal
  84. computer - assuming you gave yourself RW (or RW+) access to 'wiki' - clone the
  85. 'wiki' repository, make some trivial change to the index page (index.mdwn should
  86. already be in the repository because you made edits via the web interface
  87. earlier) and push them. Now, as the ikiwiki user on the machine where ikiwiki is
  88. located, try `git pull` to make sure you receive the change.
  89. $ git pull
  90. Both pulling and pushing should work without user interaction - no password
  91. requested, etc. They both will be used from a script, so it's important.
  92. As the ikiwiki user, open the setup file - in our case
  93. `/home/ikiwiki/MyWiki.setup`. Under the git plugin settings, find the line
  94. defining 'git_wrapper'. It should look more or less like this:
  95. # git plugin
  96. # git hook to generate
  97. git_wrapper: /home/ikiwiki/MyWiki.git/hooks/post-update
  98. # shell command for git_wrapper to run, in the background
  99. #git_wrapper_background_command: git push github
  100. Since the bare repository will not be pushing to ikiwiki anymore, disable the
  101. git_wrapper by prepending a '#' sign to its line (this will turn it into a
  102. comment).
  103. Now, tell ikiwiki to push to the 'wiki' repository when a change is done via the
  104. web interface by uncommenting the `git_wrapper_backgroud_command` line and
  105. setting the command to `git push`. This section of the file should now look like
  106. this:
  107. # git plugin
  108. # git hook to generate
  109. #git_wrapper: /home/ikiwiki/MyWiki.git/hooks/post-update
  110. # shell command for git_wrapper to run, in the background
  111. git_wrapper_background_command: git push
  112. In order to tell ikiwiki to listen to pings from the git server and rebuild the
  113. web pages, enable the 'pingee' plugin by adding it under the add_plugins
  114. variable. It should look more or less like this:
  115. add_plugins:
  116. - goodstuff
  117. - websetup
  118. - pingee
  119. Now rebuild the wiki, so it takes the new setup into account:
  120. $ ikiwiki --setup MyWiki.setup --rebuild --verbose
  121. Once side of our new setup now should work: Whenever a change is made to the
  122. wiki via the web interface, it should push it to the git server. You can test it
  123. by making a change, and then pulling in your personal clone and make sure you
  124. received the change. The other direction doesn't work yet: Ikiwiki can pull, but
  125. it doesn't know when. We are going to tell the git server to ping ikiwiki
  126. whenever a change is made via a personal clone (i.e. not the web interface).
  127. On the git server machine, as the git user, go to the hooks folder of the 'wiki'
  128. repository. A typical path would be `/home/git/repositories/wiki.git/hooks`.
  129. Create a new file named `post-receive`. This file is a script which will be
  130. executed whenever a new commit it received. The first line should be the shebang
  131. `!#/bin/sh`, then you can add a comment (a comment line starts with `#`) and
  132. finally the command itself. We'll need to tell the git server to send a ping to
  133. ikiwiki.
  134. If you use I2P or Tor, you need to tell the git server to use a proxy to access
  135. ikiwiki, because otherwise it cannot access .onion websites or .i2p eepsites. If
  136. you use the typical port 4444 as the I2P HTTP proxy, you can set the proxy like
  137. this:
  138. export http_proxy="http://localhost:4444/"
  139. If you use privoxy (I use it), specify the privoxy port instead (usualy 8118):
  140. export http_proxy="http://localhost:8118/"
  141. If you use the clearnet (regular internet), you don't need the proxy.
  142. Now, the command itself. Basically, we'll use a call to 'wget' (time to install
  143. it if you haven't yet) which will trigger the ping, and direct the returned
  144. result to /dev/null because we don't need it - when you push from a personal
  145. clone, you'll still see the feedback from the git server, so you'll know the
  146. ping was sent successfully. The wget invocation looks like this, with the URL
  147. being the public URL of the ikiwiki instance:
  148. wget "http://partager.i2p/ikiwiki.cgi?do=ping" -O /dev/null
  149. However, this is not enough: We need to ping ikiwiki only if the commit was made
  150. from somewhere else, otherwise we will cause ikiwiki to pull again, while the
  151. git server isn't done updating its own repository yet with the commit sent by
  152. ikiwiki. There are two ways to check where the commit came from:
  153. - When a commit is made via the web, the author email ends with '@web' or is the
  154. ikiwiki user itself
  155. - If you use Gitolite, it tells you the name of the committer user via the
  156. 'GL_USER' variable
  157. The second option is better if you use gitolite, because the first one has a
  158. corner case where it may not work: If you push commits you created on a local
  159. ikiwiki clone via local CGI, the author email would contain '@web' as well. If
  160. this use case is relevant to you, you can try to cross the author email with the
  161. committer email. Maybe it will then cover this case - I didn't try.
  162. For the first case, the author test looks like this:
  163. git log -1 --format=format:%ae HEAD | grep -e '@web$' -e 'ikiwiki@HOST'
  164. Just change HOST to the hostname of the machine where ikiwiki runs. The
  165. 'ikiwiki' before the @ is the name of the ikiwiki user we created. To be sure,
  166. you can check the author of the first commit made to your wiki. This should be
  167. the ikiwiki user. You can determine this by running `git log --format=format:%ae
  168. HEAD` on any wiki clone (or on the 'wiki' bare repo itself) and looking at the
  169. last email in the list.
  170. For the second case, the test looks like this:
  171. [ x"$GL_USER" = x"ikiwiki" ]
  172. "ikiwiki" here is the name of the Gitolie-registered user who made the commit.
  173. The user name comes from the filename of the SSH key. For example, if you added
  174. ikiwiki's SSH key to Gitolite as 'ikiwiki.pub', the username to test here is
  175. "ikiwiki".
  176. Now use `||` to combine the test and the ping: If the commit does *not* come
  177. from ikiwiki, then send the ping. Using the first case, it looks like this
  178. (again, replace HOST with the correct hostname):
  179. git log -1 --format=format:%ae HEAD | grep -e '@web$' -e 'ikiwiki@HOST' || \
  180. wget "http://partager.i2p/ikiwiki.cgi?do=ping" -O /dev/null
  181. And for the second case it looks like this:
  182. [ x"$GL_USER" = x"ikiwiki" ] || wget "http://partager.i2p/ikiwiki.cgi?do=ping" -O /dev/null
  183. Here's a full example, using Gitolite (second case) and an I2P address for
  184. pinging accessed via Privoxy:
  185. #!/bin/sh
  186. ## special hook for ikiwiki repo:
  187. ## update the srcdir clone (which will regenerate HTML),
  188. ## if a commit not-from-ikiwiki was received
  189. ## (if it's from ikiwiki, it already has it so no need
  190. ## to update it... that would cause a deadlock)
  191. ## "ikiwiki" here is the gitolite-registered user (i.e.
  192. ## username determined by SSH key name, e.g. ikiwiki.pub)
  193. ## from which the push came
  194. export http_proxy="http://localhost:8118/"
  195. [ x"$GL_USER" = x"ikiwiki" ] || wget "http://partager.i2p/ikiwiki.cgi?do=ping" -O /dev/null
  196. Save the file. git won't use it unless it is executable, so we need to update
  197. permissions. These are the command for the last step, and the last command is
  198. the permission change (makes our hook executable):
  199. # su - git
  200. $ cd repositories/wiki.git/hooks
  201. $ nano post-receive
  202. $ chmod 750 post-receive
  203. Time to test the new setup. Using a personal clone, push change and make sure
  204. the HTML gets updated automatically. Then, just to be sure, you can try again to
  205. make a web edit and make sure it got pushed by pulling in my personal clone and
  206. seeing the update.
  207. Done. You can delete the old bare repository ikiwiki created, to avoid confusion
  208. later:
  209. # su - ikiwiki
  210. $ rm -rf MyWiki.git
  211. Congratulations! You have a new working ikiwiki!