From bbaacfaee72f1f6b58defa0a0f64a56b504222ec Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Mon, 9 Apr 2012 07:31:33 +0530 Subject: [PATCH] (mostly) doc changes - minor typo fixes, clarifications, etc. - keep sts.html url consistent, because many people link to http://sitaramc.github.com/gitolite/sts.html - create a common migration doc, so the old 'migr.html' does not 404 when g3 docs become "main" - progit doc done - add gitosis convert script (FWIW) - a minor comment fix to Sugar.pm --- convert-gitosis-conf | 124 +++++++++++++ .../{gitolite-and-ssh.mkd => glssh.mkd} | 0 .../{ssh-troubleshooting.mkd => sts.mkd} | 0 doc/gsmigr.mkd | 126 +++++++++++++ doc/migr.mkd | 6 + doc/mirroring.mkd | 2 +- doc/non-core.mkd | 9 + doc/progit.mkd | 166 ++++++++++++++++++ doc/users.mkd | 2 +- doc/wild.mkd | 3 +- src/lib/Gitolite/Conf/Sugar.pm | 4 +- 11 files changed, 437 insertions(+), 5 deletions(-) create mode 100755 convert-gitosis-conf rename doc/extras/{gitolite-and-ssh.mkd => glssh.mkd} (100%) rename doc/extras/{ssh-troubleshooting.mkd => sts.mkd} (100%) create mode 100644 doc/gsmigr.mkd create mode 100644 doc/migr.mkd create mode 100644 doc/progit.mkd diff --git a/convert-gitosis-conf b/convert-gitosis-conf new file mode 100755 index 0000000..999f8f7 --- /dev/null +++ b/convert-gitosis-conf @@ -0,0 +1,124 @@ +#!/usr/bin/perl -w +# +# migrate gitosis.conf to gitolite.conf format +# +# Based on gl-conf-convert by: Sitaram Chamarty +# Rewritten by: Behan Webster +# + +use strict; +use warnings; + +if (not @ARGV and -t or @ARGV and $ARGV[0] eq '-h') { + print "Usage:\n gl-conf-convert < gitosis.conf > gitolite.conf\n(please see the documentation for details)\n"; + exit 1; +} + +my @comments = (); +my $groupname; +my %groups; +my $reponame; +my %repos; + +while (<>) +{ + # not supported + if (/^repositories *=/ or /^map /) { + print STDERR "not supported: $_"; + s/^/NOT SUPPORTED: /; + print; + next; + } + + # normalise whitespace to help later regexes + chomp; + s/\s+/ /g; + s/ ?= ?/ = /; + s/^ //; + s/ $//; + + if (/^\s*$/ and @comments > 1) { + @{$repos{$reponame}{comments}} = @comments if $reponame; + @{$groups{$groupname}{comments}} = @comments if $groupname; + @comments = (); + } elsif (/^\s*#/) { + push @comments, $_; + } elsif (/^\[repo\s+(.*?)\]$/) { + $groupname = ''; + $reponame = $1; + $reponame =~ s/\.git$//; + } elsif (/^gitweb\s*=\s*yes/i) { + push @{$repos{$reponame}{R}}, 'gitweb'; + } elsif (/^daemon\s*=\s*yes/i) { + push @{$repos{$reponame}{R}}, 'daemon'; + } elsif (/^description\s*=\s*(.+?)$/) { + $repos{$reponame}{desc} = $1; + } elsif (/^owner\s*=\s*(.+?)$/) { + $repos{$reponame}{owner} = $1; + } elsif (/^\[group\s+(.*)\]$/) { + $reponame = ''; + $groupname = $1; + } elsif (/^members\s*=\s*(.*)/) { + push @{$groups{$groupname}{users}}, map {s/\@([^.]+)$/_$1/g; $_} split(' ', $1); + } elsif (/^write?able\s*=\s*(.*)/) { + foreach my $repo (split(' ', $1)) { + $repo =~ s/\.git$//; + push @{$repos{$repo}{RW}}, "\@$groupname"; + } + } elsif (/^readonly\s*=\s*(.*)/) { + foreach my $repo (split(' ', $1)) { + $repo =~ s/\.git$//; + push @{$repos{$repo}{R}}, "\@$groupname"; + } + } +} + +#use Data::Dumper; +#print Dumper(\%repos); +#print Dumper(\%groups); + +# Groups +print "#\n# Groups\n#\n\n"; +foreach my $grp (sort keys %groups) { + next unless @{$groups{$grp}{users}}; + printf join("\n", @{$groups{$grp}{comments}})."\n" if $groups{$grp}{comments}; + printf "\@%-19s = %s\n", $grp, join(' ', @{$groups{$grp}{users}}); +} + +# Gitweb +print "\n#\n# Gitweb\n#\n\n"; +foreach my $repo (sort keys %repos) { + if ($repos{$repo}{desc}) { + @{$repos{$repo}{R}} = grep(!/^gitweb$/, @{$repos{$repo}{R}}); + print $repo; + print " \"$repos{$repo}{owner}\"" if $repos{$repo}{owner}; + print " = \"$repos{$repo}{desc}\"\n"; + } +} + +# Repos +print "\n#\n# Repos\n#\n"; +foreach my $repo (sort keys %repos) { + print "\n"; + printf join("\n", @{$repos{$repo}{comments}})."\n" if $repos{$repo}{comments}; + #if ($repos{$repo}{desc}) { + # @{$repos{$repo}{R}} = grep(!/^gitweb$/, @{$repos{$repo}{R}}); + #} + print "repo\t$repo\n"; + foreach my $access (qw(RW+ RW R)) { + next unless $repos{$repo}{$access}; + my @keys; + foreach my $key (@{$repos{$repo}{$access}}) { + if ($key =~ /^\@(.*)/) { + next unless defined $groups{$1} and @{$groups{$1}{users}}; + } + push @keys, $key; + } + printf "\t$access\t= %s\n", join(' ', @keys) if @keys; + } + #if ($repos{$repo}{desc}) { + # print $repo; + # print " \"$repos{$repo}{owner}\"" if $repos{$repo}{owner}; + # print " = \"$repos{$repo}{desc}\"\n"; + #} +} diff --git a/doc/extras/gitolite-and-ssh.mkd b/doc/extras/glssh.mkd similarity index 100% rename from doc/extras/gitolite-and-ssh.mkd rename to doc/extras/glssh.mkd diff --git a/doc/extras/ssh-troubleshooting.mkd b/doc/extras/sts.mkd similarity index 100% rename from doc/extras/ssh-troubleshooting.mkd rename to doc/extras/sts.mkd diff --git a/doc/gsmigr.mkd b/doc/gsmigr.mkd new file mode 100644 index 0000000..72bc357 --- /dev/null +++ b/doc/gsmigr.mkd @@ -0,0 +1,126 @@ +# migrating from gitosis to gitolite + +[2012-04-09] Modified for gitolite g3. These instructions have not really +been tested with g3, but are expected to work. + +Migrating from gitosis to gitolite is fairly easy, because the basic design is +the same. + +There's only one thing that might trip up people: the userid. Gitosis uses +`gitosis`. Gitolite can use any userid you want; most of the documentation +uses `git`, while DEB/RPM packages use `gitolite`. + +Here are the steps on the server: + + * (as 'gitosis' on the server) **Rename** `~/.ssh/authorized_keys` to + something else so that no one can accidentally push while you're doing + this. + + * (as 'gitosis' on the server) For added safety, **delete** the post-update + hook that gitosis-admin installed + + rm ~/repositories/gitosis-admin.git/hooks/post-update + + or at least rename it to `.sample` like all the other hooks hanging + around, or edit it and comment out the line that calls `gitosis-run-hook + post-update`. + + * (as 'gitosis' on the server) If you already use the `update` hook for some + reason, you'll have to make that a [VREF][vref]. This is because gitolite + uses the update hook for checking write access. + + * (as 'root' on the server) copy all of `~/repositories` to the gitolite + hosting user's home directory. Something like + + cp -a /home/gitosis/repositories /home/git + chown -R git.git /home/git/repositories + + * (as 'root' and/or 'git' on the server) Follow instructions to install + gitolite; see the [install document][install]. + + This will give you a gitolite config that has the required entries for the + "gitolite-admin" repo. + +Now, log off the server and get back to the client. All subsequent +instructions are to be read as "on gitolite admin's workstation". + + * **clone** the new gitolite-admin repo to your workstation. (You already + have a clone of the gitosis-admin repo so now you have both). + + * **convert** your gitosis config file and append it to your gitolite config + file. Substitute the path for your gitosis-admin clone in `$GSAC` below, + and similarly the path for your gito**lite**-admin clone in `$GLAC`. (The + convert-gitosis-conf program is a standalone program that you can bring + over from any gitolite clone; you don't have to install all of gitolite on + your workstation to use this): + + ./convert-gitosis-conf < $GSAC/gitosis.conf >> $GLAC/conf/gitolite.conf + + **Be sure to check the file to make sure it converted correctly** -- due + it's "I only need it once" nature, this program has not received too much + attention from anyone! + + * Remove the entry for the 'gitosis-admin' repo. You do not need it here + and it may cause confusion. + + * **copy** the keys from gitosis's keydir (same meanings for GSAC and GLAC) + + cp $GSAC/keydir/* $GLAC/keydir + + If your gitosis-admin key was `you@machine.pub`, and you supplied the same + one to gitolite's gl-setup program as `you.pub` when you installed + gitolite, then you should remove `you@machine.pub` from the new keydir + now. Otherwise you will have 2 pubkey files (`you.pub` and + `you@machine.pub`) which are identical, which is *not* a good idea. + + Similarly, you should replace all occurrences of `you@machine.pub` with + `you` in the `conf/gitolite.conf` file. + + * **IMPORTANT**: if you have any users with names like `user@foo`, where the + part after the `@` does *not* have a `.` in it (i.e., does not look like + an email address), you need to change them, because gitolite uses that + syntax for [enabling multi keys][multi-key]. + + You have two choices in how to fix this. You can change the gitolite + config so that all mention of `user@foo` is changed to just `user`. + + Or you can change each occurrence of `user@foo` to, say, `user_foo` *and* + change the pubkey filename in keydir/ also the same way (`user_foo.pub`). + + Just to repeat, you do NOT need to do this if the username was like + `user@foo.bar`, i.e., the part after the `@` had a `.` in it, because then + it looks like an email address. + + * **IMPORTANT: expand any multi-key files you may have**. Gitosis is happy + to accept files containing more than one public key (one per line) and + assign all the keys to the same user. Gitolite does not allow that; see + [here][multi-key]'s for how gitolite handles multi-keys. + + So if you had any multi-keys in gitosis, they need to be carefully split + into individual keys. + + You can split the keys manually, or use the following code (just + copy-paste it into your xterm after "cd"-ing to your gitolite-admin repo + clone): + + wc -l keydir/*.pub | grep -v total | grep -v -w 1 | while read a b + do + i=1 + cat $b|while read l + do + echo "$l" > ${b%.pub}@$i.pub + (( i++ )) + done + mv $b $b.done + done + + This will split each multi-key file (say "sitaram.pub") into individual + files called "sitaram@1.pub", "sitaram@2.pub", etc., and rename the + original to "sitaram.pub.done" so gitolite won't pick it up. + + At this point you can rename the split parts more appropriately, like + "sitaram@laptop.pub" and "sitaram@desktop.pub" or whatever. *Please check + the files to make sure this worked properly* + + * Check all your changes to your gitolite-admin clone, commit, and push + diff --git a/doc/migr.mkd b/doc/migr.mkd new file mode 100644 index 0000000..857f484 --- /dev/null +++ b/doc/migr.mkd @@ -0,0 +1,6 @@ +# migrating to gitolite + +If you're an existing (gitolite v1.x or v2.x) user, start with the [g2 +migration][g2migr] page. + +If you're migrating from gitosis, [this][gsmigr] is what you want. diff --git a/doc/mirroring.mkd b/doc/mirroring.mkd index a0a5af3..28b6a22 100644 --- a/doc/mirroring.mkd +++ b/doc/mirroring.mkd @@ -170,7 +170,7 @@ second one trusts only some slaves. Note that you cannot redirect gitolite commands (like perms, etc). -## manually synchronising a slave repo +## #sync manually synchronising a slave repo You can use the `gitolite mirror push` command on a master to manually synchronise any of its slaves. Try it with `-h` to get usage info. diff --git a/doc/non-core.mkd b/doc/non-core.mkd index 095cc3b..49215c5 100644 --- a/doc/non-core.mkd +++ b/doc/non-core.mkd @@ -9,6 +9,15 @@ remote user running `ssh git@host help`. All the commands that ship with gitolite will respond to `-h`; please report a bug to me if they don't. +Here's a list of remote commands that are shipped: + + * 'desc' -- get/set the 'description' file for a repo + * 'info' -- already documented [here][info] + * 'mirror' -- documented [here][sync] + * 'perms' -- get/set the gl-perms file; see [perms][] for more + * 'sskm' -- self-service key management + * 'writable' -- disabling pushes to take backups etc + ## syntactic sugar The following "sugar" programs are available: diff --git a/doc/progit.mkd b/doc/progit.mkd new file mode 100644 index 0000000..053ffa9 --- /dev/null +++ b/doc/progit.mkd @@ -0,0 +1,166 @@ +# (master copy of progit chapter on gitolite) + +## Gitolite ## + +Note: the latest copy of this section of the ProGit book is always available within the [gitolite documentation][progit]. The author would also like to humbly state that, while this section is accurate, and *can* (and often *has*) been used to install gitolite without reading any other documentation, it is of necessity not complete, and cannot completely replace the enormous amount of documentation that gitolite comes with. + +[Update 2012-04-10]: This page has been completely rewritten for gitolite version 3, informally called "g3". G3 is a *total* rewrite of gitolite to push a lot more features away from "core", give the core a bunch of extension mechanisms, and finally have much better shell and perl APIs to bring all this together. + +Git has become very popular in corporate environments, which tend to have some additional requirements in terms of access control. Gitolite was originally created to help with those requirements, but it turns out that it's equally useful in the open source world: the Fedora Project controls access to their package management repositories (over 10,000 of them!) using gitolite, and this is probably the largest gitolite installation anywhere too. KDE, and kernel.org, are other very high-profile users of gitolite. + +Gitolite allows you to specify permissions not just by repository, but also by branch or tag names within each repository. That is, you can specify that certain people (or groups of people) can only push certain "refs" (branches or tags) but not others. + +### Installing ### + +Installing Gitolite is very easy, even if you don't read the extensive documentation that comes with it. You need an account on a Unix server of some kind. You do not need root access, assuming git, perl, and an openssh compatible ssh server are already installed. In the examples below, we will use the `git` account on a host called `gitserver`. + +Gitolite is somewhat unusual as far as "server" software goes -- access is via ssh, and so every userid on the server is a potential "gitolite host". Gitolite is at present best installed manually, as the "g3" version does not yet have RPM/DEB support from distros. We will describe the simplest install method in this article; for the other methods please see the documentation. + +To begin, create a user called `git` on your server and login to this user. Copy your ssh pubkey (a file called `~/.ssh/id_rsa.pub` if you did a plain `ssh-keygen` with all the defaults) from your workstation, renaming it to `YourName.pub`. Then run these commands: + + git clone -b g3 git://github.com/sitaramc/gitolite + gitolite/install -ln + gitolite setup -pk $HOME/YourName.pub + # for example, I would run 'gitolite setup -pk $HOME/sitaram.pub' + +(Note: the "-b g3" will not be needed once gitolite v3 becomes the "master" version.) + +Finally, back on your workstation, run `git clone git@server:gitolite-admin`. + +And you're done! Gitolite has now been installed on the server, and you now have a brand new repository called `gitolite-admin` in your workstation. You administer your gitolite setup by making changes to this repository and pushing. See adding [users][] and [repos][] to start with. + +### Customising the Install ### + +While the default, quick, install works for most people, there are some ways to customise the install if you need to. Some changes can be made simply by editing the [rc file][rc], but if that is not sufficient, there's documentation on [customising gitolite][cust] by using non-core programs. + +### Config File and Access Control Rules ### + +Once the install is done, you switch to the `gitolite-admin` repository (placed in your HOME directory) and poke around to see what you got: + + $ cd ~/gitolite-admin/ + $ ls + conf/ keydir/ + $ find conf keydir -type f + conf/gitolite.conf + keydir/sitaram.pub + $ cat conf/gitolite.conf + + repo gitolite-admin + RW+ = sitaram + + repo testing + RW+ = @all + +Notice that "sitaram" (the name of the pubkey in the gl-setup command you used earlier) has read-write permissions on the `gitolite-admin` repository as well as a public key file of the same name. + +The config file syntax for gitolite is [well documented][conf], so we'll only mention some highlights here. + +You can group users or repos for convenience. The group names are just like macros; when defining them, it doesn't even matter whether they are projects or users; that distinction is only made when you *use* the "macro". + + @oss_repos = linux perl rakudo git gitolite + @secret_repos = fenestra pear + + @admins = scott # Adams, not Chacon, sorry :) + @interns = ashok # get the spelling right, Scott! + @engineers = sitaram dilbert wally alice + @staff = @admins @engineers @interns + +You can control permissions at the "ref" level. In the following example, interns can only push the "int" branch. Engineers can push any branch whose name starts with "eng-", and tags that start with "rc" followed by a digit. And the admins can do anything (including rewind) to any ref. + + repo @oss_repos + RW int$ = @interns + RW eng- = @engineers + RW refs/tags/rc[0-9] = @engineers + RW+ = @admins + +The expression after the `RW` or `RW+` is a regular expression (regex) that the refname (ref) being pushed is matched against. So we call it a "refex"! Of course, a refex can be far more powerful than shown here, so don't overdo it if you're not comfortable with perl regexes. + +Also, as you probably guessed, Gitolite prefixes `refs/heads/` as a syntactic convenience if the refex does not begin with `refs/`. + +An important feature of the config file's syntax is that all the rules for a repository need not be in one place. You can keep all the common stuff together, like the rules for all `oss_repos` shown above, then add specific rules for specific cases later on, like so: + + repo gitolite + RW+ = sitaram + +That rule will just get added to the ruleset for the `gitolite` repository. + +At this point you might be wondering how the access control rules are actually applied, so let's go over that briefly. + +There are two levels of access control in gitolite. The first is at the repository level; if you have read (or write) access to *any* ref in the repository, then you have read (or write) access to the repository. + +The second level, applicable only to "write" access, is by branch or tag within a repository. The username, the access being attempted (`W` or `+`), and the refname being updated are known. The access rules are checked in order of appearance in the config file, looking for a match for this combination (but remember that the refname is regex-matched, not merely string-matched). If a match is found, the push succeeds. A fallthrough results in access being denied. + +### Advanced Access Control with "deny" rules ### + +So far, we've only seen permissions to be one or `R`, `RW`, or `RW+`. However, gitolite allows another permission: `-`, standing for "deny". This gives you a lot more power, at the expense of some complexity, because now fallthrough is not the *only* way for access to be denied, so the *order of the rules now matters*! + +Let us say, in the situation above, we want engineers to be able to rewind any branch *except* master and integ. Here's how to do that: + + RW master integ = @engineers + - master integ = @engineers + RW+ = @engineers + +Again, you simply follow the rules top down until you hit a match for your access mode, or a deny. Non-rewind push to master or integ is allowed by the first rule. A rewind push to those refs does not match the first rule, drops down to the second, and is therefore denied. Any push (rewind or non-rewind) to refs other than master or integ won't match the first two rules anyway, and the third rule allows it. + +You can also use deny rules to hide specific repos from people (or gitweb, or git-daemon, etc.), when you have otherwise allowed them access to *all* repos. For example, a server containing open source repos may nevertheless wish to hide the special 'gitolite-admin' repo from gitweb, even though all the other repos can be made visible: + + repo gitolite-admin + - = gitweb daemon + [... other access rules ...] + option deny-rules = 1 + # remember this is for gitolite "g3"; the older gitolite had a + # different syntax + + repo @all + R = gitweb daemon + +[This][deny-rules] page has more details. + +### Restricting pushes by files changed ### + +In addition to restricting what branches a user can push changes to, you can also restrict what files they are allowed to touch. For example, perhaps the Makefile (or some other program) is really not supposed to be changed by just anyone, because a lot of things depend on it or would break if the changes are not done *just right*. You can tell gitolite: + + repo foo + RW = @junior_devs @senior_devs + + - VREF/NAME/Makefile = @junior_devs + +User who are migrating from the older gitolite should note that there is a significant change in behaviour with regard to this feature; please see the [migration guide][migr] for details. + +### Personal Branches ### + +Gitolite also has a feature called "personal branches" (or rather, "personal branch namespace") that can be very useful in a corporate environment. + +A lot of code exchange in the git world happens by "please pull" requests. In a corporate environment, however, unauthenticated access is a no-no, and a developer workstation cannot do authentication, so you have to push to the central server and ask someone to pull from there. + +This would normally cause the same branch name clutter as in a centralised VCS, plus setting up permissions for this becomes a chore for the admin. + +Gitolite lets you define a "personal" or "scratch" namespace prefix for each developer (for example, `refs/personal//*`); the details are [here][pers]. + +### "Wildcard" repositories ### + +Gitolite allows you to specify repositories with wildcards (actually perl regexes), like, for example `assignments/s[0-9][0-9]/a[0-9][0-9]`, to pick a random example. It allows you to assign a new permission mode ("C") which allows users to create repositories based on such wild cards, automatically assigns ownership to the specific user who created it, allows him/her to hand out R and RW permissions to other users to collaborate, etc. This feature is documented [here][wild]. + +### Other Features ### + +We'll round off this discussion with a sampling of other features, all of which, and many more, are described in great detail in the documentation. + +**Logging**: Gitolite logs all successful accesses. If you were somewhat relaxed about giving people rewind permissions (`RW+`) and some kid blew away "master", the log file is a life saver, in terms of easily and quickly finding the SHA that got hosed. + +**Access rights reporting**: Another convenient feature is what happens when you try and just ssh to the server. Gitolite shows you what repos you have access to, and what that access may be. Here's an example: + + hello sitaram, this is git@git running gitolite3 v0.02-15-g1db50f4 on git 1.7.4.4 + + R anu-wsd + R entrans + R W git-notes + R W gitolite + R W gitolite-admin + R indic_web_input + R shreelipi_converter + +**Delegation**: For really large installations, you can delegate responsibility for groups of repositories to various people and have them manage those pieces independently. This reduces the load on the main admin, and makes him less of a bottleneck. See [here][deleg] for more on this. + +**Mirroring**: Gitolite can help you maintain multiple [mirrors][mirroring], and switch between them easily if the primary server goes down. + +[progit]: http://sitaramc.github.com/gitolite/progit.html diff --git a/doc/users.mkd b/doc/users.mkd index 520451f..f815aaa 100644 --- a/doc/users.mkd +++ b/doc/users.mkd @@ -32,7 +32,7 @@ The user name is simply the base name of the public key file name. So ## #multi-key multiple keys per user The simplest and most understandable is to put their keys in different -subdirectories, (alice,pub, home/alice.pub, laptop/alice.pub, etc). +subdirectories, (alice.pub, home/alice.pub, laptop/alice.pub, etc). ### old style multi-keys diff --git a/doc/wild.mkd b/doc/wild.mkd index 9b26e0e..49f99ba 100644 --- a/doc/wild.mkd +++ b/doc/wild.mkd @@ -108,7 +108,8 @@ what users are in these roles. That needs to be done by the creator of the repo, using the `perms` command. You can run `ssh git@host perms -h` for detailed help, but in brief, that -command lets you give and take away roles to users. +command lets you give and take away roles to users. [This][perms] has some +more detail. ## adding other roles diff --git a/src/lib/Gitolite/Conf/Sugar.pm b/src/lib/Gitolite/Conf/Sugar.pm index c607417..1e9cd9f 100644 --- a/src/lib/Gitolite/Conf/Sugar.pm +++ b/src/lib/Gitolite/Conf/Sugar.pm @@ -119,14 +119,14 @@ sub owner_desc { # owner = "owner name" # -> config gitweb.owner = owner name - # description = "some long description" + # desc = "some long description" # -> config gitweb.description = some long description # category = "whatever..." # -> config gitweb.category = whatever... # older formats: # repo = "some long description" - # repo = "owner name" = "some long description" + # repo "owner name" = "some long description" # -> config gitweb.owner = owner name # -> config gitweb.description = some long description