main
1<!DOCTYPE html>
2<html lang="en">
3<head>
4<!-- Sep 03, 2024 -->
5<meta charset="utf-8" />
6<meta name="viewport" content="width=device-width, initial-scale=1" />
7<title>Gitolite quick and dirty mirror</title>
8<meta name="author" content="Vincent Demeester" />
9<meta name="generator" content="Org Mode" />
10<link rel='icon' type='image/x-icon' href='/images/favicon.ico'/>
11<meta name='viewport' content='width=device-width, initial-scale=1'>
12<link rel='stylesheet' href='/css/new.css' type='text/css'/>
13<link rel='stylesheet' href='/css/syntax.css' type='text/css'/>
14<link href='/index.xml' rel='alternate' type='application/rss+xml' title='Vincent Demeester' />
15</head>
16<body>
17<main id="content" class="content">
18<header>
19<h1 class="title">Gitolite quick and dirty mirror</h1>
20</header><section id="outline-container-Introduction" class="outline-2">
21<h2 id="Introduction">Introduction</h2>
22<div class="outline-text-2" id="text-Introduction">
23<p>
24I’m running a gitolite <span class="underline">instance</span> on my personal server to manage my repositories
25(personnal, private or public) ; and I am quickly going to share with you how I setup a
26<span class="underline">quick and dirty</span> mirror feature.
27</p>
28
29<p>
30First, I am using <b><b>gitolite 3</b></b>. The mirroring we are going to setup is not the
31<span class="underline">supported</span> <a href="http://sitaramc.github.com/gitolite/mirroring.html">mirroring <b>built-in</b></a>. We are going to implement a simplier way to set mirror
32thing :
33</p>
34
35<ol class="org-ol">
36<li>Write a custom gitolite command ; the idea is to be able to write <code>git-config</code> stuff.</li>
37<li>Write a hook that take a specific <code>git-config</code> (let say <code>mirror.url</code>) and do a simple
38mirroring.</li>
39</ol>
40</div>
41</section>
42<section id="outline-container-Gitolite%20commands" class="outline-2">
43<h2 id="Gitolite%20commands">Gitolite commands</h2>
44<div class="outline-text-2" id="text-Gitolite%20commands">
45<p>
46Gitolite 3 has been rewritten to be more flexible : <a href="http://sitaramc.github.com/gitolite/g3why.html">Why a completely new version</a>. The
47rewrite made it really easy to extend gitolite. <del>I’ve fork <a href="https://github.com/vdemeester/gitolite">gitolite</a> on github</del> I’ve
48created a <a href="http://github.com/vdemeester/vdemeester-gitolite-local-code">repository git</a> to easily add commands to my gitolite instance via <span class="underline">local
49code</span>. The gitolite command I wrote is a quick and dirty script in shell to add <code>git
50config</code>. The source should speek for itself ; It <span class="underline">should</span> include some way to check if the
51given config is not already present in the <code>gitolite-admin</code> configuration file — and so
52might be rewritten in <code>Perl</code>.
53</p>
54
55<p>
56The command is <code>write-git-config</code> because a <code>git-config</code> command already exists
57in the built-in commands.
58</p>
59
60<div class="org-src-container">
61<pre class="src src-bash">#!/bin/sh
62
63# Usage: ssh git@host write-git-config <repo> <key> <value>
64#
65# Set git-config value for user-created ("wild") repo.
66
67die() { echo "$@" >&2; exit 1; }
68usage() { perl -lne 'print substr($_, 2) if /^# Usage/../^$/' < $0; exit 1; }
69[ -z "$1" ] && [ -z "$2" ] && [ -z "$3" ] && usage
70[ "$1" = "-h" ] && usage
71[ -z "$GL_USER" ] && die GL_USER not set
72
73# ----------------------------------------------------------------------
74repo=$1; shift
75key=$1; shift
76value=$1; shift
77
78# this shell script takes arguments that are completely under the user's
79# control, so make sure you quote those suckers!
80
81if gitolite query-rc -q WRITER_CAN_UPDATE_DESC
82then
83 gitolite access -q "$repo" $GL_USER W any || die You are not authorised
84else
85 gitolite creator "$repo" $GL_USER || die You are not authorised
86fi
87
88# if it passes, $repo is a valid repo name so it is known to contain only sane
89# characters. This is because 'gitolite creator' return true only if there
90# *is* a repo of that name and it has a gl-creator file that contains the same
91# text as $GL_USER.
92
93configfile=`gitolite query-rc GL_REPO_BASE`/"$repo".git/config
94
95git config --file "$configfile" "$key" "$value"
96</pre>
97</div>
98</div>
99</section>
100<section id="outline-container-Gitolite%20hooks" class="outline-2">
101<h2 id="Gitolite%20hooks">Gitolite hooks</h2>
102<div class="outline-text-2" id="text-Gitolite%20hooks">
103<p>
104The next step is to write a quick <code>post-receive</code> hook that check if there is a
105certain <code>git-config</code> entry and run <code>git push --mirror</code>. The file is in
106<code>$HOME/.gitolite/hooks/common/post-receive</code> ; you could add a better system to
107hooks (to be able to add “dynamic” hooks, …).
108</p>
109
110<div class="org-src-container">
111<pre class="src src-bash">
112#!/bin/sh
113
114# Simple gitolite mirroring
115
116# flush STDIN coming from git, because gitolite's own post-receive.mirrorpush
117# script does the same thing
118[ -t 0 ] || cat >/dev/null
119
120[ -z "$GL_REPO" ] && die GL_REPO not set
121
122target=`git config --get mirror.url`
123[ -z "$target" ] && exit 0
124
125# Support a REPO variable for wildcard mirrors
126gl_repo_escaped=$(echo $GL_REPO | sed 's/\//\\\//g')
127target=$(echo $target | sed -e "s/REPO/$gl_repo_escaped/g")
128
129# Do the mirror push
130git push --mirror $target
131</pre>
132</div>
133
134<p>
135The next, and final step is to run `gitolite compile` to update links to hooks
136for every repositories.
137</p>
138</div>
139</section>
140<section id="outline-container-For%20real" class="outline-2">
141<h2 id="For%20real">For real</h2>
142<div class="outline-text-2" id="text-For%20real">
143<p>
144And finaly, this is the final step you’ll do.
145</p>
146
147<div class="org-src-container">
148<pre class="src src-bash">$ ssh git@host write-git-config vincent/vcsh-home mirror.url git@github.com:vdemeester/vcsh-home.git
149$ git push
150Counting objects: 5, done.
151Delta compression using up to 2 threads.
152Compressing objects: 100% (3/3), done.
153Writing objects: 100% (3/3), 294 bytes, done.
154Total 3 (delta 2), reused 0 (delta 0)
155remote: To git@github.com:vdemeester/vcsh-home.git
156remote: 65681a8..701c990 master -> master
157To git@host:vincent/vcsh-home.git
158 65681a8..701c990 master -> master
159</pre>
160</div>
161
162
163<p>
164And that should be it !
165</p>
166
167<p>
168<span class="underline">Update 2012/10/04</span> : Moved from gitolite fork to <span class="underline">gitolite local code</span>
169repository.
170</p>
171</div>
172</section>
173</main>
174<footer id="postamble" class="status">
175<footer>
176 <small><a href="/" rel="history">Index</a> • <a href="/sitemap.html">Sitemap</a> • <a href="https://dl.sbr.pm/">Files</a></small><br/>
177 <small class='questions'>Questions, comments ? Please use my <a href="https://lists.sr.ht/~vdemeester/public-inbox">public inbox</a> by sending a plain-text email to <a href="mailto:~vdemeester/public-inbox@lists.sr.ht">~vdemeester/public-inbox@lists.sr.ht</a>.</small><br/>
178 <small class='copyright'>
179 Content and design by Vincent Demeester
180 (<a rel='licence' href='http://creativecommons.org/licenses/by-nc-sa/3.0/'>Some rights reserved</a>)
181 </small><br />
182</footer>
183</footer>
184</body>
185</html>