Compare commits
No commits in common. "v2.0.1" and "master" have entirely different histories.
4
.gitattributes
vendored
4
.gitattributes
vendored
|
@ -1,4 +0,0 @@
|
|||
conf/* crlf=input
|
||||
src/* crlf=input
|
||||
hooks/common/* crlf=input
|
||||
hooks/gitolite-admin/* crlf=input
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -1,5 +0,0 @@
|
|||
*.tar
|
||||
*.tgz
|
||||
*.tar.gz
|
||||
*.tar.bz2
|
||||
conf/VERSION
|
86
CHANGELOG
Normal file
86
CHANGELOG
Normal file
|
@ -0,0 +1,86 @@
|
|||
2012-12-29 v3.3 bug fix: gl-perms propagation to slaves broke sometime
|
||||
after v3.2 (so if you're only picking up tagged releases
|
||||
you're OK)
|
||||
|
||||
the "D" command now allows rm/unlock to be totally
|
||||
disabled
|
||||
|
||||
new trigger: update-gitweb-daemon-from-options; another
|
||||
way to update gitweb and daemon access lists
|
||||
|
||||
new 'create' command for explicit wild repo creation, and
|
||||
new AutoCreate trigger to control auto-creation
|
||||
|
||||
allow simple macros in conf file
|
||||
|
||||
2012-11-14 v3.2 major efficiency boost for large setups
|
||||
|
||||
optional support for multi-line pubkeys; see
|
||||
src/triggers/post-compile/ssh-authkeys-split
|
||||
|
||||
bug fix for not creating gl-conf when repo para has only
|
||||
config lines and no access rules
|
||||
|
||||
new 'bg' trigger command to put long jobs started from a
|
||||
trigger into background
|
||||
|
||||
%GL_REPO and %GL_CREATOR now work for 'option's also
|
||||
|
||||
test suite now much more BSD friendly
|
||||
|
||||
2012-10-05 v3.1 (security) fix path traversal on wild repos
|
||||
|
||||
new %GL_CREATOR variable for git-config lines
|
||||
|
||||
rsync command to create and send bundles automagically
|
||||
|
||||
migrated 'who-pushed'
|
||||
|
||||
logical expressions on refexes!!!
|
||||
|
||||
2012-06-27 v3.04 documentation graduated and moved out of parents house :)
|
||||
|
||||
new trigger for 'repo specific umask'
|
||||
|
||||
new 'list-dangling-repos' command
|
||||
|
||||
new LOCAL_CODE rc var; allow admin specified programs to
|
||||
override system-installed ones
|
||||
|
||||
new 'upstream' trigger-cum-command to maintain local
|
||||
copies of external repos
|
||||
|
||||
new 'sudo' command
|
||||
|
||||
minor backward compat breakage in 'gitolite query-rc'
|
||||
|
||||
'perms' command can now create repo if needed
|
||||
|
||||
migrated 'symbolic-ref' command
|
||||
|
||||
'gitolite setup --hooks-only'
|
||||
|
||||
2012-05-23 v3.03 fix major bug that allowed an admin to get a shell
|
||||
|
||||
2012-05-20 v3.02 packaging instructions fixed up and smoke tested
|
||||
|
||||
make it easier to give some users a full shell
|
||||
|
||||
allow aliasing a repo to another name
|
||||
|
||||
simulate POST_CREATE for new normal (non-wild) repos
|
||||
|
||||
(just for kicks) a VREF that allows for voting on changes
|
||||
to a branch
|
||||
|
||||
bug fix: smart http was not running PRE_ and POST_GIT
|
||||
triggers
|
||||
|
||||
htpasswd migrated
|
||||
|
||||
2012-04-29 v3.01 mostly BSD and Solaris compat
|
||||
also fork command added
|
||||
|
||||
2012-04-18 v3.0 first release to "master"
|
||||
This is a compete rewrite of gitolite; please see
|
||||
documentation before upgrading.
|
|
@ -1,12 +1,12 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
|
@ -56,7 +56,7 @@ patent must be licensed for everyone's free use or not licensed at all.
|
|||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
|
@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
|
|||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
|
@ -276,64 +276,3 @@ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
|||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
21
Makefile
21
Makefile
|
@ -1,21 +0,0 @@
|
|||
# this is a simple wrapper around "git archive" using make
|
||||
|
||||
# "make [refname].tar" produces a tar of refname, then adds a file containing
|
||||
# the "git describe" output for that refname to the tar. This lets you say
|
||||
# "cat .GITOLITE-VERSION" to find out which ref produced this tar
|
||||
|
||||
# Note: I'm not sure if that "-r" is a GNU tar extension...
|
||||
|
||||
branch := $(shell git rev-parse --abbrev-ref HEAD)
|
||||
|
||||
$(branch): $(branch).tar
|
||||
|
||||
.GITOLITE-VERSION:
|
||||
@touch conf/VERSION
|
||||
|
||||
%.tar: .GITOLITE-VERSION
|
||||
git describe --tags --long $* > conf/VERSION
|
||||
git archive $* > $@
|
||||
tar -r -f $@ conf/VERSION
|
||||
rm conf/VERSION
|
||||
cp -v $@ /tmp
|
359
README.md
Normal file
359
README.md
Normal file
|
@ -0,0 +1,359 @@
|
|||
Github-users: click the 'wiki' link before sending me anything via github.
|
||||
|
||||
Existing users: this is gitolite v3.x. If you are upgrading from v2.x this
|
||||
file will not suffice; you *must* check the online docs (see below for URL).
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
|
||||
This file contains BASIC DOCUMENTATION ONLY.
|
||||
|
||||
* It is suitable for a fresh, ssh-based, installation of gitolite and basic
|
||||
usage of its most important features.
|
||||
* It is NOT meant to be exhaustive or detailed.
|
||||
|
||||
The COMPLETE DOCUMENTATION is at:
|
||||
|
||||
http://sitaramc.github.com/gitolite/master-toc.html
|
||||
|
||||
Please go there for what/why/how, concepts, background, troubleshooting, more
|
||||
details on what is covered here, or advanced features not covered here.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
|
||||
BASIC DOCUMENTATION FOR GITOLITE
|
||||
================================
|
||||
|
||||
This file contains the following sections:
|
||||
|
||||
* INSTALLATION AND SETUP
|
||||
* ADDING USERS AND REPOS
|
||||
* HELP FOR YOUR USERS
|
||||
* BASIC SYNTAX
|
||||
* ACCESS RULES
|
||||
* GROUPS
|
||||
* COMMANDS
|
||||
* THE 'rc' FILE
|
||||
* GIT-CONFIG
|
||||
* GIT-DAEMON
|
||||
* GITWEB
|
||||
* CONTACT AND SUPPORT
|
||||
* LICENSE
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
|
||||
INSTALLATION AND SETUP
|
||||
----------------------
|
||||
|
||||
Server requirements:
|
||||
|
||||
* any unix system
|
||||
* sh
|
||||
* git 1.6.6+
|
||||
* perl 5.8.8+
|
||||
* openssh 5.0+
|
||||
* a dedicated userid to host the repos (in this document, we assume it
|
||||
is 'git'), with shell access ONLY by 'su - git' from some other userid
|
||||
on the same server.
|
||||
|
||||
Steps to install:
|
||||
|
||||
* login as 'git' as described above
|
||||
* make sure ~/.ssh/authorized_keys is empty or non-existent
|
||||
* make sure your ssh public key from your workstation is available at $HOME/YourName.pub
|
||||
* run the following commands:
|
||||
|
||||
git clone git://github.com/sitaramc/gitolite
|
||||
mkdir -p $HOME/bin
|
||||
gitolite/install -to $HOME/bin
|
||||
gitolite setup -pk YourName.pub
|
||||
|
||||
If the last command doesn't run perhaps 'bin' in not in your 'PATH'.
|
||||
You can either add it, or just run:
|
||||
|
||||
$HOME/bin/gitolite setup -pk YourName.pub
|
||||
|
||||
|
||||
ADDING USERS AND REPOS
|
||||
----------------------
|
||||
|
||||
Do NOT add new repos or users manually on the server. Gitolite users,
|
||||
repos, and access rules are maintained by making changes to a special repo
|
||||
called 'gitolite-admin' and pushing those changes to the server.
|
||||
|
||||
----
|
||||
|
||||
To administer your gitolite installation, start by doing this on your
|
||||
workstation (if you have not already done so):
|
||||
|
||||
git clone git@host:gitolite-admin
|
||||
|
||||
**NOTE**: if you are asked for a password, something has gone wrong.
|
||||
|
||||
Now if you 'cd gitolite-admin', you will see two subdirectories in it:
|
||||
'conf' and 'keydir'.
|
||||
|
||||
To add new users alice, bob, and carol, obtain their public keys and add
|
||||
them to 'keydir' as alice.pub, bob.pub, and carol.pub respectively.
|
||||
|
||||
To add a new repo 'foo' and give different levels of access to these
|
||||
users, edit the file 'conf/gitolite.conf' and add lines like this:
|
||||
|
||||
repo foo
|
||||
RW+ = alice
|
||||
RW = bob
|
||||
R = carol
|
||||
|
||||
See the 'ACCESS RULES' section later for more details.
|
||||
|
||||
Once you have made these changes, do something like this:
|
||||
|
||||
git add conf
|
||||
git add keydir
|
||||
git commit -m 'added foo, gave access to alice, bob, carol'
|
||||
git push
|
||||
|
||||
When the push completes, gitolite will add the new users to
|
||||
~/.ssh/authorized_keys on the server, as well as create a new, empty, repo
|
||||
called 'foo'.
|
||||
|
||||
|
||||
HELP FOR YOUR USERS
|
||||
-------------------
|
||||
|
||||
Once a user has sent you their public key and you have added them as
|
||||
specified above and given them access, you have to tell them what URL to
|
||||
access their repos at. This is usually 'git clone git@host:reponame'; see
|
||||
man git-clone for other forms.
|
||||
|
||||
**NOTE**: again, if they are asked for a password, something is wrong.
|
||||
|
||||
If they need to know what repos they have access to, they just have to run
|
||||
'ssh git@host info'; see 'COMMANDS' section later for more on this.
|
||||
|
||||
|
||||
BASIC SYNTAX
|
||||
------------
|
||||
|
||||
The basic syntax of the conf file is very simple.
|
||||
|
||||
* Everything is space separated; there are no commas, semicolons, etc.,
|
||||
in the syntax.
|
||||
* Comments are in the usual perl/shell style.
|
||||
* User and repo names are as simple as possible; they must start with an
|
||||
alphanumeric, but after that they can also contain '.', '_', or '-'.
|
||||
|
||||
Usernames can optionally be followed by an '@' and a domainname
|
||||
containing at least one '.'; this allows you to use an email address
|
||||
as someone's username.
|
||||
|
||||
Reponames can contain '/' characters; this allows you to put your
|
||||
repos in a tree-structure for convenience.
|
||||
* There are no continuation lines.
|
||||
|
||||
|
||||
ACCESS RULES
|
||||
------------
|
||||
|
||||
This section is mostly 'by example'.
|
||||
|
||||
Gitolite's access rules are very powerful. The simplest use was already
|
||||
shown above. Here is a slightly more detailed example:
|
||||
|
||||
repo foo
|
||||
RW+ = alice
|
||||
- master = bob
|
||||
- refs/tags/v[0-9] = bob
|
||||
RW = bob
|
||||
RW refs/tags/v[0-9] = carol
|
||||
R = dave
|
||||
|
||||
For clones and fetches, as long as the user is listed with an R, RW
|
||||
or RW+ in at least one rule, he is allowed to read the repo.
|
||||
|
||||
For pushes, rules are processed in sequence until a rule is found
|
||||
where the user, the permission (see note 1), and the refex (note 2)
|
||||
*all* match. At that point, if the permission on the matched rule
|
||||
was '-', the push is denied, otherwise it is allowed. If no rule
|
||||
matches, the push is denied.
|
||||
|
||||
Note 1: permission matching:
|
||||
|
||||
* a permission of RW matches only a fast-forward push or create
|
||||
* a permission of RW+ matches any type of push
|
||||
* a permission of '-' matches any type of push
|
||||
|
||||
Note 2: refex matching:
|
||||
(refex = optional regex to match the ref being pushed)
|
||||
|
||||
* an empty refex is treated as 'refs/.*'
|
||||
* a refex that does not start with 'refs/' is prefixed with 'refs/heads/'
|
||||
* finally, a '^' is prefixed
|
||||
* the ref being pushed is matched against this resulting refex
|
||||
|
||||
With all that background, here's what the example rules say:
|
||||
|
||||
* alice can do anything to any branch or tag -- create, push, delete, rewind/overwrite etc.
|
||||
* bob can create or fast-forward push any branch whose name does
|
||||
not start with 'master' and create any tag whose name does not
|
||||
start with 'v'+digit.
|
||||
* carol can create tags whose names start with 'v'+digit.
|
||||
* dave can clone/fetch.
|
||||
|
||||
|
||||
GROUPS
|
||||
------
|
||||
|
||||
Gitolite allows you to group users or repos for convenience. Here's an
|
||||
example that creates two groups of users:
|
||||
|
||||
@staff = alice bob carol
|
||||
@interns = ashok
|
||||
|
||||
repo secret
|
||||
RW = @staff
|
||||
|
||||
repo foss
|
||||
RW+ = @staff
|
||||
RW = @interns
|
||||
|
||||
Group lists accumulate. The following two lines have the same effect as
|
||||
the earlier definition of @staff above:
|
||||
|
||||
@staff = alice bob
|
||||
@staff = carol
|
||||
|
||||
You can also use group names in other group names:
|
||||
|
||||
@all-devs = @staff @interns
|
||||
|
||||
Finally, @all is a special group name that is often convenient to use if
|
||||
you really mean 'all repos' or 'all users'.
|
||||
|
||||
|
||||
COMMANDS
|
||||
--------
|
||||
|
||||
Users can run certain commands remotely, using ssh. For example:
|
||||
|
||||
ssh git@host help
|
||||
|
||||
prints a list of available commands.
|
||||
|
||||
The most commonly used command is 'info'. All commands respond to a
|
||||
single argument of '-h' with suitable information.
|
||||
|
||||
If you have shell on the server, you have a lot more commands available to
|
||||
you; try running 'gitolite help'.
|
||||
|
||||
|
||||
THE 'rc' FILE
|
||||
--------------
|
||||
|
||||
Some of the instructions below may require you to edit the rc file
|
||||
(~/.gitolite.rc on the server).
|
||||
|
||||
The rc file is perl code, but you do NOT need to know perl to edit it.
|
||||
Just mind the commas, use single quotes unless you know what you're doing,
|
||||
and make sure the brackets and braces stay matched up.
|
||||
|
||||
|
||||
GIT-CONFIG
|
||||
----------
|
||||
|
||||
Gitolite lets you set git-config values for individual repos without
|
||||
having to log on to the server and run 'git config' commands:
|
||||
|
||||
repo foo
|
||||
config hooks.mailinglist = foo-commits@example.tld
|
||||
config hooks.emailprefix = '[foo] '
|
||||
config foo.bar = ''
|
||||
config foo.baz =
|
||||
|
||||
**WARNING**
|
||||
|
||||
The last syntax shown above is the *only* way to *delete* a config
|
||||
variable once you have added it. Merely removing it from the conf
|
||||
file will *not* delete it from the repo.git/config file.
|
||||
|
||||
**SECURITY NOTE**
|
||||
|
||||
Some git-config keys allow arbitrary code to be run on the server.
|
||||
|
||||
If all of your gitolite admins already have shell access to the server
|
||||
account hosting it, you can edit the rc file (~/.gitolite.rc) on the
|
||||
server, and change the GIT_CONFIG_KEYS line to look like this:
|
||||
|
||||
GIT_CONFIG_KEYS => '.*',
|
||||
|
||||
Otherwise, give it a space-separated list of regular expressions that
|
||||
define what git-config keys are allowed. For example, this one allows
|
||||
only variables whose names start with 'gitweb' or with 'gc' to be
|
||||
defined:
|
||||
|
||||
GIT_CONFIG_KEYS => 'gitweb\..* gc\..*',
|
||||
|
||||
|
||||
GIT-DAEMON
|
||||
----------
|
||||
|
||||
Gitolite creates the 'git-daemon-export-ok' file for any repo that is
|
||||
readable by a special user called 'daemon', like so:
|
||||
|
||||
repo foo
|
||||
R = daemon
|
||||
|
||||
|
||||
GITWEB
|
||||
------
|
||||
|
||||
Any repo that is readable by a special user called 'gitweb' will be added
|
||||
to the projects.list file.
|
||||
|
||||
repo foo
|
||||
R = gitweb
|
||||
|
||||
Or you can set one or more of the following config variables instead:
|
||||
|
||||
repo foo
|
||||
config gitweb.owner = some person's name
|
||||
config gitweb.description = some description
|
||||
config gitweb.category = some category
|
||||
|
||||
**NOTE**
|
||||
|
||||
You will probably need to change the UMASK in the rc file from the
|
||||
default (0077) to 0027 and add whatever user your gitweb is running as
|
||||
to the 'git' group. After that, you need to run a one-time 'chmod -R'
|
||||
on the already created files and directories.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
|
||||
CONTACT AND SUPPORT
|
||||
-------------------
|
||||
|
||||
Mailing list for support and general discussion:
|
||||
gitolite@googlegroups.com
|
||||
subscribe address: gitolite+subscribe@googlegroups.com
|
||||
|
||||
Mailing list for announcements and notices:
|
||||
subscribe address: gitolite-announce+subscribe@googlegroups.com
|
||||
|
||||
IRC: #git and #gitolite on freenode. Note that I live in India (UTC+0530
|
||||
time zone).
|
||||
|
||||
Author: sitaramc@gmail.com, but please DO NOT use this for general support
|
||||
questions. Subscribe to the list and ask there instead.
|
||||
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
|
||||
The gitolite *code* is released under GPL v2. See COPYING for details.
|
||||
|
||||
This documentation, which is part of the source code repository, is
|
||||
provided under a Creative Commons Attribution-ShareAlike 3.0 Unported
|
||||
License -- see http://creativecommons.org/licenses/by-sa/3.0/
|
203
README.mkd
203
README.mkd
|
@ -1,203 +0,0 @@
|
|||
# main README file for gitolite -- start here!
|
||||
|
||||
<a name="start"></a>
|
||||
|
||||
***IMPORTANT NOTE: v2.0rc1 is out; all development will be on that now.
|
||||
Please see new doc/developer-notes.mkd***
|
||||
|
||||
----
|
||||
|
||||
Gitolite is an access control layer on top of git, which allows access control
|
||||
down to the branch level, including specifying who can and cannot *rewind* a
|
||||
given branch.
|
||||
|
||||
Gitolite comes with a **huge** amount of documentation. If you're absolutely
|
||||
new, the suggested reading order is this:
|
||||
|
||||
* the README (this document) for a quick intro
|
||||
* the [INSTALL][install] document
|
||||
* the [ADMIN][admin] document
|
||||
|
||||
If you run into trouble start [here](#support). If you're migrating from
|
||||
gitosis, read [this][migr].
|
||||
|
||||
And [here][who]'s some information on some of the projects and people using
|
||||
gitolite (and who, in turn, have helped shape its features).
|
||||
|
||||
Once you've installed it and started using it, you'll want to explore some of
|
||||
the more powerful features. **The documentation is best read [online
|
||||
here][docs] or you can read it in your clone's `doc/` directory**. All the
|
||||
longer documents have tables of contents, so you can quickly get a feel for
|
||||
what is covered right at the top.
|
||||
|
||||
----
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_what">what</a>
|
||||
* <a href="#_why">why</a>
|
||||
* <a href="#_main_features">main features</a>
|
||||
* <a href="#_support">support</a>
|
||||
* <a href="#_security">security</a>
|
||||
* <a href="#_contact_and_license">contact and license</a>
|
||||
|
||||
----
|
||||
|
||||
<a name="_what"></a>
|
||||
|
||||
### what
|
||||
|
||||
Gitolite lets you use a single user on a server to host many git repositories
|
||||
and provide access to many developers, without having to give them real
|
||||
userids on or shell access to the server. The essential magic in doing this
|
||||
is ssh's pubkey access and the `authorized_keys` file, and the inspiration was
|
||||
an older program called gitosis.
|
||||
|
||||
Gitolite can restrict who can read from (clone/fetch) or write to (push) a
|
||||
repository. It can also restrict who can push to what branch or tag, which is
|
||||
very important in a corporate environment. Gitolite can be installed without
|
||||
requiring root permissions, and with no additional software than git itself
|
||||
and perl. It also has several other neat features described below and
|
||||
elsewhere in the [doc/][docs] directory.
|
||||
|
||||
<a name="_why"></a>
|
||||
|
||||
### why
|
||||
|
||||
Gitolite is separate from git, and needs to be installed and configured. So...
|
||||
why do we bother?
|
||||
|
||||
Gitolite is useful in any server that is going to host multiple git
|
||||
repositories, each with many developers, where some sort of access control is
|
||||
required.
|
||||
|
||||
In theory, this can be done with plain old Unix permissions: each user is a
|
||||
member of one or more groups, each group "owns" one or more repositories, and
|
||||
using unix permissions (especially the setgid bit -- `chmod g+s`) you can
|
||||
allow/disallow users access to repos.
|
||||
|
||||
But there are several disadvantages here:
|
||||
|
||||
* every user needs a userid and password on the server. This is usually a
|
||||
killer, especially in tightly controlled environments
|
||||
* adding/removing access rights involves complex `usermod -G ...` mumblings
|
||||
which most admins would rather not deal with
|
||||
* *viewing* (aka auditing) the current set of permissions requires running
|
||||
multiple commands to list directories and their permissions/ownerships,
|
||||
users and their group memberships, and then correlating all these manually
|
||||
* auditing historical permissions or permission changes is pretty much
|
||||
impossible without extraneous tools
|
||||
* errors or omissions in setting the permissions exactly can cause problems
|
||||
of either kind: false accepts or false rejects
|
||||
* without going into ACLs it is not possible to give someone read-only
|
||||
access to a repo; they either get read-write access or no access
|
||||
* it is absolutely impossible to restrict pushing by branch name or tag
|
||||
name.
|
||||
|
||||
Gitolite does away with all this:
|
||||
|
||||
* it uses ssh magic to remove the need to give actual unix userids to
|
||||
developers
|
||||
* it uses a simple but powerful config file format to specify access rights
|
||||
* access control changes are affected by modifying this file, adding or
|
||||
removing user's public keys, and "compiling" the configuration
|
||||
* this also makes auditing trivial -- all the data is in one place, and
|
||||
changes to the configuration are also logged, so you can audit them.
|
||||
* finally, the config file allows distinguishing between read-only and
|
||||
read-write access, not only at the repository level, but at the branch
|
||||
level within repositories.
|
||||
|
||||
<a name="_main_features"></a>
|
||||
|
||||
### main features
|
||||
|
||||
The most important feature I needed was **per-branch permissions**. This is
|
||||
pretty much mandatory in a corporate environment, and is almost the single
|
||||
reason I started *thinking* about writing gitolite.
|
||||
|
||||
It's not just "read-only" versus "read-write". Rewinding a branch (aka "non
|
||||
fast forward push") is potentially dangerous, but sometimes needed. So is
|
||||
deleting a branch (which is really just an extreme form of rewind). I needed
|
||||
something in between allowing anyone to do it (the default) and disabling it
|
||||
completely (`receive.denyNonFastForwards` or `receive.denyDeletes`).
|
||||
|
||||
Here're **some more features**. All of them, and more, are documented in
|
||||
detail somewhere in gitolite's [doc/][docs] subdirectory.
|
||||
|
||||
* simple, yet powerful, config file syntax, including specifying
|
||||
gitweb/daemon access. You'll need this power if you manage lots of
|
||||
users+repos+combinations of access
|
||||
* apart from branch-name based restrictions, you can also restrict by
|
||||
file/dir name changed (i.e., output of `git diff --name-only`)
|
||||
* if your requirements are still too complex, you can split up the config
|
||||
file and delegate authority over parts of it
|
||||
* easy to specify gitweb owner, description and gitweb/daemon access
|
||||
* easy to sync gitweb (http) authorisation with gitolite's access config
|
||||
* comprehensive logging [aka: management does not think "blame" is just a
|
||||
synonym for "annotate" :-)]
|
||||
* "personal namespace" prefix for each dev
|
||||
* migration guide and simple converter for gitosis conf file
|
||||
* "exclude" (or "deny") rights at the branch/tag level
|
||||
* specify repos using patterns (patterns may include creator's name)
|
||||
* define powerful operations on the server side, even github-like forking
|
||||
|
||||
<a name="support"></a>
|
||||
|
||||
<a name="_support"></a>
|
||||
|
||||
### support
|
||||
|
||||
Most installation problems are caused by not knowing ssh. Take a look at this
|
||||
[transcript][] to see how simple it actually is, if your server's ssh daemon
|
||||
is behaving itself. Someone also wrote a tutorial, see [here][tut].
|
||||
|
||||
If I suspect your problem is an ssh issue, I will probably ignore it. Please
|
||||
learn how [gitolite uses ssh][doc9gas] and then methodically go through the
|
||||
[ssh trouble shooting][doc6sts] document. These two documents contain
|
||||
everything I could possibly tell you. I have nothing to add.
|
||||
|
||||
Even for other topics, please look through at least the table of contents of
|
||||
at least the numbered documents to see if your question is already answered,
|
||||
before asking.
|
||||
|
||||
<a name="_security"></a>
|
||||
|
||||
### security
|
||||
|
||||
Due to the environment in which this was created and the need it fills, I
|
||||
consider this a "security" program, albeit a very modest one.
|
||||
|
||||
For the first person to find a security hole in it, defined as allowing a
|
||||
normal user (not the gitolite admin) to read a repo, or write/rewind a ref,
|
||||
that the config file says he shouldn't, and caused by a bug in *code* that is
|
||||
in the "master" branch, (not in the other branches, or the configuration file
|
||||
or in Unix, perl, shell, etc.)... well I can't afford 1000 USD rewards like
|
||||
djb, so you'll have to settle for 5000 INR (Indian Rupees) as a "token" prize
|
||||
:-)
|
||||
|
||||
However, there are a few optional features (which must be explicitly enabled
|
||||
in the RC file) where I just haven't had the time to reason about security
|
||||
thoroughly enough. Please read the comments in `conf/example.gitolite.rc` for
|
||||
details, looking for the word "security".
|
||||
|
||||
----
|
||||
|
||||
<a name="_contact_and_license"></a>
|
||||
|
||||
### contact and license
|
||||
|
||||
Gitolite is released under GPL v2. See COPYING for details.
|
||||
|
||||
* author: sitaramc@gmail.com, sitaram@atc.tcs.com
|
||||
* mailing list: gitolite@googlegroups.com
|
||||
* list subscribe address : gitolite+subscribe@googlegroups.com
|
||||
|
||||
[transcript]: http://sitaramc.github.com/gitolite/doc/install-transcript.html
|
||||
[install]: http://sitaramc.github.com/gitolite/doc/1-INSTALL.html
|
||||
[admin]: http://sitaramc.github.com/gitolite/doc/2-admin.html
|
||||
[migr]: http://sitaramc.github.com/gitolite/doc/migrate.html
|
||||
[docs]: http://sitaramc.github.com/gitolite
|
||||
[doc9gas]: http://sitaramc.github.com/gitolite/doc/gitolite-and-ssh.html
|
||||
[doc6sts]: http://sitaramc.github.com/gitolite/doc/ssh-troubleshooting.html
|
||||
[who]: http://sitaramc.github.com/gitolite/doc/who-uses-it.html
|
||||
[tut]: http://sites.google.com/site/senawario/home/gitolite-tutorial
|
99
check-g2-compat
Executable file
99
check-g2-compat
Executable file
|
@ -0,0 +1,99 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use Cwd;
|
||||
|
||||
my $h = $ENV{HOME};
|
||||
my $rc = "$h/.gitolite.rc";
|
||||
my %count;
|
||||
|
||||
intro();
|
||||
|
||||
msg( FATAL => "no rc file found; do you even *have* g2 running?" ) if not -f $rc;
|
||||
do $rc;
|
||||
unless ( $return = do $rc ) {
|
||||
msg( FATAL => "couldn't parse $rc: $@" ) if $@;
|
||||
msg( FATAL => "couldn't do $rc: $!" ) unless defined $return;
|
||||
msg( WARNING => "couldn't run $rc" ) unless $return;
|
||||
}
|
||||
|
||||
print "checking rc file...\n";
|
||||
rc_basic();
|
||||
rest_of_rc();
|
||||
print "\n";
|
||||
|
||||
print "checking conf file(s)...\n";
|
||||
conf();
|
||||
print "\n";
|
||||
|
||||
print "checking repos...\n";
|
||||
repo();
|
||||
print "\n";
|
||||
|
||||
print "...all done...\n";
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
sub intro {
|
||||
msg( INFO => "This program only checks for uses that make the new g3 completely unusable" );
|
||||
msg( '' => "or that might end up giving *more* access to someone if migrated as-is." );
|
||||
msg( '' => "It does NOT attempt to catch all the differences described in the docs." );
|
||||
msg( '', '' );
|
||||
msg( INFO => "'see docs' usually means the pre-migration checklist in" );
|
||||
msg( '', => "'g2migr.html'; to get there, start from the main migration" );
|
||||
msg( '', => "page at http://sitaramc.github.com/gitolite/install.html#migr" );
|
||||
msg( '', '' );
|
||||
}
|
||||
|
||||
sub rc_basic {
|
||||
msg( FATAL => "GL_ADMINDIR in the wrong place -- aborting; see docs" ) if $GL_ADMINDIR ne "$h/.gitolite";
|
||||
msg( NOTE => "GL_ADMINDIR is in the right place; assuming you did not mess with" );
|
||||
msg( '', "GL_CONF, GL_LOGT, GL_KEYDIR, and GL_CONF_COMPILED" );
|
||||
msg( FATAL => "REPO_BASE in the wrong place -- aborting; see docs" ) if $REPO_BASE ne "$h/repositories" and $REPO_BASE ne "repositories";
|
||||
# ( abs or rel both ok)
|
||||
}
|
||||
|
||||
sub rest_of_rc {
|
||||
msg( SEVERE => "GIT_PATH found; see docs" ) if $GIT_PATH;
|
||||
msg( SEVERE => "GL_ALL_INCLUDES_SPECIAL found; see docs" ) if $GL_ALL_INCLUDES_SPECIAL;
|
||||
msg( SEVERE => "GL_NO_CREATE_REPOS not yet implemented" ) if $GL_NO_CREATE_REPOS;
|
||||
msg( SEVERE => "rsync not yet implemented" ) if $RSYNC_BASE;
|
||||
msg( WARNING => "ADMIN_POST_UPDATE_CHAINS_TO found; see docs" ) if $ADMIN_POST_UPDATE_CHAINS_TO;
|
||||
msg( WARNING => "GL_NO_DAEMON_NO_GITWEB found; see docs" ) if $GL_NO_DAEMON_NO_GITWEB;
|
||||
msg( WARNING => "GL_NO_SETUP_AUTHKEYS found; see docs" ) if $GL_NO_SETUP_AUTHKEYS;
|
||||
msg( WARNING => "UPDATE_CHAINS_TO found; see docs" ) if $UPDATE_CHAINS_TO;
|
||||
msg( WARNING => "GL_ADC_PATH found; see docs" ) if $GL_ADC_PATH;
|
||||
msg( WARNING => "non-default GL_WILDREPOS_PERM_CATS found" ) if $GL_WILDREPOS_PERM_CATS ne 'READERS WRITERS';
|
||||
}
|
||||
|
||||
sub conf {
|
||||
chdir($h);
|
||||
chdir($GL_ADMINDIR);
|
||||
|
||||
my $conf = `find . -name "*.conf" | xargs cat`;
|
||||
msg( "SEVERE", "NAME rules; see docs" ) if $conf =~ m(NAME/);
|
||||
msg( "SEVERE", "subconf command in admin repo; see docs" ) if $conf =~ m(NAME/conf/fragments);
|
||||
msg( "SEVERE", "mirroring used; see docs" ) if $conf =~ m(config +gitolite\.mirror\.);
|
||||
}
|
||||
|
||||
sub repo {
|
||||
chdir($h);
|
||||
chdir($REPO_BASE);
|
||||
my @creater = `find . -name gl-creater`;
|
||||
if (@creater) {
|
||||
msg( WARNING => "found " . scalar(@creater) . " gl-creater files; see docs" );
|
||||
}
|
||||
|
||||
my @perms = `find . -name gl-perms | xargs egrep -l -w R\\|RW`;
|
||||
if (@perms) {
|
||||
msg( WARNING => "found " . scalar(@perms) . " gl-perms files with R or RW; see docs" );
|
||||
}
|
||||
}
|
||||
|
||||
sub msg {
|
||||
my ( $type, $text ) = @_;
|
||||
print "$type" if $type;
|
||||
print "\t$text\n";
|
||||
exit 1 if $type eq 'FATAL';
|
||||
|
||||
$count{$type}++ if $type;
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
# see doc/gitolite.conf.mkd for help on the syntax and semantics of this file
|
||||
# online at http://sitaramc.github.com/gitolite/doc/gitolite.conf.html
|
||||
|
||||
|
||||
|
||||
# this file now has docs for just 2 features
|
||||
|
||||
|
||||
|
||||
# (1) NAME/ restrctions: documentation for this feature currently does not fit
|
||||
# anywhere else, so it's still here
|
||||
|
||||
# FILE/DIR NAME BASED RESTRICTIONS
|
||||
# --------------------------------
|
||||
|
||||
# Here's a hopefully self-explanatory example. Assume the project has the
|
||||
# following contents at the top level: a README, a "doc/" directory, and an
|
||||
# "src/" directory.
|
||||
|
||||
repo foo
|
||||
RW+ = lead_dev # rule 1
|
||||
RW = dev1 dev2 dev3 dev4 # rule 2
|
||||
|
||||
RW NAME/ = lead_dev # rule 3
|
||||
RW NAME/doc/ = dev1 dev2 # rule 4
|
||||
RW NAME/src/ = dev1 dev2 dev3 dev4 # rule 5
|
||||
|
||||
# Notes
|
||||
|
||||
# - the "NAME/" is part of the syntax; think of it as a keyword if you like.
|
||||
# The rest of it is treated as a refex to match against each file being
|
||||
# touched (see "SPECIFYING AND USING A REFEX" above for details)
|
||||
|
||||
# - file/dir NAME-based restrictions are *in addition* to normal (branch-name
|
||||
# based) restrictions; they are not a *replacement* for them. This is why
|
||||
# rule #2 (or something like it, maybe with a more specific branch-name) is
|
||||
# needed; without it, dev1/2/3/4 cannot push any branches.
|
||||
|
||||
# - if a repo has *any* NAME/ rules, then NAME-based restrictions are checked
|
||||
# for *all* users. This is why rule 3 is needed, even though we don't
|
||||
# actually have any NAME-based restrictions on lead_dev. Notice the pattern
|
||||
# on rule 3.
|
||||
|
||||
# - *each* file touched by the commits being pushed is checked against those
|
||||
# rules. So, lead_dev can push changes to any files, dev1/2 can push
|
||||
# changes to files in "doc/" and "src/" (but not the top level README), and
|
||||
# dev3/4 can only push changes to files in "src/".
|
||||
|
||||
|
||||
|
||||
# (2) rsync helper: this is an oddball feature that only the person who asked
|
||||
# me for is apparently using, created long ago, before I learned the value of
|
||||
# saying "no" :-) These items just don't seem to fit in any of the existing
|
||||
# documents.
|
||||
|
||||
# EXTERNAL COMMAND HELPERS -- RSYNC
|
||||
# ---------------------------------
|
||||
|
||||
# If $RSYNC_BASE is non-empty, the following config entries come into play
|
||||
# (otherwise they are ignored):
|
||||
|
||||
# a "fake" git repository to collect rsync rules. Gitolite does not
|
||||
# auto-create any repo whose name starts with EXTCMD/
|
||||
repo EXTCMD/rsync
|
||||
# grant permissions to files/dirs within the $RSYNC_BASE tree. A leading
|
||||
# NAME/ is required as a prefix; the actual path starts after that. Matching
|
||||
# follows the same rules as given in "FILE/DIR NAME BASED RESTRICTIONS" above
|
||||
RW NAME/ = sitaram
|
||||
RW NAME/foo/ = user1
|
||||
R NAME/bar/ = user2
|
||||
# just to remind you that these are perl regexes, not shell globs
|
||||
RW NAME/baz/.*/*.c = user3
|
|
@ -1,93 +0,0 @@
|
|||
# configuration variables for gitolite
|
||||
|
||||
# PLEASE READ THE DOCUMENTATION BEFORE EDITING OR ASKING QUESTIONS
|
||||
# ( http://github.com/sitaramc/gitolite/blob/pu/doc/gitolite.rc.mkd )
|
||||
# ( or http://sitaramc.github.com/gitolite/doc/gitolite.rc.html )
|
||||
|
||||
# this file is in perl syntax. However, you do NOT need to know perl to edit
|
||||
# it; it should be fairly self-explanatory and easy to maintain
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# DO NOT TOUCH THIS SECTION!
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
$GL_ADMINDIR=$ENV{HOME} . "/.gitolite";
|
||||
$GL_CONF="$GL_ADMINDIR/conf/gitolite.conf";
|
||||
$GL_KEYDIR="$GL_ADMINDIR/keydir";
|
||||
$GL_CONF_COMPILED="$GL_ADMINDIR/conf/gitolite.conf-compiled.pm";
|
||||
|
||||
# DO NOT CHANGE THE NEXT FOUR LINES UNLESS YOU REALLY KNOW WHAT YOU'RE DOING.
|
||||
# These variables are set automatically by the install method you choose.
|
||||
# (PACKAGE MAINTAINERS: PLEASE READ doc/packaging.mkd)
|
||||
# $GL_PACKAGE_CONF = "";
|
||||
# $GL_PACKAGE_HOOKS = "";
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# most often used/changed variables
|
||||
# ------------------------------------------------------------------------------
|
||||
$GL_WILDREPOS = 0;
|
||||
$PROJECTS_LIST = $ENV{HOME} . "/projects.list";
|
||||
$REPO_UMASK = 0077;
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# variables with an efficiency/performance impact
|
||||
# ------------------------------------------------------------------------------
|
||||
$GL_BIG_CONFIG = 0;
|
||||
$GL_NO_DAEMON_NO_GITWEB = 0;
|
||||
# $GL_NICE_VALUE = 0;
|
||||
# $BIG_INFO_CAP = 20;
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# VARIABLES WITH A SECURITY IMPACT. READ DOCS BEFORE CHANGING THESE!
|
||||
# http://github.com/sitaramc/gitolite/blob/pu/doc/gitolite.rc.mkd#_variables_with_a_security_impact
|
||||
# (or http://sitaramc.github.com/gitolite/doc/gitolite.rc.html#_variables_with_a_security_impact)
|
||||
# ------------------------------------------------------------------------------
|
||||
# $GL_ALL_READ_ALL = 0;
|
||||
$GIT_PATH="";
|
||||
$GL_GITCONFIG_KEYS = "";
|
||||
# $GL_GITCONFIG_WILD = 0;
|
||||
$GL_NO_CREATE_REPOS = 0;
|
||||
$GL_NO_SETUP_AUTHKEYS = 0;
|
||||
# $GL_WILDREPOS_DEFPERMS = 'R @all';
|
||||
$HTPASSWD_FILE = "";
|
||||
$RSYNC_BASE = "";
|
||||
$SVNSERVE = "";
|
||||
# $UPDATE_CHAINS_TO = "hooks/update.secondary";
|
||||
# $ADMIN_POST_UPDATE_CHAINS_TO = "hooks/post-update.secondary";
|
||||
# $GL_ADC_PATH = "";
|
||||
# $GL_GET_MEMBERSHIPS_PGM = "/usr/local/bin/expand-ldap-user-to-groups"
|
||||
# $GL_HTTP_ANON_USER = "mob";
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# less used/changed variables
|
||||
# ------------------------------------------------------------------------------
|
||||
# $GL_ALL_INCLUDES_SPECIAL = 0;
|
||||
# $GL_SLAVE_MODE = 0;
|
||||
# $ENV{GL_SLAVES} = 'gitolite@server2 gitolite@server3';
|
||||
# PLEASE USE SINGLE QUOTES ABOVE, NOT DOUBLE QUOTES
|
||||
$GL_WILDREPOS_PERM_CATS = "READERS WRITERS";
|
||||
# $GL_SITE_INFO = "XYZ.COM DEVELOPERS: PLEASE SEE http://xyz.com/gitolite/help first";
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# rarely changed variables
|
||||
# ------------------------------------------------------------------------------
|
||||
$GL_LOGT="$GL_ADMINDIR/logs/gitolite-%y-%m.log";
|
||||
# $GL_PERFLOGT="$GL_ADMINDIR/logs/perf-gitolite-%y-%m.log";
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# variables that should NOT be changed after the install step completes
|
||||
# ------------------------------------------------------------------------------
|
||||
$REPO_BASE="repositories";
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# DO NOT TOUCH ANY THING AFTER THIS LINE
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# per perl rules, this should be the last line in such a file:
|
||||
1;
|
||||
|
||||
# Local variables:
|
||||
# mode: perl
|
||||
# End:
|
||||
# vim: set syn=perl:
|
|
@ -1,57 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
. $(dirname $0)/adc.common-functions
|
||||
|
||||
get_rights_and_owner gitolite-admin
|
||||
[ -z "$perm_write" ] && die "just *what* are you trying to pull, young man?"
|
||||
|
||||
op=$1
|
||||
shift
|
||||
|
||||
locs=
|
||||
while [ -n "$1" ]
|
||||
do
|
||||
case $1 in
|
||||
'@all' )
|
||||
locs="$locs $HOME"
|
||||
;;
|
||||
* )
|
||||
loc="$GL_REPO_BASE_ABS/$1.git"
|
||||
[ -d $loc ] && locs="$locs $GL_REPO_BASE_ABS/$1.git"
|
||||
[ -d $loc ] || echo "ignoring $1..."
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
[ -z "$locs" ] && die "give me '@all' or some reponame"
|
||||
|
||||
case $op in
|
||||
en|enable )
|
||||
for l in $locs
|
||||
do
|
||||
rm -fv $l/.gitolite.down
|
||||
done
|
||||
;;
|
||||
dis|disable )
|
||||
|
||||
TEMPDIR=$(mktemp -d -t tmp.XXXXXXXXXX)
|
||||
export TEMPDIR
|
||||
trap "/bin/rm -rf $TEMPDIR" 0
|
||||
|
||||
echo 'type the message to be shown to users when they try to push; end with Ctrl-D:'
|
||||
echo > $TEMPDIR/msg
|
||||
cat >> $TEMPDIR/msg
|
||||
echo disabling following locations with message:
|
||||
cat $TEMPDIR/msg
|
||||
echo
|
||||
for l in $locs
|
||||
do
|
||||
cat $TEMPDIR/msg > $l/.gitolite.down
|
||||
echo $l
|
||||
done
|
||||
;;
|
||||
* )
|
||||
die "argument 1 must be 'en' or 'dis'"
|
||||
;;
|
||||
esac
|
|
@ -1,56 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# please make sure this file is NOT chmod +x
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# settings for various ADCs, collected in one place for ease of keeping local
|
||||
# settings intact during upgrades (you only have to worry about this file
|
||||
# now). Documentation for the variables, however, is in the respective ADC
|
||||
|
||||
# settings for 'rm' ADC
|
||||
ARE_YOU_SURE=1
|
||||
USE_LOCK_UNLOCK=1
|
||||
|
||||
# settings for 'trash' ADC
|
||||
TRASH_CAN=$GL_REPO_BASE_ABS/deleted
|
||||
TRASH_SUFFIX=`date +%Y-%m-%d_%H:%M:%S`
|
||||
|
||||
# settings for 'hub' ADC
|
||||
BASE_FETCH_URL="git://gl.example.com"
|
||||
GL_FORKED_FROM="gl-forked-from"
|
||||
# KDE may set this to kde-cloned-from for historical reasons
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# test an option value more concisely
|
||||
opt() {
|
||||
[ "$1" = "1" ] && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
valid_owned_repo() {
|
||||
# check that an arg passed is a valid repo and the current user owns it
|
||||
[ -z "$1" ] && die need a repo name
|
||||
get_rights_and_owner $1
|
||||
[ "$owner" = "$GL_USER" ] || die "$repo does not exist or is not yours!"
|
||||
|
||||
# and we sneak this in too, quietly :)
|
||||
cd $GL_REPO_BASE_ABS
|
||||
}
|
||||
|
||||
die() { echo "$@"; exit 1; }
|
||||
|
||||
# NOTE: this also sets $repo to the normalised (without .git suffix) reponame
|
||||
get_rights_and_owner() {
|
||||
local ans
|
||||
repo=${1%.git}
|
||||
ans=$(perl -I$GL_BINDIR -Mgitolite -e 'cli_repo_rights("'$repo'")')
|
||||
|
||||
# set shell variables as needed
|
||||
owner=${ans#* }
|
||||
rights=${ans% *}
|
||||
echo $rights | grep C >/dev/null 2>&1 && perm_create=yes || perm_create=
|
||||
echo $rights | grep R >/dev/null 2>&1 && perm_read=yes || perm_read=
|
||||
echo $rights | grep W >/dev/null 2>&1 && perm_write=yes || perm_write=
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
. $(dirname $0)/adc.common-functions
|
||||
|
||||
[ -z "$GL_RC" ] && die "ENV GL_RC not set"
|
||||
[ -z "$2" ] && die "Usage: fork source_repo target_repo"
|
||||
|
||||
# get_rights_and_owner now also sets $repo; see comments in common functions
|
||||
get_rights_and_owner $1; from=$repo
|
||||
[ -z "$perm_read" ] && die "no read permissions on $from"
|
||||
|
||||
get_rights_and_owner $2; to=$repo
|
||||
[ -z "$perm_create" ] && die "no create permissions on $to"
|
||||
|
||||
# clone $from to $to
|
||||
git clone --bare -l $GL_REPO_BASE_ABS/$from.git $GL_REPO_BASE_ABS/$to.git
|
||||
[ $? -ne 0 ] && exit 1
|
||||
|
||||
echo "$from forked to $to"
|
||||
|
||||
# fix up creator, gitweb owner, and hooks
|
||||
cd $GL_REPO_BASE_ABS/$to.git
|
||||
echo $GL_USER > gl-creater
|
||||
git config gitweb.owner "$GL_USER"
|
||||
( $GL_BINDIR/gl-query-rc GL_WILDREPOS_DEFPERMS ) |
|
||||
SSH_ORIGINAL_COMMAND="setperms $to" $GL_BINDIR/gl-auth-command $GL_USER
|
||||
cp -R $GL_REPO_BASE_ABS/$from.git/hooks/* $GL_REPO_BASE_ABS/$to.git/hooks
|
||||
|
||||
if [ -n "$GL_WILDREPOS_DEFPERMS" ]; then
|
||||
echo "$GL_WILDREPOS_DEFPERMS" > gl-perms
|
||||
fi
|
||||
|
||||
echo "$from" > gl-forked-from
|
||||
|
||||
# run gitolite's post-init hook if you can (hook code expects GL_REPO to be set)
|
||||
export GL_REPO; GL_REPO="$to"
|
||||
[ -x hooks/gl-post-init ] && hooks/gl-post-init
|
|
@ -1,52 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
die "ENV GL_RC not set\n" unless $ENV{GL_RC};
|
||||
die "ENV GL_BINDIR not set\n" unless $ENV{GL_BINDIR};
|
||||
|
||||
unshift @INC, $ENV{GL_BINDIR};
|
||||
require gitolite or die "parse gitolite.pm failed\n";
|
||||
gitolite->import;
|
||||
|
||||
# get the repo name
|
||||
my $repo = shift;
|
||||
$repo =~ s/\.git$//;
|
||||
# IMPORTANT NOTE: to do any of this inside a hook, you should just use
|
||||
# $ENV{GL_REPO}, since it's guaranteed to be set to the right value
|
||||
|
||||
|
||||
|
||||
# to do a "level 1" check (repo level -- not branch level), do this:
|
||||
my ($perm, $creator) = check_access($repo);
|
||||
# you can pass in any repo name you wish instead of the active repo
|
||||
|
||||
# the first return value looks like one of these, so you can just check for
|
||||
# the presence of "R" or "W" and be done:
|
||||
# _____R___W_
|
||||
# _____R_____
|
||||
# ___________
|
||||
|
||||
# The second value is "<gitolite>" for a normal repo, an actual username for
|
||||
# a wildrepo, or "<notfound>" for a non-existent repo.
|
||||
|
||||
|
||||
|
||||
# to do a "level 2" check (branches), do something like this
|
||||
my $ret = check_access($repo, 'refs/heads/foo', 'W', 1);
|
||||
# the 2nd argument must be a *full* refname (i.e., not "master", but
|
||||
# "refs/heads/master"). The 3rd argument is one of W, +, C, or D. The 4th
|
||||
# argument should be any non-false perl value, like 1.
|
||||
|
||||
# the return value may look like this:
|
||||
# refs/.*
|
||||
# or perhaps this, if you were denied
|
||||
# DENIED by fallthru
|
||||
|
||||
# NOTE: do NOT pass "R" as the 3rd argument. It will seem to work because
|
||||
# you're merely testing the permissions in this code, but an *actual* "git
|
||||
# fetch" for even a DENIED ref will succeed if the user has read access to at
|
||||
# least one branch. This is because the information on what ref is being read
|
||||
# is not made available externally in any useful way (the way the "update"
|
||||
# hook gets its arguments when a push happens).
|
123
contrib/adc/git
123
contrib/adc/git
|
@ -1,123 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# READ ALL INSTRUCTIONS **AND** SOURCE CODE BEFORE DEPLOYING.
|
||||
|
||||
# run arbitrary git commands on the server
|
||||
|
||||
# ----
|
||||
|
||||
# WARNING: HIGHLY INFLAMMABLE. FISSILE MATERIAL, RADIATION HAZARD. HANDLE
|
||||
# WITH CARE. DO NOT REMOVE MANUFACTURER LABEL. NOT TO BE USED WHILE DRIVING
|
||||
# OR UNDER THE INFLUENCE OF ALCOHOL. PATIENTS WITH HEART PROBLEMS MUST SEE
|
||||
# THEIR CARDIOLOGIST BEFORE USING.
|
||||
|
||||
# ----
|
||||
|
||||
# ok, warnings done, here's the saner description.
|
||||
#
|
||||
# This ADC lets you run arbirtrary git commands on any repo on the server.
|
||||
# The first argument will be the repo name, the second and subsequent
|
||||
# arguments will be the rest of the git command. For example, to run `git
|
||||
# describe --tags` on repo `foo`, you would run:
|
||||
#
|
||||
# ssh git@server git foo describe --tags
|
||||
#
|
||||
# If that looks weird to you, you can use
|
||||
#
|
||||
# ssh git@server git --repo=foo describe --tags
|
||||
#
|
||||
# (the position remains the same: between 'git' and '<command>')
|
||||
|
||||
# SECURITY AND SAFETY NOTES:
|
||||
#
|
||||
# - ADC arguments are checked (in `sub try_adc`) to fit `ADC_CMD_ARGS_PATT`
|
||||
# and the only special characters allowed by that pattern are ".", "_", "@",
|
||||
# "/", "+", ":", and "-". Thus, *this* adc does not check arguments
|
||||
# anymore. ANY RISK IN THIS LAXITY IS YOURS, NOT MINE, although I believe
|
||||
# it is safe enough.
|
||||
#
|
||||
# - Most commands don't make sense to allow, even among those that do not
|
||||
# require a work-tree. Avoid commands that can be done using normal git
|
||||
# remote access (ls-remote, clone, archive, push, etc). Also, avoid
|
||||
# commands that *write* to the repo if possible, or at least think/test
|
||||
# thoroughly before enabling them.
|
||||
#
|
||||
# - You have to deal with issues like stdin/out, output files created etc.,
|
||||
# which is another reason to avoid most of the more complex commands.
|
||||
#
|
||||
# - Do not enable prune, gc, etc., if your repos are on NFS/CIFS/etc. See
|
||||
# http://permalink.gmane.org/gmane.comp.version-control.git/122670 for why.
|
||||
#
|
||||
# - The list of commands allowed to be executed, and the permissions required
|
||||
# to do so, are defined here. Feel free to uncomment any of this to make
|
||||
# things more relaxed. If you add new ones, note that the permissions can
|
||||
# only be 'R', 'W', or 'A'. The meanings of R and W are obvious; "A" means
|
||||
# the user must have write access to the *gitolite-admin* repo to run this
|
||||
# command -- yeah that's a nice twist innit? ;-)
|
||||
|
||||
my %GIT_COMMANDS = (
|
||||
# annotate => 'R',
|
||||
# blame => 'R',
|
||||
'count-objects' => 'R',
|
||||
describe => 'R',
|
||||
# diff => 'R',
|
||||
# 'fast-export' => 'R',
|
||||
# grep => 'R',
|
||||
# log => 'R',
|
||||
# shortlog => 'R',
|
||||
# 'show-branch' => 'R',
|
||||
# show => 'R',
|
||||
# whatchanged => 'R',
|
||||
|
||||
# config => 'A', # I strongly discourage un-commenting this
|
||||
# fsck => 'W', # write access required
|
||||
# gc => 'W', # write access required
|
||||
# prune => 'A', # admin access required
|
||||
# repack => 'A', # admin access required
|
||||
);
|
||||
|
||||
# preliminary stuff; indented just to visually get it out of the way
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
die "ENV GL_RC not set\n" unless $ENV{GL_RC};
|
||||
die "ENV GL_BINDIR not set\n" unless $ENV{GL_BINDIR};
|
||||
|
||||
unshift @INC, $ENV{GL_BINDIR};
|
||||
require gitolite or die "parse gitolite.pm failed\n";
|
||||
gitolite->import;
|
||||
|
||||
my $no_help = "this command is too dangerous to just show a help message; we don't want anyone\nrunning it without reading the source and understanding the implications!\n";
|
||||
|
||||
# get the repo name
|
||||
my $repo = shift or die $no_help;
|
||||
$repo =~ s/^--repo=//;
|
||||
$repo =~ s/\.git$//;
|
||||
# get the command
|
||||
my $cmd = shift or die $no_help;
|
||||
|
||||
# is it a valid command at all?
|
||||
exists $GIT_COMMANDS{$cmd} or die "invalid git command\n";
|
||||
|
||||
# check access
|
||||
my $aa = $GIT_COMMANDS{$cmd}; # aa == attempted access
|
||||
if ($aa eq 'A') {
|
||||
my ($perm, $creator) = check_access('gitolite-admin');
|
||||
$perm =~ /W/ or die "no admin access\n";
|
||||
} else {
|
||||
my ($perm, $creator) = check_access($repo);
|
||||
$perm =~ /$aa/ or die "no $aa access to $repo\n";
|
||||
}
|
||||
|
||||
# cd to the repo dir
|
||||
chdir("$ENV{GL_REPO_BASE_ABS}/$repo.git") or die "chdir failed: $!\n";
|
||||
|
||||
# remove or comment the below line to signify you have read and understood all this
|
||||
die $no_help;
|
||||
|
||||
# now run the git command... fingers crossed
|
||||
|
||||
unshift @ARGV, "git", $cmd;
|
||||
print STDERR "+ ", join(" ", @ARGV), "\n";
|
||||
exec @ARGV;
|
|
@ -1,101 +0,0 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
die "ENV GL_RC not set\n" unless $ENV{GL_RC};
|
||||
die "ENV GL_BINDIR not set\n" unless $ENV{GL_BINDIR};
|
||||
|
||||
# - show fake "reflog" from gitolite server
|
||||
# - recover deleted branches
|
||||
# - recover from bad force pushes
|
||||
|
||||
# --------------------
|
||||
|
||||
# WARNING
|
||||
# - heavily dependent on the gitolite log file format (duh!)
|
||||
# - cannot recover if some other commits were made after the force push
|
||||
|
||||
sub usage {
|
||||
print STDERR <<'EOF';
|
||||
USAGE
|
||||
ssh git@server gl-reflog show r1 refs/heads/b1
|
||||
# shows last 10 updates to branch b1 in repo r1
|
||||
ssh git@server gl-reflog show r1 refs/heads/b1 20
|
||||
# shows last 20 entries...
|
||||
ssh git@server gl-reflog recover r1 refs/heads/b1
|
||||
# recovers the last update to b1 in r1 if it was a "+"
|
||||
EOF
|
||||
exit 1;
|
||||
}
|
||||
|
||||
usage unless (@ARGV >= 3);
|
||||
|
||||
# NOTES
|
||||
# - the verb "recover" is used because this is expected to be used most often
|
||||
# to recover deleted branches. Plus there's enough confusion in git land
|
||||
# caused by "reset" and "revert" I thought I should add my bit to it ;-)
|
||||
# - git's internal reflog is NOT recovered, even if you recover the branch.
|
||||
# I'm good but not *that* good ;-)
|
||||
# - since this program produces a log entry that satisfies it's own criteria,
|
||||
# it acts as a "toggle" for its own action for rewinds (but not for deletes)
|
||||
|
||||
my($cmd, $repo, $ref, $limit) = @ARGV;
|
||||
$limit ||= 10;
|
||||
|
||||
unshift @INC, $ENV{GL_BINDIR};
|
||||
require gitolite or die "parse gitolite.pm failed\n";
|
||||
gitolite->import;
|
||||
|
||||
my ($perm, $creator, $wild) = repo_rights($repo);
|
||||
die "you don't have read access to $repo\n" unless $perm =~ /R/;
|
||||
|
||||
my @logfiles = sort glob("$ENV{GL_ADMINDIR}/logs/*");
|
||||
|
||||
# TODO figure out how to avoid reading *all* the log files when you really
|
||||
# only need the last few
|
||||
|
||||
our @loglines;
|
||||
{
|
||||
my @f;
|
||||
local(@ARGV) = @logfiles;
|
||||
while (<>) {
|
||||
chomp;
|
||||
@f = split /\t/;
|
||||
# field 2 is the userid, 5 is W or +, 6/7 are old/new SHAs
|
||||
# 8 is reponame, 9 is refname (but all those are 1-based)
|
||||
next unless $f[3] =~ /^(git-receive-pack|gl-reflog recover) /;
|
||||
next unless $f[8];
|
||||
next unless $f[7] eq $repo;
|
||||
next unless $f[8] eq $ref;
|
||||
push @loglines, $_;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $cmd eq 'show' ) {
|
||||
my $start = @loglines - $limit;
|
||||
$start = 0 if $start < 0;
|
||||
map { print "$loglines[$_]\n" } $start .. $#loglines;
|
||||
|
||||
exit 0;
|
||||
}
|
||||
|
||||
if ( $cmd eq 'recover' ) {
|
||||
my @f = split /\t/, $loglines[$#loglines];
|
||||
die "the last push was not yours\n" unless $f[1] eq $ENV{GL_USER};
|
||||
die "the last push was not a rewind or delete\n" unless $f[4] eq '+';
|
||||
|
||||
my($oldsha, $newsha) = @f[5,6];
|
||||
if ($newsha =~ /^0+$/) {
|
||||
print "recovering $repo $ref at $oldsha (was deleted)\n";
|
||||
} else {
|
||||
print "recovering $repo $ref at $oldsha (was forced to $newsha)\n";
|
||||
}
|
||||
chdir("$ENV{GL_REPO_BASE_ABS}/$repo.git");
|
||||
|
||||
my $newsha2 = $newsha;
|
||||
$newsha2 = '' if $newsha =~ /^0+$/;
|
||||
system("git", "update-ref", $ref, $oldsha, $newsha2) and
|
||||
die "repo $repo, update-ref $ref $oldsha $newsha failed...\n";
|
||||
log_it("", "+\t$newsha\t$oldsha\t$repo\t$ref");
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
. $(dirname $0)/adc.common-functions
|
||||
|
||||
# the local site can have a file called gl-adc-help.txt, which will be used as
|
||||
# the *entire* help text for this site...
|
||||
|
||||
[ -f $HOME/gl-adc-help.txt ] && {
|
||||
cat $HOME/gl-adc-help.txt
|
||||
exit 0
|
||||
}
|
||||
|
||||
# or the local site will use the default help text in this file, with an
|
||||
# optional pre- and post- text that is site local (like maybe the admin's
|
||||
# contact details)
|
||||
|
||||
# pre
|
||||
[ -f $HOME/gl-adc-pre-help.txt ] && cat $HOME/gl-adc-pre-help.txt
|
||||
|
||||
# default help text
|
||||
cat <<EOF
|
||||
|
||||
The following adc's (admin-defined commands) are available at this site.
|
||||
|
||||
creating a "fork" of a repo:
|
||||
the 'fork' adc forks a repo that you have read access to, to a repo that
|
||||
you have create rights to
|
||||
|
||||
deleting/trashing repos:
|
||||
You can permanently remove a repo using 'rm'. By default, repos are
|
||||
protected ('lock'ed) from being 'rm'-ed. You have to first 'unlock' a
|
||||
repo before you can 'rm' it.
|
||||
|
||||
A different scheme of handling this is to use 'trash' to move the repo to
|
||||
a "trashcan" area. You can then 'list-trash' to see what you have, and
|
||||
you can then 'restore' whichever repo you need to bring back.
|
||||
|
||||
More details can be found at:
|
||||
http://github.com/sitaramc/gitolite/blob/pu/contrib/adc/repo-deletion.README
|
||||
|
||||
EOF
|
||||
|
||||
# post
|
||||
[ -f $HOME/gl-adc-post-help.txt ] && cat $HOME/gl-adc-post-help.txt
|
470
contrib/adc/hub
470
contrib/adc/hub
|
@ -1,470 +0,0 @@
|
|||
#!/usr/bin/perl -w
|
||||
|
||||
# SECURITY: look for the word SECURITY below and decide...
|
||||
|
||||
# handle pull-requests and related stuff
|
||||
|
||||
# developer notes:
|
||||
# - 'requestor' is too long, so I use "bob"; if you see the documentation
|
||||
# you'll realise this isn't as crazy as you think :-)
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
die "ENV GL_RC not set\n" unless $ENV{GL_RC};
|
||||
die "ENV GL_BINDIR not set\n" unless $ENV{GL_BINDIR};
|
||||
|
||||
sub usage {
|
||||
print STDERR <<'EOF';
|
||||
GENERAL USAGE: ssh git@server hub <hub-command> <args>
|
||||
|
||||
See docs for concepts; this usage message is only a refresher!
|
||||
|
||||
Requestor's commands (repo child):
|
||||
request-pull child b1 [parent]
|
||||
request-status child [parent] [request-number]
|
||||
Parent repo owner's commands (repo parent):
|
||||
list-requests parent
|
||||
view-request parent request-number
|
||||
view-log parent request-number <git log options>
|
||||
view-diff parent request-number <git diff options>
|
||||
reject parent request-number
|
||||
fetch parent request-number
|
||||
accept parent request-number
|
||||
|
||||
EOF
|
||||
exit 1;
|
||||
}
|
||||
|
||||
our $tempdir;
|
||||
END {
|
||||
wrap_chdir($ENV{GL_REPO_BASE_ABS});
|
||||
system("rm", "-rf", "$tempdir.git") if $tempdir and $tempdir =~ /gl-internal-temp-repo/;
|
||||
}
|
||||
|
||||
my %dispatch = (
|
||||
rp => \&rp,
|
||||
'request-pull' => \&rp,
|
||||
rs => \&rs,
|
||||
'request-status' => \&rs,
|
||||
lr => \&lr,
|
||||
'list-requests' => \&lr,
|
||||
vr => \&vr,
|
||||
'view-request' => \&vr,
|
||||
vl => \&vl,
|
||||
'view-log' => \&vl,
|
||||
vd => \&vd,
|
||||
'view-diff' => \&vd,
|
||||
reject => \&reject,
|
||||
fetch => \&fetch,
|
||||
accept => \&accept,
|
||||
);
|
||||
|
||||
my $cmd = shift || '';
|
||||
usage() unless ($dispatch{$cmd});
|
||||
|
||||
unshift @INC, $ENV{GL_BINDIR};
|
||||
require gitolite or die "parse gitolite.pm failed\n";
|
||||
gitolite->import;
|
||||
|
||||
# find what is effectively GL_ADC_PATH, then get the config var we're interested in
|
||||
use FindBin;
|
||||
my $BASE_FETCH_URL = `. $FindBin::Bin/adc.common-functions; echo \$BASE_FETCH_URL`;
|
||||
chomp($BASE_FETCH_URL);
|
||||
my $GL_FORKED_FROM = `. $FindBin::Bin/adc.common-functions; echo \$GL_FORKED_FROM`;
|
||||
chomp($GL_FORKED_FROM);
|
||||
|
||||
my @args = @ARGV; @ARGV = ();
|
||||
$dispatch{$cmd}->(@args);
|
||||
|
||||
# -------------------- bob's commands
|
||||
|
||||
sub rp {
|
||||
# request-pull child b1 [parent]
|
||||
usage() unless @_ == 2 or @_ == 3;
|
||||
|
||||
# implicitly gives owner-parent read access to part of child, so requestor
|
||||
# should already have read access to child (to prevent someone gaining
|
||||
# access to child by faking a pull request against it!)
|
||||
# XXX would it be better to ensure it is writable by Bob, because how/why
|
||||
# would he make a pull request if he didn't just write to it?
|
||||
my ($repo, $creator) = readable_repo(shift);
|
||||
my $ref = valid_ref($repo, shift);
|
||||
|
||||
# the parent is either explicitly given, or the name of the parent
|
||||
# recorded by the 'fork' ADC is used
|
||||
my $repo_to = shift || parent_repo($repo);
|
||||
# requestor need not have any access to parent; it is quite possible he
|
||||
# gets this via git-daemon or something, so we just need to make sure it's
|
||||
# a valid repo
|
||||
$repo_to = valid_repo($repo_to);
|
||||
|
||||
# the 'cover letter' message comes from STDIN
|
||||
my $cover = join("", <>);
|
||||
|
||||
# now create/update the pull request file
|
||||
cd2repo($repo_to);
|
||||
my %hub = get_hub();
|
||||
$hub{$repo}{$ref}{BOB} = $ENV{GL_USER};
|
||||
$hub{$repo}{$ref}{COVER} = $cover;
|
||||
$hub{$repo}{$ref}{TIME} = time();
|
||||
$hub{$repo}{$ref}{STATUS} = 'pending';
|
||||
dump_hub(%hub);
|
||||
}
|
||||
|
||||
sub rs {
|
||||
# request-status child [parent] [request-number]
|
||||
usage() unless @_ > 0 and @_ < 4; # 1 or 2 or 3
|
||||
# same checks as in 'rp' above
|
||||
my ($repo_from, $creator) = readable_repo(shift);
|
||||
|
||||
my $repo;
|
||||
if ($_[0] and $_[0] !~ /^\d+$/) {
|
||||
# next arg is not a number, so it should be 'parent'
|
||||
$repo = shift;
|
||||
} else {
|
||||
$repo = parent_repo($repo_from);
|
||||
}
|
||||
$repo = valid_repo($repo);
|
||||
|
||||
my $rqno = 0;
|
||||
$rqno = shift if ($_[0] and $_[0] =~ /^\d+$/);
|
||||
|
||||
# there should not be any arguments left over
|
||||
usage() if @_;
|
||||
|
||||
unless ($rqno) {
|
||||
cd2repo($repo);
|
||||
my %hub_full = get_hub();
|
||||
return unless $hub_full{$repo_from};
|
||||
my %hub; $hub{$repo_from} = $hub_full{$repo_from};
|
||||
|
||||
list_hub('', %hub);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
my ($child, $ref, %hub) = get_request_N($repo, $rqno);
|
||||
# this also does a chdir to $repo, by the way
|
||||
|
||||
my %hub1; $hub1{$child}{$ref} = $hub{$child}{$ref};
|
||||
list_hub('', %hub1);
|
||||
print "\nMessage:\n$hub1{$child}{$ref}{COVER}\n";
|
||||
}
|
||||
|
||||
# -------------------- alice's commands
|
||||
|
||||
sub lr {
|
||||
# list-requests parent [optional search strings]
|
||||
usage() unless @_ >= 1;
|
||||
|
||||
# Alice must have write access to parent, otherwise she can't really
|
||||
# accept a pull request eventually right?
|
||||
my ($repo, $creator) = writable_repo(shift);
|
||||
cd2repo($repo);
|
||||
my %hub = get_hub();
|
||||
return unless %hub;
|
||||
|
||||
# create the search pattern. ADC arg checking is very strict; it doesn't
|
||||
# allow &, | etc., so we just generate an OR condition out of the pieces
|
||||
my $patt = join("|", @_);
|
||||
list_hub($patt, %hub);
|
||||
}
|
||||
|
||||
sub vr {
|
||||
# view-request parent request-number
|
||||
usage() unless @_ == 2;
|
||||
my ($repo, $n) = @_;
|
||||
my ($child, $ref, %hub) = get_request_N($repo, $n);
|
||||
# this also does a chdir to $repo, by the way
|
||||
|
||||
my %hub1; $hub1{$child}{$ref} = $hub{$child}{$ref};
|
||||
list_hub('', %hub1);
|
||||
print "\nMessage:\n$hub1{$child}{$ref}{COVER}\n";
|
||||
}
|
||||
|
||||
sub vl {
|
||||
# view-log parent request-number <git log options>
|
||||
usage() unless @_ >= 2;
|
||||
|
||||
my ($repo, $n) = (shift, shift);
|
||||
my ($child, $ref, %hub) = get_request_N($repo, $n);
|
||||
|
||||
# so now we can find the set of SHAs that we already have
|
||||
# XXX should we include tags also?
|
||||
my @known_shas = grep { chomp; } `git for-each-ref refs/heads --format='%(objectname)'`;
|
||||
|
||||
# make a copy of the child repo (Bob's repo) containing only the ref being
|
||||
# offered for fetch, then cd to it. This is easier to do than to sanitise
|
||||
# all possible git-log arguments. We're doing this to prevent Alice from
|
||||
# seeing anything more than the ref offered.
|
||||
temp_clone($child, $ref);
|
||||
|
||||
# verify the list of "known_shas" because what's known in Alice's repo may
|
||||
# not be known here. While you're about it, negate them. (We don't want
|
||||
# to use "--not" because we're not sure what arguments the user will want
|
||||
# to add and we don't want to negate some of them by mistake
|
||||
@known_shas = grep { $_ = `git rev-parse --verify -q $_`; chomp && s/^/^/ } @known_shas;
|
||||
|
||||
# run the log command
|
||||
# XXX SECURITY XXX do we need to check these arguments? Don't forget they
|
||||
# are restricted by $ADC_CMD_ARGS_PATT (defined in gitolite_rc.pm), which
|
||||
# is pretty tight to start with, so we know this cannot be used to run
|
||||
# external programs. The question is, are any of git-log's arguments
|
||||
# dangerous in their own right?
|
||||
my @args = ('git', 'log', $ref);
|
||||
push @args, @known_shas if @known_shas;
|
||||
check_SHAs($ref, @_);
|
||||
# each SHA in @_ must be a parent of $ref. Non-shas are not allowed
|
||||
# since all refs other than $ref have been deleted in the temp clone
|
||||
push @args, @_ if @_;
|
||||
system @args;
|
||||
}
|
||||
|
||||
sub vd {
|
||||
# view-diff parent request-number <git diff options>
|
||||
usage() unless @_ >= 4;
|
||||
# we just check for 4 arguments; I guess later on we could also check
|
||||
# to make sure at least 2 of them are SHAs or something but unless
|
||||
# there's a security risk it's not needed
|
||||
|
||||
my ($repo, $n) = (shift, shift);
|
||||
my ($child, $ref, %hub) = get_request_N($repo, $n);
|
||||
# this also does a chdir to $repo, by the way
|
||||
|
||||
# now go to the child repo (Bob's repo)
|
||||
temp_clone($child, $ref);
|
||||
|
||||
# run the diff command
|
||||
# XXX SECURITY XXX do we need to check these arguments? Don't forget they
|
||||
# are restricted by $ADC_CMD_ARGS_PATT (defined in gitolite_rc.pm), which
|
||||
# is pretty tight to start with, so we know this cannot be used to run
|
||||
# external programs. The question is, are any of git-diff's arguments
|
||||
# dangerous in their own right?
|
||||
my @args = ('git', 'diff');
|
||||
check_SHAs($ref, @_);
|
||||
push @args, @_ if @_;
|
||||
system @args;
|
||||
}
|
||||
|
||||
sub reject {
|
||||
# reject parent request-number
|
||||
usage() unless @_ == 2;
|
||||
my ($repo, $n) = @_;
|
||||
writable_repo($repo); # yeah we're throwing away the return values
|
||||
my ($child, $ref, %hub) = get_request_N($repo, $n);
|
||||
|
||||
map { die "request status is already '$_'\n" if $_ ne 'pending' } $hub{$child}{$ref}{STATUS};
|
||||
|
||||
# the 'cover letter' message comes from STDIN
|
||||
my $cover = join("", <>);
|
||||
$hub{$child}{$ref}{STATUS} = "rejected by $ENV{GL_USER}";
|
||||
$hub{$child}{$ref}{COVER} .= "\n\nRejected. Message to requestor:\n$cover";
|
||||
dump_hub(%hub);
|
||||
}
|
||||
|
||||
sub fetch {
|
||||
# fetch parent request-number
|
||||
usage() unless @_ == 2;
|
||||
my ($repo, $n) = @_;
|
||||
writable_repo($repo); # yeah we're throwing away the return values
|
||||
my ($child, $ref, %hub) = get_request_N($repo, $n);
|
||||
|
||||
map { die "request status is already '$_'\n" if $_ ne 'pending' } $hub{$child}{$ref}{STATUS};
|
||||
|
||||
print "user $hub{$child}{$ref}{BOB} asked you to\n\tgit fetch $BASE_FETCH_URL/$child $ref\n";
|
||||
print "hit enter to accept the fetch request or Ctrl-C to cancel...";
|
||||
<>;
|
||||
|
||||
my $fetched_ref = "refs/heads/requests/child/$ref";
|
||||
# you're already chdir'd to parent, by get_request_N
|
||||
system("git", "update-ref", "-d", "refs/heads/$fetched_ref");
|
||||
system("git", "fetch", "$ENV{GL_REPO_BASE_ABS}/$child.git", "$ref:$fetched_ref");
|
||||
|
||||
$hub{$child}{$ref}{STATUS} = "fetched by $ENV{GL_USER}";
|
||||
dump_hub(%hub);
|
||||
}
|
||||
|
||||
sub accept {
|
||||
# accept parent request-number
|
||||
usage() unless @_ == 2;
|
||||
my ($repo, $n) = @_;
|
||||
writable_repo($repo); # yeah we're throwing away the return values
|
||||
my ($child, $ref, %hub) = get_request_N($repo, $n);
|
||||
|
||||
map { die "request status is '$_'; must be 'fetched'\n" if $_ !~ /^fetched by / } $hub{$child}{$ref}{STATUS};
|
||||
|
||||
# the 'cover letter' message comes from STDIN
|
||||
my $cover = join("", <>);
|
||||
$hub{$child}{$ref}{STATUS} = "accepted by $ENV{GL_USER}";
|
||||
$hub{$child}{$ref}{COVER} .= "\n\nAccepted. Message to requestor:\n$cover";
|
||||
dump_hub(%hub);
|
||||
}
|
||||
|
||||
# -------------------- service subs
|
||||
|
||||
sub assert {
|
||||
my ($expr, $message) = @_;
|
||||
eval $expr or die ($message ? "$message\n" : "assert '$expr' failed\n");
|
||||
}
|
||||
|
||||
sub cd2repo {
|
||||
my $repo = shift;
|
||||
wrap_chdir("$ENV{GL_REPO_BASE_ABS}/$repo.git");
|
||||
}
|
||||
|
||||
sub dump_hub {
|
||||
# pwd assumed to git repo.git; dump a file called "gl-adc-hub-requests"
|
||||
use Data::Dumper;
|
||||
$Data::Dumper::Indent = 1;
|
||||
$Data::Dumper::Sortkeys = 1;
|
||||
my %hub = @_;
|
||||
|
||||
my $fh = wrap_open(">", "gl-adc-hub-requests");
|
||||
print $fh Data::Dumper->Dump([\%hub], [qw(*hub)]);
|
||||
close $fh;
|
||||
}
|
||||
|
||||
sub get_hub {
|
||||
# pwd assumed to git repo.git; "do" a file called "gl-adc-hub-requests"
|
||||
|
||||
return () unless -w "gl-adc-hub-requests";
|
||||
our %hub = ();
|
||||
do "gl-adc-hub-requests" or die "error parsing gl-adc-hub-requests\n";
|
||||
return %hub;
|
||||
}
|
||||
|
||||
sub get_request_N {
|
||||
# given a repo and an N, return "child", "ref", and %hub (or die trying!)
|
||||
|
||||
# you can't look at pull requests for repos you don't have at least read access to
|
||||
my ($repo, $creator) = readable_repo(shift);
|
||||
cd2repo($repo);
|
||||
my %hub = get_hub();
|
||||
die "you have no pending requests\n" unless %hub;
|
||||
|
||||
my $n = shift || '';
|
||||
usage() unless ($n =~ /^\d+$/);
|
||||
|
||||
my @hub = hub_sort(%hub);
|
||||
die "you have only " . scalar(@hub) . " requests\n" if @hub < $n;
|
||||
$n--; # make it 0-relative
|
||||
return ($hub[$n]->{REPO}, $hub[$n]->{REF}, %hub);
|
||||
}
|
||||
|
||||
sub hub_sort {
|
||||
my %hub = @_;
|
||||
my %sorted_hub = ();
|
||||
for my $child (sort keys %hub) {
|
||||
for my $ref (sort keys %{ $hub{$child} }) {
|
||||
my $key = $hub{$child}{$ref}{TIME} . "-$child-$ref";
|
||||
$sorted_hub{$key} = { REPO=>$child, REF=>$ref };
|
||||
}
|
||||
}
|
||||
my @hub = ();
|
||||
for my $key (sort keys %sorted_hub) {
|
||||
push @hub, $sorted_hub{$key};
|
||||
}
|
||||
return @hub;
|
||||
}
|
||||
|
||||
sub list_hub {
|
||||
my ($status, %hub) = @_;
|
||||
|
||||
my $header = "#\tchild-repository-name\t(requestor)\tbranch-or-tag-to-pull\tstatus\n----\n";
|
||||
my @hub = hub_sort(%hub);
|
||||
my $sn = 0;
|
||||
for my $pr (@hub) {
|
||||
$sn++;
|
||||
my $child = $pr->{REPO};
|
||||
my $ref = $pr->{REF};
|
||||
my $pr_status = $hub{$child}{$ref}{STATUS};
|
||||
next if $status and $pr_status !~ /$status/;
|
||||
print $header if $header; $header = '';
|
||||
print "$sn\t$child\t($hub{$child}{$ref}{BOB})\t$ref\t$pr_status\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub parent_repo {
|
||||
my ($repo) = shift;
|
||||
cd2repo($repo);
|
||||
die "parent repo was not recorded, sorry!\n" unless -f $GL_FORKED_FROM;
|
||||
my $gff = `cat $GL_FORKED_FROM`;
|
||||
chomp($gff);
|
||||
return $gff;
|
||||
}
|
||||
|
||||
sub readable_repo {
|
||||
my $repo = valid_repo(shift);
|
||||
my ($perm, $creator) = check_access($repo);
|
||||
die "$repo does not exist or you have no read access\n" unless $perm =~ /R/;
|
||||
return ($repo, $creator);
|
||||
}
|
||||
|
||||
sub valid_log_options {
|
||||
}
|
||||
|
||||
sub valid_ref {
|
||||
my ($repo, $ref) = @_;
|
||||
cd2repo($repo);
|
||||
die "invalid ref $ref\n" unless `git cat-file -t $ref` =~ /^commit$/;
|
||||
die "invalid ref $ref\n" unless `git rev-parse $ref` =~ /^[0-9a-f]{40}$/;
|
||||
return $ref;
|
||||
}
|
||||
|
||||
sub valid_repo {
|
||||
my $repo = shift;
|
||||
$repo =~ s/\.git$//;
|
||||
die "$repo does not exist or you have no read access\n" unless -d "$ENV{GL_REPO_BASE_ABS}/$repo.git";
|
||||
return $repo;
|
||||
}
|
||||
|
||||
sub writable_repo {
|
||||
my $repo = valid_repo(shift);
|
||||
my ($perm, $creator) = check_access($repo);
|
||||
die "$repo does not exist or you have no write access\n" unless $perm =~ /W/;
|
||||
return ($repo, $creator);
|
||||
}
|
||||
|
||||
sub temp_clone {
|
||||
my ($repo, $ref) = @_;
|
||||
|
||||
die "internal error; temp_clone called twice?\n" if $tempdir;
|
||||
|
||||
# some of this code is also in "rrr" branch
|
||||
|
||||
# first make a temp directory within $REPO_BASE
|
||||
$ENV{TMPDIR} = $ENV{GL_REPO_BASE_ABS};
|
||||
$tempdir = `mktemp -d -t gl-internal-temp-repo.XXXXXXXXXX`;
|
||||
chomp($tempdir);
|
||||
rename $tempdir, "$tempdir.git";
|
||||
|
||||
# make the clone
|
||||
wrap_chdir("$ENV{GL_REPO_BASE_ABS}");
|
||||
system("git clone --mirror -l $repo.git $tempdir.git >/dev/null 2>&1");
|
||||
|
||||
# go to the clone and delete refs he's not allowed to read
|
||||
wrap_chdir("$ENV{GL_REPO_BASE_ABS}");
|
||||
wrap_chdir("$tempdir.git");
|
||||
# for each available ref
|
||||
for my $ar (`git for-each-ref refs '--format=%(refname)'`) {
|
||||
chomp($ar);
|
||||
system('git', 'update-ref', '-d', $ar) unless $ar eq "refs/heads/$ref";
|
||||
}
|
||||
|
||||
# you've already cd-d to the temp repo, just set the name up properly
|
||||
$tempdir =~ s/^\Q$ENV{GL_REPO_BASE_ABS}\///;
|
||||
}
|
||||
|
||||
sub check_SHAs {
|
||||
my $ref = shift;
|
||||
for (@_) {
|
||||
next unless /^[0-9a-f]+$/i;
|
||||
my $fullsha = `git rev-parse $_`;
|
||||
chomp($fullsha);
|
||||
die "invalid SHA: $_\n" unless $fullsha =~ /^[0-9a-f]{40}$/;
|
||||
my $mergebase = `git merge-base $fullsha $ref`;
|
||||
chomp($mergebase);
|
||||
die "invalid SHA: $_\n" unless $mergebase eq $fullsha;
|
||||
}
|
||||
}
|
|
@ -1,208 +0,0 @@
|
|||
# the 'hub' ADC
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_a_home_grown_hub_for_git_repos">a home grown 'hub' for git repos</a>
|
||||
* <a href="#_general_syntax">general syntax</a>
|
||||
* <a href="#_Bob_s_commands">Bob's commands</a>
|
||||
* <a href="#_Alice_s_just_looking_commands">Alice's "just looking" commands</a>
|
||||
* <a href="#_Alice_s_action_commands">Alice's "action" commands</a>
|
||||
* <a href="#_what_next_">what next?</a>
|
||||
* <a href="#_note_to_the_admin_configuration_variables">note to the admin: configuration variables</a>
|
||||
|
||||
<a name="_a_home_grown_hub_for_git_repos"></a>
|
||||
|
||||
### a home grown 'hub' for git repos
|
||||
|
||||
This ADC (admin-defined command) helps collaboration among repos. The name is
|
||||
in honor of github, which is the primary host for gitolite itself.
|
||||
|
||||
[Note that github is a web-based service, and does a lot more, like comments,
|
||||
code reviews, etc., none of which are possible here. We're only talking about
|
||||
some basic stuff to make the most common operations easier. In particular,
|
||||
this system is not a replacement for normal project communications like
|
||||
email!]
|
||||
|
||||
**Conventions used**: all through the following description, we will assume
|
||||
that **Alice** has a repo **parent**, **Bob** has a fork of parent called
|
||||
**child**, and he is asking Alice to pull a branch he made called **b1** from
|
||||
child to parent.
|
||||
|
||||
In plain git (without using github or similar), the pull request process
|
||||
starts with an email from Bob to Alice, followed by Alice running a `git fetch
|
||||
<Bob's URL> b1` (optionally preceded by a `git remote add` for convenience of
|
||||
long term use). Until this happens she can't see much detail about the
|
||||
commits to be pulled.
|
||||
|
||||
**What this ADC does** is (a) collect all the pull requests she needs to look
|
||||
at in one place, and (b) allow her to examine the changes with any combination
|
||||
of `git log` and `git diff` options *without having to fetch the content
|
||||
first*, and (c) act as a trusted intermediary to allow Alice to fetch *just
|
||||
one branch* from Bob even if she does not have any access to Bob's repository!
|
||||
|
||||
In a situation where there may be lots of requests, being able to take a quick
|
||||
look at them (and possibly reject some), without having to pull down anything
|
||||
at all, could be very useful.
|
||||
|
||||
Once past that level, she could get the changes down to her workstation using
|
||||
`git fetch` as normal. With this ADC, however, she has another alternative:
|
||||
get them over to `parent` (her repo) on the same gitolite server, then later
|
||||
do a normal `git fetch [origin]` to get it to her workstation. This has the
|
||||
added advantage that other people, who may be watching her repo but not Bob's,
|
||||
now get to see what Bob sent her and send comments etc.
|
||||
|
||||
<a name="_general_syntax"></a>
|
||||
|
||||
### general syntax
|
||||
|
||||
The general syntax is
|
||||
|
||||
ssh git@server hub <hub-command> <args>
|
||||
|
||||
<a name="_Bob_s_commands"></a>
|
||||
|
||||
#### Bob's commands
|
||||
|
||||
The following commands do not cause a fetch, and should be quite fast:
|
||||
|
||||
* Bob sends a pull request for branch b1 to repo parent. Notice he does not
|
||||
mention Alice by name. This command expects a message to be piped/typed
|
||||
in via STDIN [this message is meant to be transient and is not stored long
|
||||
term; use email for more "permanent" communications].
|
||||
|
||||
echo "hi Alice, please pull" | ssh git@server hub request-pull child b1 [parent]
|
||||
|
||||
If `child` was created by a recent version of the 'fork' ADC (or the KDE
|
||||
'clone' ADC), which records the name of the parent repo on a fork, and it
|
||||
is *that* repo to which Bob wishes to send the pull request, the third
|
||||
argument is optional.
|
||||
|
||||
* Bob lists the status (fetched/rejected/pending) of pull requests he has
|
||||
made from his repo child to repo parent. (Note we don't say "accepted" but
|
||||
"fetched"; see later for why):
|
||||
|
||||
ssh git@server hub request-status child [parent]
|
||||
|
||||
The second argument is optional the same way as the 3rd argument in the
|
||||
previous command.
|
||||
|
||||
Requests that have been accepted or rejected will usually have some
|
||||
additional text, supplied by the user who did the reject/accept. Bob can
|
||||
ask for those details by request number:
|
||||
|
||||
ssh git@server hub request-status child [parent] request-number
|
||||
|
||||
<a name="_Alice_s_just_looking_commands"></a>
|
||||
|
||||
#### Alice's "just looking" commands
|
||||
|
||||
* Alice lists requests waiting for her to check and possibly pull into
|
||||
parent. For each waiting pull request, she will see a serial number, the
|
||||
originating repo name (child, in our example), the requestor (Bob, here),
|
||||
and the branch/tag-name (b1) being pulled:
|
||||
|
||||
ssh git@server hub list-requests parent
|
||||
|
||||
This command also takes an optional list of search strings that are OR-d
|
||||
together and matched against the 'status' field. So saying
|
||||
|
||||
ssh git@server hub list-requests parent fetched pending
|
||||
|
||||
would list only items that were 'fetched' or 'pending' (meaning 'accepted'
|
||||
and 'rejected' would not show up).
|
||||
|
||||
* Alice views request # 1 waiting to be pulled into parent. Shows the same
|
||||
details as above for that request, followed by the message that Bob typed
|
||||
in when he ran `request-pull`:
|
||||
|
||||
ssh git@server hub view-request parent 1
|
||||
|
||||
* Alice views the log of the branch she is being asked to pull. Note that
|
||||
this does NOT involve a fetch, so it will be pretty fast. The log starts
|
||||
from b1, and stops at a SHA that represents any of the branches in parent.
|
||||
Alice can use any git-log options she wants to; for instance `--graph`,
|
||||
`--decorate`, `--boundary`, etc., could be quite useful. However, she
|
||||
can't use any GUI; it has to be 'git log':
|
||||
|
||||
ssh git@server hub view-log parent 1 <git log options>
|
||||
|
||||
Notice that the repo name Alice supplies is still her own, although the
|
||||
log comes from the child repo that Bob wants Alice to pull from. It's
|
||||
best if you think of this as "view the commits from pull request #1 in
|
||||
'parent'".
|
||||
|
||||
* Alice views the diff between arbitrary commits on child:
|
||||
|
||||
ssh git@server hub view-diff parent 1 <git diff options>
|
||||
|
||||
Again, she mentions *her* reponame but the diff's come from `child`. Also
|
||||
note that, due to restrictions on what characters are allowed in arguments
|
||||
to ADCs, you probably can't do things like `pu^` or `master~3`, and have
|
||||
to use SHAs instead.
|
||||
|
||||
<a name="_Alice_s_action_commands"></a>
|
||||
|
||||
#### Alice's "action" commands
|
||||
|
||||
* Alice doesn't like what she sees and decides to reject it. This command
|
||||
expects some text on STDIN as the rejection message:
|
||||
|
||||
echo "hi Bob, your patch needs work; see email" | ssh git@server hub reject parent 1
|
||||
|
||||
* Alice likes what she sees so far and wants to fetch the branch Bob is
|
||||
asking her to pull. Note that we are intentionally not using the word
|
||||
"accept", because this command does not (and cannot, since it is running
|
||||
on a bare repo on the server) do a pull. What it does is it fetches into
|
||||
a branch whose name will be `requests/child/b1`.
|
||||
|
||||
Note that when multiple requests from the same repo (child) for the same
|
||||
branch (b1) happen, each "fetch" overwrites the branch. This allows Bob
|
||||
to continually refine the branch he is requesting for a pull based on
|
||||
(presumably emailed) comments from Alice. In a way, this is a "remote
|
||||
tracking branch", just like `refs/remotes/origin/b1`.
|
||||
|
||||
ssh git@server hub fetch parent 1
|
||||
|
||||
This command will actually fetch from child into parent, and may take time
|
||||
when the changes are large. However all this is on the server so it does
|
||||
not involve network traffic:
|
||||
|
||||
* Alice has fetched the stuff she wants, looked at it/tested it, and decides
|
||||
to merge it into `parent`. Once that is done, she runs:
|
||||
|
||||
echo "thanks for the frobnitz patch Bob" | ssh git@server hub accept parent 1
|
||||
|
||||
to let Bob know next time he checks 'request-status'. Like the `reject`
|
||||
sub-command, this is also just a status update; no actual 'git' changes
|
||||
happen.
|
||||
|
||||
Notice the sequence of Alice's action commands: it's either 'reject', or a
|
||||
'fetch' then 'accept'.
|
||||
|
||||
<a name="_what_next_"></a>
|
||||
|
||||
### what next?
|
||||
|
||||
At this point, you're done with the `hub` ADC. However, all this is on the
|
||||
bare `parent.git` on the server, and nothing has hit Alice's workstation yet!
|
||||
Alice will still have to run a fetch or a pull on her workstation if she wants
|
||||
to check the code in detail, use a tool like gitk, and especially to
|
||||
compile/test it. *Then* she decides whether to accept or reject the request,
|
||||
which will have to be communicated via email, of course; see the second para
|
||||
of this document ;-)
|
||||
|
||||
Finally, note that Alice does not actually need to use the `fetch` subcommand.
|
||||
She can do the traditional thing and fetch Bob's repo/branch directly to her
|
||||
*workstation*.
|
||||
|
||||
<a name="_note_to_the_admin_configuration_variables"></a>
|
||||
|
||||
### note to the admin: configuration variables
|
||||
|
||||
There are 2 configuration variables. `BASE_FETCH_URL` should be set to a
|
||||
simple "read" URL (so it doesn't even have to be ssh) that almost anyone using
|
||||
this server can use. It's only used in producing the `git fetch` command
|
||||
mentioned just above.
|
||||
|
||||
`GL_FORKED_FROM` is set to `gl-forked-from` by default, but if your initials
|
||||
are `JM` you can set it to `kde-cloned-from` to save time and trouble ;-)
|
|
@ -1,13 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
. $(dirname $0)/adc.common-functions
|
||||
|
||||
# this is a helper ADC for "trash"; see that one for option settings etc
|
||||
|
||||
cd $TRASH_CAN 2>/dev/null || exit 0
|
||||
find . -name gl-creater | sort | while read t
|
||||
do
|
||||
owner=
|
||||
owner=`cat "$t"`
|
||||
[ "$owner" = "$GL_USER" ] && dirname $t
|
||||
done | cut -c3-
|
|
@ -1,12 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
. $(dirname $0)/adc.common-functions
|
||||
|
||||
# this is a helper ADC for "rm"; see that one for documentation
|
||||
|
||||
# cd to repo base and make sure arg1 is a valid repo (also sets $repo)
|
||||
valid_owned_repo $1
|
||||
|
||||
rm -f $repo.git/gl-rm-ok
|
||||
|
||||
echo "$repo has been locked. Please run the 'help' adc for more info."
|
|
@ -1,115 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Original author: Richard Bateman <taxilian@gmail.com>
|
||||
#
|
||||
# Any questions or concerns about how this works should be addressed to
|
||||
# me, not to sitaram. Please note that neither I nor sitaram make any
|
||||
# guarantees about the security or usefulness of this script. It may
|
||||
# be used without warantee or any guarantee of any kind.
|
||||
#
|
||||
# That said, it works fine for me.
|
||||
#
|
||||
# This script is licensed under the New BSD license
|
||||
# Copyright 2011 Richard Bateman
|
||||
#
|
||||
|
||||
import sys, os
|
||||
from pygitolite import *
|
||||
|
||||
def list(gl, user, repo, filter_var = ""):
|
||||
perms = gl.get_perms(repo, user)
|
||||
for var, ppl in perms.iteritems():
|
||||
if filter_var == "" or filter_var == var:
|
||||
print "%s:" % var
|
||||
for item in ppl:
|
||||
print " %s" % item
|
||||
|
||||
def clear(gl, user, repo, filter_var = ""):
|
||||
try:
|
||||
os.system(r"echo Are you sure? Type YES \(all caps\) to continue: ")
|
||||
bval = raw_input()
|
||||
if bval != "YES":
|
||||
print "Canceling..."
|
||||
|
||||
if filter_var == "":
|
||||
gl.set_perms(repo, user, {})
|
||||
else:
|
||||
perms = gl.get_perms(repo, user)
|
||||
if filter_var in perms:
|
||||
del perms[filter_var]
|
||||
gl.set_perms(repo, user, perms)
|
||||
print "Perms after clear:"
|
||||
list(gl, user, repo)
|
||||
except:
|
||||
print "An error occured"
|
||||
|
||||
def add(gl, user, repo, var, *users):
|
||||
perms = gl.get_perms(repo, user)
|
||||
if var not in perms:
|
||||
perms[var] = []
|
||||
if len(users) == 0:
|
||||
print "Usage: perms add %s %s <username>" % (repo, var)
|
||||
return
|
||||
for cur in users:
|
||||
if cur not in perms[var]:
|
||||
perms[var].append(cur)
|
||||
gl.set_perms(repo, user, perms)
|
||||
list(gl, user, repo, var)
|
||||
|
||||
def set(gl, user, repo, var, *users):
|
||||
perms = gl.get_perms(repo, user)
|
||||
perms[var] = []
|
||||
if len(users) == 0:
|
||||
print "Usage: perms set %s %s <username>" % (repo, var)
|
||||
return
|
||||
for cur in users:
|
||||
if cur not in perms[var]:
|
||||
perms[var].append(cur)
|
||||
gl.set_perms(repo, user, perms)
|
||||
list(gl, user, repo, var)
|
||||
|
||||
def remove(gl, user, repo, var, *users):
|
||||
perms = gl.get_perms(repo, user)
|
||||
if var not in perms:
|
||||
print "%s isn't a valid type" % var
|
||||
return
|
||||
if len(users) == 0:
|
||||
print "No users specified to remove; perhaps you want clear?"
|
||||
return
|
||||
for cur in users:
|
||||
if cur in perms[var]:
|
||||
perms[var].remove(cur)
|
||||
gl.set_perms(repo, user, perms)
|
||||
list(gl, user, repo, var)
|
||||
|
||||
commands = {
|
||||
"list": list,
|
||||
"clear": clear,
|
||||
"add": add,
|
||||
"set": set,
|
||||
"remove": remove,
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
if "GL_USER" not in os.environ:
|
||||
raise "No user!"
|
||||
user = os.environ["GL_USER"]
|
||||
command = sys.argv[1] if len(sys.argv) > 2 else ""
|
||||
if len(sys.argv) < 3 or command not in commands:
|
||||
print "Usage: perms <command> <repository> <args>"
|
||||
print " list <repository> [TYPE]"
|
||||
print " clear <repository>"
|
||||
print " add <repository> <TYPE> [user and group list]"
|
||||
print " set <repository> <TYPE> [user and group list]"
|
||||
print " remove <repository> <TYPE> [user and group list]"
|
||||
sys.exit(1)
|
||||
repo = sys.argv[2]
|
||||
|
||||
gl = gitolite()
|
||||
rights, owner = gl.get_rights_and_owner(repo, user)
|
||||
|
||||
if owner != user:
|
||||
print "Either %s does not exist or you are not the owner." % repo
|
||||
sys.exit(1)
|
||||
|
||||
commands[command](gl, user, repo, *sys.argv[3:])
|
|
@ -1,77 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Original author: Richard Bateman <taxilian@gmail.com>
|
||||
#
|
||||
# Any questions or concerns about how this works should be addressed to
|
||||
# me, not to sitaram. Please note that neither I nor sitaram make any
|
||||
# guarantees about the security or usefulness of this script. It may
|
||||
# be used without warantee or any guarantee of any kind.
|
||||
#
|
||||
# This script is licensed under the New BSD license
|
||||
# Copyright 2011 Richard Bateman
|
||||
#
|
||||
|
||||
import sys, os, subprocess
|
||||
|
||||
class gitolite(object):
|
||||
def __init__(self, **kvargs):
|
||||
self.GL_BINDIR = kvargs["GL_BINDIR"] if "GL_BINDIR" in kvargs else os.environ["GL_BINDIR"]
|
||||
self.user = kvargs["GL_USER"] if "GL_USER" in kvargs else os.environ["GL_USER"]
|
||||
pass
|
||||
|
||||
def gitolite_execute(self, command, std_inputdata = None):
|
||||
cmd = "perl -I%s -Mgitolite -e '%s'" % (self.GL_BINDIR,command)
|
||||
p = subprocess.Popen(cmd, shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE, stdin = subprocess.PIPE)
|
||||
stdout, stderr = p.communicate(std_inputdata)
|
||||
if p.returncode is not 0:
|
||||
raise Exception(stderr)
|
||||
return stdout.strip()
|
||||
|
||||
def run_custom_command(self, repo, user, command, extra = None):
|
||||
os.environ["SSH_ORIGINAL_COMMAND"] = "%s %s" % (command, repo)
|
||||
return self.gitolite_execute('run_custom_command("%s")' % user, extra)
|
||||
|
||||
def get_perms(self, repo, user):
|
||||
full = self.run_custom_command(repo, user, "getperms")
|
||||
plist = full.split("\n")
|
||||
perms = {}
|
||||
for line in plist:
|
||||
if line == "":
|
||||
continue
|
||||
var, strlist = line.split(" ", 1)
|
||||
perms[var] = strlist.split(" ")
|
||||
|
||||
return perms
|
||||
|
||||
def set_perms(self, repo, user, perms):
|
||||
permstr = ""
|
||||
for var, curlist in perms.iteritems():
|
||||
if len(curlist) == 0:
|
||||
continue;
|
||||
varstr = var
|
||||
for cur in curlist:
|
||||
varstr += " %s" % cur
|
||||
permstr = permstr + "\n" + varstr
|
||||
resp = self.run_custom_command(repo, user, "setperms", permstr.strip())
|
||||
|
||||
def valid_owned_repo(self, repo, user):
|
||||
rights, user = self.get_rights_and_owner(repo, user)
|
||||
return owner == user
|
||||
|
||||
def get_rights_and_owner(self, repo, user):
|
||||
if not repo.endswith(".git"):
|
||||
repo = "%s.git" % repo
|
||||
ans = self.gitolite_execute('cli_repo_rights("%s")' % repo)
|
||||
perms, owner = ans.split(" ")
|
||||
rights = {"Read": "R" in perms, "Write": "W" in perms, "Create": "C" in perms}
|
||||
return rights, owner
|
||||
|
||||
if __name__ == "__main__":
|
||||
if "GL_USER" not in os.environ:
|
||||
raise "No user!"
|
||||
user = os.environ["GL_USER"]
|
||||
repo = sys.argv[1]
|
||||
|
||||
gl = gitolite()
|
||||
print gl.get_rights_and_owner(repo, user)
|
||||
print gl.get_perms(repo, user)
|
|
@ -1,48 +0,0 @@
|
|||
# deleting repos safely
|
||||
|
||||
(see http://groups.google.com/group/gitolite/browse_thread/thread/fb9cf5a464b6dfee )
|
||||
|
||||
By default, the old 'rmrepo' ADC (admin-defined command) just went and deleted
|
||||
the repo -- no questions asked! Sometimes, that could be a disaster -- you
|
||||
lose the whole thing in one mad moment of typo-ing or frustration. Ouch.
|
||||
|
||||
This has been replaced by 2 families of ADCs. I say "families" because each
|
||||
has one main command and 2 ancillary ones. Admins can choose to install
|
||||
either, both, or neither family of commands.
|
||||
|
||||
Local settings for these ADCs can be found in the common settings file
|
||||
"adc.common-functions".
|
||||
|
||||
1. 'rm' will remove the repo. If USE_LOCK_UNLOCK is set, rm will refuse to
|
||||
remove a locked repo. All repos are locked by default, and you have to
|
||||
explicitly 'unlock' a repo to remove it. You can also 'lock' it again
|
||||
instead of removing it of course.
|
||||
|
||||
There's also ARE_YOU_SURE, for situations where a simple warning suffices.
|
||||
|
||||
You can also use both these flags if you wish.
|
||||
|
||||
2. 'trash' will move the repo to a safe location. There are settings for
|
||||
where this location is and what suffix is added to the repo name. You can
|
||||
'list-trash' to see what trash you have collected, and you can 'restore'
|
||||
one of the listed repos.
|
||||
|
||||
It's easy to automatically clean out the trash occasionally. By default,
|
||||
entries in the trash look like this:
|
||||
|
||||
foo/r1/2010-10-22_13:14:24
|
||||
foo/r1/2010-10-22_13:14:50
|
||||
|
||||
This shows a repo foo/r1 that was created and trashed twice.
|
||||
|
||||
Since the date appears in the name, you can use it with a cutoff to clean
|
||||
up old repos. Untested example:
|
||||
|
||||
cutoff=`date -I -d '28 days ago'`
|
||||
find $TRASH_CAN -type d -name "20??-??-??_*" | while read r
|
||||
do
|
||||
d=`basename $r`
|
||||
[[ $d < $cutoff ]] && rm -rf $r
|
||||
done
|
||||
|
||||
Put this in cron to run once a day and that should be it.
|
|
@ -1,16 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
. $(dirname $0)/adc.common-functions
|
||||
|
||||
repo=$1
|
||||
[ -z "$1" ] && die need a repo name
|
||||
|
||||
owner=
|
||||
owner=`cat $TRASH_CAN/$repo/gl-creater 2>/dev/null`
|
||||
[ "$owner" = "$GL_USER" ] || die "$repo is not yours!"
|
||||
|
||||
cd $TRASH_CAN
|
||||
realrepo=`dirname $repo`
|
||||
[ -d $GL_REPO_BASE_ABS/$realrepo.git ] && die $realrepo already exists
|
||||
mv $repo $GL_REPO_BASE_ABS/$realrepo.git
|
||||
echo $repo restored to $realrepo
|
|
@ -1,11 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
. $(dirname $0)/adc.common-functions
|
||||
|
||||
get_rights_and_owner gitolite-admin
|
||||
[ -z "$perm_write" ] && die "just *what* are you trying to pull, young man?"
|
||||
|
||||
# and here you let them do the dangerous stuff
|
||||
echo "+rm -rf $GL_REPO_BASE_ABS"
|
||||
sleep 2
|
||||
echo ...just kidding!
|
|
@ -1,39 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
. $(dirname $0)/adc.common-functions
|
||||
|
||||
[ -z "$GL_RC" ] && die "ENV GL_RC not set"
|
||||
|
||||
# options settable in adc.common-functions are
|
||||
# ARE_YOU_SURE -- prompts "are you sure?"
|
||||
# USE_LOCK_UNLOCK -- allows delete only if repo is "unlock"ed
|
||||
# As shipped, both options are set. If you set both of them to "0", repos are
|
||||
# just deleted blindly, with no confirmation
|
||||
|
||||
# helper ADCs: lock, unlock
|
||||
|
||||
# cd to repo base and make sure arg1 is a valid repo (also sets $repo)
|
||||
valid_owned_repo $1
|
||||
|
||||
opt $USE_LOCK_UNLOCK && {
|
||||
if [ -f $repo.git/gl-rm-ok ]
|
||||
then
|
||||
:
|
||||
else
|
||||
die "$repo is locked! Please run the 'help' adc for more info."
|
||||
fi
|
||||
}
|
||||
|
||||
opt $ARE_YOU_SURE && {
|
||||
echo "Are you sure? (type 'yes' if you are)" >&2
|
||||
read s
|
||||
[ $s = "yes" ] || die aborting...
|
||||
}
|
||||
|
||||
rm -rf $repo.git
|
||||
echo "$repo is now GONE!"
|
||||
|
||||
cd $HOME
|
||||
PROJECTS_LIST=$($GL_BINDIR/gl-query-rc PROJECTS_LIST)
|
||||
export repo
|
||||
perl -ni -e 'print unless /^\Q$ENV{repo}.git\E$/' $PROJECTS_LIST
|
|
@ -1,4 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo "this command no longer exists. Please run the 'help' adc for more info."
|
||||
exit 1
|
|
@ -1,150 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
# Copyright 2011, David Bremner <bremner@debian.org>
|
||||
#
|
||||
# This add-on to gitolite is licensed under the same terms as gitolite
|
||||
# At the time of this writing this is GPL-2, but I also grant
|
||||
# Sitaram Chamarty the right to re-license as he chooses.
|
||||
|
||||
=pod
|
||||
|
||||
S3BACKUP - Backup the whole gitolite home directory to amazon s3.
|
||||
|
||||
RUNNING
|
||||
|
||||
To run it (assuming you call this "s3backup")
|
||||
As an ADC, only by a user with read access to gitolite-admin :
|
||||
|
||||
ssh git@server s3backup [-v error|warning|notice|info|debug] [subcommands]
|
||||
|
||||
You must pass the AWS_SECRET_ACCESS_KEY on stdin.
|
||||
|
||||
SUBCOMMANDS
|
||||
|
||||
You may optionally pass one of the following sub commands
|
||||
|
||||
=over
|
||||
|
||||
=item incr|full
|
||||
|
||||
Run incremental or full backup. By default, leave it to duplicity to
|
||||
guess.
|
||||
|
||||
=item prune
|
||||
|
||||
remove all but $S3_KEEP_FULL (see Configuration below)
|
||||
|
||||
=back
|
||||
|
||||
OPTIONS
|
||||
|
||||
-v specifies a log level, passed straight to duplicity.
|
||||
incr or full specify backup level
|
||||
|
||||
CONFIGURATION
|
||||
|
||||
Make a file ~git/.s3backup.rc that looks like
|
||||
|
||||
$S3_EUROPE=0; # 1 to store in europe
|
||||
# (only matters at creation)
|
||||
$S3_KEEP_FULL=3; # keep 3 full backups
|
||||
$S3_BUCKET="my_bucket"; # s3 bucket name, will be created
|
||||
# if it doesn't exist.
|
||||
$S3_AWS_KEY_ID="ABADABA57DOO"; # this is the _non_ secret one
|
||||
$S3_ENCRYPT_KEY="DEADBEEF AA232332"; # gpg keys, space delimited.
|
||||
# note that duplicity will abort if
|
||||
# these keys are not trusted
|
||||
=cut
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
die "ENV GL_RC not set\n" unless $ENV{GL_RC};
|
||||
die "ENV GL_BINDIR not set\n" unless $ENV{GL_BINDIR};
|
||||
|
||||
unshift @INC, $ENV{GL_BINDIR};
|
||||
require gitolite or die "parse gitolite.pm failed\n";
|
||||
gitolite->import;
|
||||
|
||||
my ($perm, $creator) = check_access("gitolite-admin");
|
||||
die "no read access to gitolite-admin\n" unless $perm =~ /R/;
|
||||
|
||||
our ($S3_EUROPE, $S3_BUCKET, $S3_AWS_KEY_ID, $S3_ENCRYPT_KEYS, $S3_KEEP_FULL);
|
||||
|
||||
chdir($ENV{HOME}) or die "chdir $ENV{HOME} : $!\n";
|
||||
|
||||
my $configfile = $ENV{HOME} . "/.s3backup.rc";
|
||||
|
||||
do $configfile or die "error parsing $configfile\n";
|
||||
|
||||
# ANCHOR ALL PATTERNS
|
||||
die 'bad value for $S3_EUROPE'
|
||||
unless (defined($S3_EUROPE) && $S3_EUROPE =~ m/^0|1$/);
|
||||
|
||||
die 'bad value for $S3_KEEP_FULL'
|
||||
unless (defined($S3_KEEP_FULL) && $S3_KEEP_FULL =~ m/^[0-9]+$/);
|
||||
|
||||
die 'bad value for $S3_BACKUP'
|
||||
unless (defined($S3_BUCKET) && $S3_BUCKET =~ m/^[a-z\-_0-9\.]+$/);
|
||||
|
||||
die 'bad value for $S3_AWS_KEY_ID'
|
||||
unless (defined($S3_AWS_KEY_ID) && $S3_AWS_KEY_ID =~ m/^[A-Z0-9]+$/);
|
||||
|
||||
die 'bad value for $S3_ENCRYPT_KEYS'
|
||||
unless (defined($S3_ENCRYPT_KEYS) &&
|
||||
$S3_ENCRYPT_KEYS =~ m/^[a-fA-F0-9]+(\s+[a-fA-F0-9]+)*/);
|
||||
|
||||
my $verbosity='notice';
|
||||
if (scalar(@ARGV)>0 and $ARGV[0] eq '-v'){
|
||||
shift;
|
||||
$verbosity = shift;
|
||||
}
|
||||
|
||||
die "bad verbosity" unless ($verbosity =~ m/^(error|warning|notice|info|debug)$/);
|
||||
|
||||
my $subcommand=shift || 'default';
|
||||
|
||||
die "bad subcommand" if (defined($subcommand) &&
|
||||
$subcommand !~ m/^(incr|full|prune|default)$/);
|
||||
|
||||
$ENV{AWS_ACCESS_KEY_ID}=$S3_AWS_KEY_ID;
|
||||
|
||||
chomp($ENV{AWS_SECRET_ACCESS_KEY}=<>) or
|
||||
die "must pass SECRET_ACCESS_KEY on stdin";
|
||||
|
||||
my @args=();
|
||||
|
||||
if ($subcommand ne 'default' ){
|
||||
if ($subcommand eq 'prune') {
|
||||
push(@args, 'remove-all-but-n-full', $S3_KEEP_FULL, '--force');
|
||||
} else {
|
||||
push(@args, $subcommand);
|
||||
}
|
||||
}
|
||||
|
||||
push(@args, '--verb', $verbosity);
|
||||
push(@args, '--s3-use-new-style');
|
||||
foreach my $key (split(' ',$S3_ENCRYPT_KEYS)){
|
||||
push(@args, '--encrypt-key', $key);
|
||||
}
|
||||
|
||||
push(@args, '--s3-european-buckets') if ($S3_EUROPE);
|
||||
|
||||
push(@args, $ENV{HOME}) unless ($subcommand eq 'prune');
|
||||
|
||||
push(@args, 's3+http://'.$S3_BUCKET);
|
||||
|
||||
my $semaphore=$ENV{HOME}."/.gitolite.down";
|
||||
|
||||
die "$semaphore already exists" if (-f $semaphore);
|
||||
|
||||
eval {
|
||||
open (SEMFD,'>',$semaphore) or die ("failed to open $semaphore");
|
||||
my $now = gmtime();
|
||||
print SEMFD "Repo unavailable due to $subcommand backup started at $now GMT\n";
|
||||
close SEMFD;
|
||||
|
||||
system '/usr/bin/duplicity', @args;
|
||||
|
||||
};
|
||||
|
||||
unlink $semaphore;
|
|
@ -1,17 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
. $(dirname $0)/adc.common-functions
|
||||
|
||||
[ -z "$GL_RC" ] && die "ENV GL_RC not set"
|
||||
|
||||
[ -z "$2" ] && die "usage: set-head /path/to/repo.git refs/heads/branchname"
|
||||
|
||||
get_rights_and_owner $1; to=$repo
|
||||
[ -z "$perm_write" ] && die "no write permissions on $to"
|
||||
|
||||
# change head
|
||||
cd $GL_REPO_BASE_ABS/$to.git
|
||||
|
||||
git symbolic-ref HEAD $2
|
||||
echo HEAD on $to is `git symbolic-ref HEAD`
|
||||
cd - > /dev/null
|
|
@ -1,56 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# adc for someone with admin privs to invoke "expand" on other users.
|
||||
|
||||
# This doc block as "WHY", "HOW", and "CAVEATS" sections; I mention that only
|
||||
# for those people with very small xterms who may miss the CAVEATS section
|
||||
# otherwise...!
|
||||
|
||||
# WHY
|
||||
# ===
|
||||
|
||||
# ...because info has it, and expand doesn't :-)
|
||||
|
||||
# (Possible question: Why not add that capability to expand instead to be
|
||||
# consistent? Probable answer: how about we go the other way and make
|
||||
# "info" also work like this, and remove that code from core? I like
|
||||
# having less less code in core!)
|
||||
|
||||
# HOW
|
||||
# ===
|
||||
|
||||
# ssh gitolite su-expand . user1 user2 user3
|
||||
|
||||
# note that the first argument is still treated as a "pattern", so at
|
||||
# least put in a "." for a catch-all pattern. Also see caveats for
|
||||
# patterns below.
|
||||
|
||||
# This will output the same thing as "ssh git@server expand ." performed
|
||||
# by the individual users
|
||||
|
||||
# CAVEATS
|
||||
# =======
|
||||
|
||||
# (1) LIMITS TO THE PATTERN
|
||||
|
||||
# Due to this being an ADC, and ADC arguments being very, Very, VERY,
|
||||
# stricly limited, you won't be able to use any regex meta characters
|
||||
# expect ".". I'll worry about changing it if enough people complain.
|
||||
|
||||
# (2) NAME OF THIS SCRIPT
|
||||
|
||||
# please name this script something other than "expand", because we can't
|
||||
# have name clashes between internal commands (info, expand,
|
||||
# (get|set)(perms|desc), etc) and admin-defined (external) commands. I'm
|
||||
# calling it su-expand; feel free to change it.
|
||||
|
||||
. $(dirname $0)/adc.common-functions
|
||||
|
||||
get_rights_and_owner gitolite-admin
|
||||
[ -z "$perm_write" ] && die "just *what* are you trying to pull here, $GL_USER?"
|
||||
pat="$1"; shift
|
||||
|
||||
for user
|
||||
do
|
||||
SSH_ORIGINAL_COMMAND="expand $pat" $GL_BINDIR/gl-auth-command $user
|
||||
done
|
|
@ -1,24 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# this command is pretty cool, even if I may say so myself :)
|
||||
|
||||
# for any ADC that a normal user can run, like
|
||||
|
||||
# ssh git@server adc arguments
|
||||
|
||||
# this adc lets a "super user" (defined as "have write access to the
|
||||
# gitolite-admin repo"), do this
|
||||
|
||||
# ssh git@server sudo normal_user adc arguments
|
||||
|
||||
. $(dirname $0)/adc.common-functions
|
||||
|
||||
get_rights_and_owner gitolite-admin
|
||||
[ -z "$perm_write" ] && die "just *what* are you trying to pull, young man?"
|
||||
|
||||
user="$1"; shift
|
||||
cmd="$1"; shift
|
||||
|
||||
GL_USER=$user; export GL_USER
|
||||
[ -x $(dirname $0)/$cmd ] || die "no adc called $cmd"
|
||||
exec $(dirname $0)/$cmd "$@"
|
|
@ -1,29 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
. $(dirname $0)/adc.common-functions
|
||||
|
||||
# options settable in adc.common-functions are
|
||||
# TRASH_CAN -- where the trashed repos are moved. Can be anywhere that the
|
||||
# hosting user has write access to. Does not have to be (and ideally
|
||||
# should NOT be) inside $GL_REPO_BASE_ABS (but see note below)
|
||||
# TRASH_SUFFIX -- a timestamp, (ideally and by default), to be
|
||||
# suffixed to the moved repo
|
||||
|
||||
# helper ADCs: list-trash, restore
|
||||
|
||||
# NOTE: although I would NOT advise it in the interests of keeping things
|
||||
# simple, it *is* possible to have even deleted repos be *directly* accessible
|
||||
# via normal gitolite mechanisms (clone, etc). Here's how:
|
||||
# (1) make TRASH_CAN point somewhere *within* $REPO_BASE
|
||||
# (2) change TRASH_SUFFIX to something that has a .git at the end, like:
|
||||
# TRASH_SUFFIX=`date +%Y-%m-%d-%H-%M-%S`.git
|
||||
# (3) set ACL rules in conf/gitolite.conf for repos named
|
||||
# deleted/foo/sitaram/bar.*
|
||||
|
||||
# cd to repo base and make sure arg1 is a valid repo (also sets $repo)
|
||||
valid_owned_repo $1
|
||||
|
||||
mkdir -p $TRASH_CAN/$repo 2>/dev/null || die "failed creating directory in trashcan"
|
||||
[ -d $TRASH_CAN/$repo/$TRASH_SUFFIX ] && die try again in a few seconds
|
||||
mv $repo.git $TRASH_CAN/$repo/$TRASH_SUFFIX
|
||||
echo "$repo moved to trashcan. Please run the 'help' adc for more info."
|
|
@ -1,12 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
. $(dirname $0)/adc.common-functions
|
||||
|
||||
# this is a helper ADC for "rm"; see that one for documentation
|
||||
|
||||
# cd to repo base and make sure arg1 is a valid repo (also sets $repo)
|
||||
valid_owned_repo $1
|
||||
|
||||
touch $repo.git/gl-rm-ok
|
||||
|
||||
echo "$repo has been unlocked. Please run the 'help' command for more info."
|
|
@ -1,85 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
. $(dirname $0)/adc.common-functions
|
||||
|
||||
# Copyright 2010 Massachusetts Institute of Technology
|
||||
#
|
||||
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
# This "watch" ADC can be used to maintain a list of watchers to a
|
||||
# repository. You can then perform actions on the watchlist from a
|
||||
# hook or ADC.
|
||||
#
|
||||
# An obvious function of this would be to maintain a list of email
|
||||
# addresses that are sent commit notifications. There are however
|
||||
# unlimited uses, such as:
|
||||
#
|
||||
# * Specifying Twitter accounts that should receive notifications
|
||||
# of new clones created via the "fork" ADC
|
||||
# * Specifying hostnames of machines that should be poked to update
|
||||
# their repository web views
|
||||
# * Etc...
|
||||
#
|
||||
# The parameters are the repository path, "add"/"remove", and the
|
||||
# identifier. These are added along with your system identifier to a
|
||||
# gl-watchers file. However, there is an optional argument that allows you
|
||||
# specify what the identifier is used for. This allows you to perform
|
||||
# a default action if there is no optional argument, or a specific action
|
||||
# depending on what the optional argument. For instance, the gl-watchers
|
||||
# file on the server might look like this (note the actions described would
|
||||
# only occur if you actually code it in!):
|
||||
#
|
||||
# mitchell mitchell@kde.org [no optional argument; would default to email]
|
||||
# mitchell mitchell@kde.org email [will send email on pushes]
|
||||
# mitchell projects.kde.org httppost [will send commit details in an
|
||||
# HTTP POST to proejcts.kde.org]
|
||||
#
|
||||
#
|
||||
# Note that there is no authentication here; any user is allowed to
|
||||
# set any identifier, although users can only modify their own
|
||||
# identifiers. (This applies of course only to repositories a user can read
|
||||
# in the first place!) This script can easily be modified to only allow only
|
||||
# administrators (those with write access to the gitolite
|
||||
# administration repository) to add or remove watchers. See the
|
||||
# commented code below; uncomment it to enable this functionality.
|
||||
|
||||
# Adminstrators can use the "sudo" ADC to add entries for specific
|
||||
# users.
|
||||
|
||||
# Uncomment this and comment the corresponding block below to
|
||||
# restrict this functionality to administrators only
|
||||
#get_rights_and_owner gitolite-admin
|
||||
#[ -z "$perm_write" ] && die "just *what* are you trying to pull, young man?"
|
||||
#get_rights_and_owner $1;
|
||||
|
||||
# Comment this block if uncommenting the above block
|
||||
get_rights_and_owner $1;
|
||||
[ -z "$perm_read" ] && die "no read permissions on $repo"
|
||||
|
||||
cmd=$2
|
||||
identifier=$3
|
||||
arg=$4
|
||||
[ -z "$cmd" -o -z "$identifier" -o "$cmd" != "add" -a "$cmd" != "remove" ] && die "paramters must be <repopath> <add|remove> <identifier> <optional argument>"
|
||||
|
||||
if [ ! -z "$arg" ]
|
||||
then
|
||||
identarg="$identifier $arg"
|
||||
else
|
||||
identarg="$identifier"
|
||||
fi
|
||||
|
||||
cd $GL_REPO_BASE_ABS/$repo.git
|
||||
[ ! -e gl-watchers ] && { touch gl-watchers || die "cannot create blank watchers file"; }
|
||||
[ ! -r gl-watchers ] && die "cannot read watchers file"
|
||||
|
||||
grep "^$GL_USER $identarg$" gl-watchers > /dev/null
|
||||
found=$?
|
||||
|
||||
[ $found -eq 0 -a $cmd == "add" ] && die "There is already a watch \"$identarg\" for user $GL_USER"
|
||||
[ $found -ne 0 -a $cmd == "remove" ] && die "No watch \"$identarg\" found for user $GL_USER"
|
||||
|
||||
[ $cmd == "add" ] && echo "$GL_USER $identarg" >> gl-watchers && { echo "Added a watch \"$identarg\" for user $GL_USER"; exit 0; }
|
||||
|
||||
[ $cmd == "remove" ] && sed -i -e "/^$GL_USER $identarg$/d" gl-watchers && { echo "Removed a watch \"$identarg\" for user $GL_USER"; exit 0; }
|
||||
|
||||
die "16 cores, 320GB of RAM, 4TB of disk, and you give me a command I am not programmed to do. Humans..."
|
|
@ -1,33 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# find the last person to push the given commit
|
||||
|
||||
# XXX we assume the logfile names have been left as default, or at least, if
|
||||
# changed, in such a way that when sorted by "ls", they come up oldest first
|
||||
|
||||
. $(dirname $0)/adc.common-functions
|
||||
|
||||
sha=$2
|
||||
[ -n "$sha" ] || die Usage: ssh ... who-pushed reponame SHA \# at least first few hex digits
|
||||
|
||||
# get_rights_and_owner now also sets $repo; see comments in common functions
|
||||
get_rights_and_owner $1
|
||||
[ -z "$perm_read" ] && die "no read permissions on $repo"
|
||||
|
||||
cd $GL_REPO_BASE_ABS/$repo.git
|
||||
|
||||
logdir=$(dirname $GL_LOG) # uncodumented env var ;-)
|
||||
|
||||
ls $logdir | tac | while read lf
|
||||
do
|
||||
< $logdir/$lf perl -ne "print if /receive-pack.*\s$repo\s/" | cut -f1,2,3,5- | tac
|
||||
done | while read ts who IP perm old new repo ref rule
|
||||
do
|
||||
save_old=$old
|
||||
[ "$new" = "00000000000000" ] && continue
|
||||
[ -z "$old" ] && continue
|
||||
[ "$old" = "00000000000000" ] && old=
|
||||
[ -n "$old" ] && old=$old..
|
||||
git rev-list $old$new 2>/dev/null | grep ^$sha >/dev/null &&
|
||||
printf "$ts $who $IP $perm $save_old $new $repo $ref $rule\n"
|
||||
done
|
|
@ -1,122 +0,0 @@
|
|||
## comparing gerrit and gitolite
|
||||
|
||||
Gerrit and gitolite have too many high level differences. Size is most
|
||||
visible of course: 56000 lines of Java versus 1300 lines of perl+shell,
|
||||
according to David A. Wheeler's 'SLOCCount' tool. Gerrit needs a database (it
|
||||
comes with a perfectly usable one, or I believe you can use any of the usual
|
||||
suspects),
|
||||
and even comes with its own ssh server and git server, and since the git
|
||||
engine is internal it probably has to include a lot of things that normal git
|
||||
already has; I wouldn't know for sure.
|
||||
|
||||
Gerrit allows a lot more de-centralisation in managing the system, and of
|
||||
course excels at code review, and it seems geared to really large, open
|
||||
source-ish projects with lots of contributors.
|
||||
|
||||
Gitolite works on a pure command-line install and a plain text file config,
|
||||
and is designed to run unobtrusively and quite transparently to all developers
|
||||
-- other than sending the admin their pubkey, nothing really changes for them
|
||||
in their workflow, toolset, etc. The "lite" in the name still holds, despite
|
||||
all the extra features being pumped in!
|
||||
|
||||
Gitolite was mainly written for a corporate environment, where we really,
|
||||
really, need branch-level ACLs. While they would certainly love the code
|
||||
review part, things like *voting* on a change, and so on seem a bit alien, and
|
||||
it seems to me that code review itself is more likely to be a hierarchical
|
||||
thing, not a peer-to-peer, "anyone can comment" thing. I could be wrong.
|
||||
|
||||
----
|
||||
|
||||
In short, gitolite doesn't do the main thing that gerrit does, and gerrit is
|
||||
so much bigger than gitolite in so many ways, it seems really odd to compare
|
||||
them at all.
|
||||
|
||||
However, it seems gerrit comes closest to gitolite in terms of flexibility of
|
||||
access control, which is gitolite's main strength, so I thought it would be
|
||||
useful to compare gitolite with just what is in the "access-control.html" in
|
||||
the gerrit war file. Or see [this][gdac]. [...and stop sniggering at the
|
||||
"svn" in the link dammit!]
|
||||
|
||||
Note that I don't necessarily list something that both tools have. (For
|
||||
example, per-user branches denoted by `/USER/` in gitolite and `$(username)`
|
||||
in gerrit, or being able to distinguish between creating a branch and pushing
|
||||
to an already created one, etc).
|
||||
|
||||
[gdac]: http://gerrit.googlecode.com/svn/documentation/2.1.2/access-control.html
|
||||
[jwzq]: http://regex.info/blog/2006-09-15/247
|
||||
|
||||
**Administrators**: anyone who has gitolite-admin push privs
|
||||
|
||||
**Anonymous Users**: gitolite doesn't do that, though the "ssh-plus" branch,
|
||||
combined with git-daemon2 (Ilari) will allow that in future. When git-daemon2
|
||||
becomes mainstream, the supporting code in this branch will also be merged
|
||||
into "master".
|
||||
|
||||
**Registered Users**: @all
|
||||
|
||||
**Account Groups**: @groups in gitolite. We do allow them to be nested,
|
||||
although the parsing is single-pass. We also don't have group `foo-admin`
|
||||
managing membership to group `foo` though; all groups are managed by the eqvt
|
||||
of "Administrators".
|
||||
|
||||
**Project ACLs**: first, let's remember (again) that we don't have any of the code
|
||||
review stuff :)
|
||||
|
||||
* This is a subjective point, but gerrit doesn't give permissions to
|
||||
individual users, only groups. People who have several small projects
|
||||
(only one QA, one integrator, etc.), would have to create lots of 1-man
|
||||
groups, which could be cumbersome.
|
||||
|
||||
* **Evaluation** order and priority of access control rules are different.
|
||||
Gerrit goes by specificity, gitolite goes by sequence. It shouldn't
|
||||
matter; they're probably equivalent except perhaps in some far-fetched
|
||||
scenarios.
|
||||
|
||||
* One big difference is that gitolite does not process "deny" rules ("-1 no
|
||||
Access" in gerrit terms) for *read* access -- we only support those for
|
||||
write access. Gerrit uses this to "hide a handful of projects on an
|
||||
otherwise public server"; in gitolite you'd better avoid giving `R = @all`
|
||||
in the first place :)
|
||||
|
||||
* Update 2010-10-24: as per [this][gitlog1] Gerrit now has *read* access
|
||||
control at the branch level -- they can afford to do that because they
|
||||
have a full jgit stack to play with. Even then it was not easy -- they
|
||||
had to implement a callback from jgit to gerrit for the fetch, *and* deal
|
||||
with evil clients that might try to read an object by *pushing* a supposed
|
||||
change on top of a SHA that they know but don't actually have. (You'll
|
||||
have to think about this carefully; it may not be immediately obvious to
|
||||
people who do not know the ref-exchange in the git protocol).
|
||||
|
||||
Gitolite is dependent on git itself to provide that -- it just cannot be
|
||||
done without support from git core. I can see some corporates drooling at
|
||||
this possibility (makes no sense for open source projects IMO) ;-)
|
||||
|
||||
My normal recommendation is to **use separate repos** if you really need
|
||||
this while continuing to use gitolite. Much simpler and easier to audit
|
||||
and to convince auditors that "those people can't see that code".
|
||||
|
||||
**Categories**:
|
||||
|
||||
* gitolite doesnt have an "owner" for each project in any administrative
|
||||
sense. Perhaps you could consider whoever has `RW+` perms to be an owner
|
||||
but it doesn't go beyond what that implies.
|
||||
|
||||
* gitolite doesnt do anything special to signed or annotated tags
|
||||
|
||||
* Force push is the same as delete by default. However, gitolite can now
|
||||
allow these two separately if that's how you need it.
|
||||
|
||||
Of course, direct pushing clashes with code review, and gerrit recommends
|
||||
that if you want code review you should not use this feature. [Normal
|
||||
pushes in gerrit go through a temp branch that is moved to the correct one
|
||||
after a review is done; direct pushes are all that gitolite has].
|
||||
|
||||
* author/committer identity: checking these fields in pushed commits is
|
||||
likely to be important in some projects, but gitolite doesn't have any
|
||||
notion of this. Hmm... I smell another feature in the future :)
|
||||
|
||||
The rest of it is in areas that the two tools have no overlap on (again, code
|
||||
review being the main thing), or, as I said at the top, features that both
|
||||
tools have.
|
||||
|
||||
[gitlog1]: http://colabti.org/irclogger/irclogger_log/git?date=2010-09-17#l2710
|
|
@ -1,15 +0,0 @@
|
|||
## gitolite-tools
|
||||
|
||||
gitolite-tools is a collection of external git commands to work with
|
||||
gitolite server and repositories:
|
||||
|
||||
* git gl-info - Display gitolite server information
|
||||
* git gl-ls - List accessible gitolite repositories
|
||||
* git gl-desc - Display or edit description of gitolite wildcard repositories
|
||||
* git gl-perms - Display or edit permissions of gitolite wildcard repositories
|
||||
* git gl-htpasswd - Set password for gitweb/apache
|
||||
|
||||
## Homepage
|
||||
|
||||
The project in GitHub:
|
||||
[http://github.com/tmatilai/gitolite-tools](http://github.com/tmatilai/gitolite-tools)
|
|
@ -1,53 +0,0 @@
|
|||
# --------------------------------------------
|
||||
# Per-repo authorization based on gitolite ACL
|
||||
# Include this in gitweb.conf
|
||||
# See doc/3-faq-tips-etc.mkd for more info
|
||||
|
||||
# please note that the author does not have personal experience with gitweb
|
||||
# and does not use it. Some testing may be required. Patches welcome but
|
||||
# please make sure they are tested against a "github" version of gitolite
|
||||
# and not an RPM or a DEB, for obvious reasons.
|
||||
|
||||
# HOME of the gitolite user
|
||||
my $gl_home = $ENV{HOME} = "/home/git";
|
||||
|
||||
# the following variables are needed by gitolite; please edit before using
|
||||
|
||||
# this should normally not be anything else
|
||||
$ENV{GL_RC} = "$gl_home/.gitolite.rc";
|
||||
# this can have different values depending on how you installed.
|
||||
|
||||
# If you installed using the 'from-client' method it will be this:
|
||||
$ENV{GL_BINDIR} = "$gl_home/.gitolite/src";
|
||||
# if you used RPM/DEB or "root" methods it **might** be this:
|
||||
$ENV{GL_BINDIR} = "/usr/local/bin";
|
||||
# if you used the "non-root" method it **might** be this:
|
||||
$ENV{GL_BINDIR} = "$gl_home/bin";
|
||||
# If in doubt take a look at ~/.ssh/authorized_keys; at least one of the lines
|
||||
# might contain something like:
|
||||
# command="/home/git/.gitolite/src/gl-auth-command
|
||||
# and you should use whatever directory the gl-auth-command is in (in this
|
||||
# example /home/git/.gitolite.src)
|
||||
|
||||
# finally the user name
|
||||
$ENV{GL_USER} = $cgi->remote_user || "gitweb";
|
||||
|
||||
# now get gitolite stuff in...
|
||||
unshift @INC, $ENV{GL_BINDIR};
|
||||
require gitolite_rc; gitolite_rc -> import;
|
||||
require gitolite; gitolite -> import;
|
||||
|
||||
# set project root etc. absolute paths
|
||||
$ENV{GL_REPO_BASE_ABS} = ( $REPO_BASE =~ m(^/) ? $REPO_BASE : "$gl_home/$REPO_BASE" );
|
||||
$projects_list = $projectroot = $ENV{GL_REPO_BASE_ABS};
|
||||
|
||||
$export_auth_hook = sub {
|
||||
my $repo = shift;
|
||||
# gitweb passes us the full repo path; so we strip the beginning
|
||||
# and the end, to get the repo name as it is specified in gitolite conf
|
||||
return unless $repo =~ s/^\Q$projectroot\E\/?(.+)\.git$/$1/;
|
||||
|
||||
# check for (at least) "R" permission
|
||||
my ($perm, $creator) = &repo_rights($repo);
|
||||
return ($perm =~ /R/);
|
||||
};
|
|
@ -1,20 +0,0 @@
|
|||
## ldap helper programs
|
||||
|
||||
These programs were contributed by the Nokia MeeGo folks.
|
||||
|
||||
The first 2 are perl and shell verisions of programs meant to be used as
|
||||
`$GL_GET_MEMBERSHIPS_PGM` (see [this][ldap] for more).
|
||||
|
||||
|
||||
* ldap-query-example.pl
|
||||
* ldap-query-example.sh
|
||||
|
||||
The third program is meant to be installed as an adc (admin-defined command,
|
||||
see [here][adc]), and helps users change their LDAP passwords.
|
||||
|
||||
* passwd
|
||||
|
||||
Enjoy!
|
||||
|
||||
[ldap]: http://sitaramc.github.com/gitolite/doc/big-config.html#_storing_usergroup_information_outside_gitolite_like_in_LDAP_
|
||||
[adc]: http://sitaramc.github.com/gitolite/doc/admin-defined-commands.html
|
|
@ -1,80 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
#
|
||||
# Copyright (c) 2010 Nokia Corporation
|
||||
#
|
||||
# This code is licensed to you under MIT-style license. License text for that
|
||||
# MIT-style license is as follows:
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
# ldap-query.pl <arg1>
|
||||
#
|
||||
# this script is used to perform ldap querys by giving one argument:
|
||||
# - <arg1> the user UID for ldap search query
|
||||
#
|
||||
# NOTICE: This script requires libnet-ldap-perl package to be installed
|
||||
# to the system.
|
||||
#
|
||||
|
||||
use Net::LDAP;
|
||||
|
||||
# Script requires user UID as the only parameter
|
||||
if ( $ARGV[0] eq '' || $ARGV[1] ne '' )
|
||||
{
|
||||
print "ldap-query.pl requires one argument, user's uid\n";
|
||||
exit 1;
|
||||
}
|
||||
$user = $ARGV[0];
|
||||
|
||||
# Create communication structure for LDAP connection
|
||||
$ldap = Net::LDAP->new(
|
||||
'localhost',
|
||||
port => 389,
|
||||
debug => 0,
|
||||
timeout => 120,
|
||||
version => 3 ) or die "$@";
|
||||
|
||||
# Bind to LDAP with proper user
|
||||
$ldapret = $ldap->bind( 'cn=administrator,o=company',
|
||||
password => '5ecretpa55w0rd' );
|
||||
die "$ldapret->code" if $ldapret->code;
|
||||
|
||||
# Create filter for LDAP query
|
||||
my $filter = '(&'.
|
||||
'(objectClass=groupAttributeObjectClassName)'.
|
||||
"(uid=$user)".
|
||||
')';
|
||||
|
||||
# Execute the actual LDAP search to get groups for the given UID
|
||||
$ldapret = $ldap->search( base => 'ou=users,ou=department,o=company',
|
||||
scope => 'subtree',
|
||||
filter => $filter );
|
||||
|
||||
# Parse search result to get actual group names
|
||||
my $default_group = '';
|
||||
my $extra_groups = '';
|
||||
|
||||
foreach my $entry ( $ldapret->entries ) {
|
||||
|
||||
$default_group = $entry->get_value( 'defaultGroupAttributeName' ) . ' ' . "$default_group";
|
||||
$extra_groups = $entry->get_value( 'extraGroupsAttributeName' ) . ' ' . "$extra_groups";
|
||||
}
|
||||
|
||||
# Return group names for given user UID
|
||||
print "$default_group" . "$extra_groups";
|
|
@ -1,68 +0,0 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2010 Nokia Corporation
|
||||
#
|
||||
# This code is licensed to you under MIT-style license. License text for that
|
||||
# MIT-style license is as follows:
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
# ldap-query.sh <arg1>
|
||||
#
|
||||
# this script is used to perform ldap querys by giving one argument:
|
||||
# - <arg1> the user UID for ldap search query
|
||||
#
|
||||
# NOTICE: This script requires ldap-utils and sed to be installed to the system.
|
||||
#
|
||||
|
||||
# Script requires user UID as the only parameter
|
||||
#
|
||||
if [ $# -ne 1 ]
|
||||
then
|
||||
echo "ldap-query.sh requires one argument, user's uid"
|
||||
exit 1
|
||||
fi
|
||||
uid_param="${1}"
|
||||
|
||||
# Set needed LDAP search tool options for the query
|
||||
ldap_host="localhost"
|
||||
ldap_binddn="cn=administrator,o=company"
|
||||
ldap_bindpw="5ecretpa55w0rd"
|
||||
ldap_searchbase="ou=users,ou=department,o=company"
|
||||
ldap_scope="subtree"
|
||||
|
||||
# Construct the command line base with needed options for the LDAP query
|
||||
ldap_options="-h ${ldap_host} -x -D ${ldap_binddn} -w ${ldap_bindpw} -b ${ldap_searchbase} -s ${ldap_scope}"
|
||||
|
||||
# Construct the search filter for the LDAP query for the given UID
|
||||
ldap_filter="(&(objectClass=groupAttributeObjectClassName)(uid=${uid_param}))"
|
||||
|
||||
# Construct return attribute list for LDAP query result
|
||||
attr1="defaultGroupAttributeName"
|
||||
attr2="extraGroupsAttributeName"
|
||||
ldap_attr="${attr1} ${attr2}"
|
||||
|
||||
# Execute the actual LDAP search to get groups for the given UID
|
||||
ldap_result=$(ldapsearch ${ldap_options} -LLL ${ldap_filter} ${ldap_attr})
|
||||
|
||||
# Edit search result to get space separated list of group names
|
||||
ldap_result=$(echo ${ldap_result} | sed -e "s/.* ${attr1}://" -e "s/ ${attr2}://")
|
||||
|
||||
# Return group names for given user UID
|
||||
echo ${ldap_result}
|
|
@ -1,112 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use Net::LDAP;
|
||||
use Term::ReadPassword;
|
||||
use Digest::SHA1;
|
||||
use MIME::Base64;
|
||||
use Data::UUID;
|
||||
use Crypt::Cracklib;
|
||||
|
||||
my $PASSWD_MIN_LEN = 8;
|
||||
my $password;
|
||||
|
||||
# parse RC file
|
||||
# $ENV{GL_RC} = "/home/gitolite/.gitolite.rc";
|
||||
die "parse $ENV{GL_RC} failed: " . ($! or $@) unless do $ENV{GL_RC};
|
||||
|
||||
# These come from .gitolite.rc file
|
||||
our ($GL_LDAP_HOST, $GL_LDAP_BIND_DN, $GL_LDAP_BIND_PASSWORD, $GL_LDAP_USER_DN);
|
||||
|
||||
$Term::ReadPassword::ALLOW_STDIN = 1;
|
||||
|
||||
# NOTICE: For some reason Perl fails to disable terminal echo
|
||||
# so following warning about ECHO must be given to the user
|
||||
|
||||
# Warn about password echo because of bugs in Perl ReadPasword
|
||||
print "\nNOTE THAT THE PASSWORD WILL BE ECHOED TO THE SCREEN!\n" .
|
||||
"Please make sure no one is shoulder-surfing, and make sure\n" .
|
||||
"you clear your screen and scrollback history after you are done\n" .
|
||||
"(or close your terminal session).\n\n";
|
||||
|
||||
print "Please type in your new password at the prompt.\n\n" .
|
||||
"Following special keys are available while typing:\n" .
|
||||
" <BackSpace> key to remove the last character\n" .
|
||||
" <Ctrl-U> to remove all characters\n" .
|
||||
" <Ctrl-C> to terminate password change operation\n" .
|
||||
" <Enter> to end password typing\n";
|
||||
|
||||
while ( 1 ) {
|
||||
|
||||
print "\n"; # Start reading with new line
|
||||
$password = read_password("Enter new password: ", 0, 1);
|
||||
|
||||
# Check the validity of new password
|
||||
if ( length( $password ) >= $PASSWD_MIN_LEN # require minimum length
|
||||
&& $password =~ /([\x20-\x7E])/ # require printable characters
|
||||
&& $password =~ /[a-z]/ # require lower case letter
|
||||
&& $password =~ /[A-Z]/ # require upper case letter
|
||||
&& $password =~ /[0-9]/ # require number
|
||||
&& check( $password ) ) # require other than dictionary words
|
||||
{
|
||||
# Re-enter new password to check possible typos
|
||||
if ( $password ne read_password("Enter password again: ") ) {
|
||||
|
||||
print "Passwords do not match!\n";
|
||||
redo;
|
||||
} else {
|
||||
|
||||
last; # Password is valid and there are no typos, so break out
|
||||
}
|
||||
} else { # Given password is not valid
|
||||
|
||||
print "Password must contain at least $PASSWD_MIN_LEN characters and numbers,\n" .
|
||||
"must have both upper and lower case characters,\n" .
|
||||
"can have special characters like !,",#,...\n" .
|
||||
"but cannot be any valid dictionary word.\n";
|
||||
redo;
|
||||
}
|
||||
}
|
||||
|
||||
# Create hash from the password to be stored to the LDAP
|
||||
my $ctx = Digest::SHA1->new();
|
||||
my $ug = new Data::UUID;
|
||||
my $salt = $ug->create_b64();
|
||||
$ctx->add( $password );
|
||||
$ctx->add( $salt );
|
||||
$password = '{SSHA}' . encode_base64( $ctx->digest . $salt, '' );
|
||||
|
||||
# Create communication structure for LDAP connection
|
||||
my $ldap = Net::LDAP->new( $GL_LDAP_HOST ) or die "$@";
|
||||
my $r = $ldap->start_tls( verify => 'none',
|
||||
sslversion => 'tlsv1' );
|
||||
if ( $r->code ) {
|
||||
print "Password handling failed with $r->code return code!\n";
|
||||
log_it( "Password change, LDAP connection failed for $ENV{GL_USER}" );
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# Bind to LDAP with proper user
|
||||
$r = $ldap->bind( $GL_LDAP_BIND_DN,
|
||||
password => $GL_LDAP_BIND_PASSWORD );
|
||||
if ( $r->code ) {
|
||||
print "Password update failed with $r->code return code!\n";
|
||||
log_it( "Password change, LDAP bind failed for $ENV{GL_USER}" );
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# Update new password to the LDAP
|
||||
$r = $ldap->modify( "uid=$ENV{GL_USER},
|
||||
$GL_LDAP_USER_DN",
|
||||
replace => { 'userPassword', $password } );
|
||||
|
||||
if ( $r->code ) {
|
||||
print "Password change failed!\n" .
|
||||
"Please contact administrator to change password.\n";
|
||||
# log_it( "Password change, LDAP modify failed for $ENV{GL_USER}" );
|
||||
} else {
|
||||
print "Password changed succesfully.\n";
|
||||
# log_it( "Password change, LDAP modify done for $ENV{GL_USER}" );
|
||||
}
|
||||
|
||||
$r = $ldap->unbind();
|
||||
|
|
@ -1,248 +0,0 @@
|
|||
## putty and msysgit
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_msysgit_setup">msysgit setup</a>
|
||||
* <a href="#_Going_back_to_OpenSSH">Going back to OpenSSH</a>
|
||||
* <a href="#_Putty_keys">Putty keys</a>
|
||||
* <a href="#_Creating_a_new_key">Creating a new key</a>
|
||||
* <a href="#_Importing_an_existing_key">Importing an existing key</a>
|
||||
* <a href="#_Loading_an_existing_key">Loading an existing key</a>
|
||||
* <a href="#_Public_key">Public key</a>
|
||||
* <a href="#_Putty_ageant">Putty ageant</a>
|
||||
* <a href="#_Sessionless_or_raw_hostname_usage">Sessionless or raw hostname usage</a>
|
||||
* <a href="#_Putty_sessions">Putty sessions</a>
|
||||
* <a href="#_Host_key_authentication">Host key authentication</a>
|
||||
* <a href="#_Debugging_multiple_putty_ageant_keys">Debugging multiple putty ageant keys</a>
|
||||
* <a href="#_Setperms_and_other_commands">Setperms and other commands</a>
|
||||
* <a href="#_About_this_document">About this document</a>
|
||||
|
||||
This document is intended for those who wish to use Putty/Plink with msysgit.
|
||||
|
||||
If you need more help with putty or component programs I suggest looking at [the official putty documentation](http://the.earth.li/~sgtatham/putty/latest/htmldoc/).
|
||||
|
||||
**If you are not already using Putty for SSH it is recommended you do _NOT_ use it with msysgit.**
|
||||
|
||||
**Please note that this only covers the client side of things, and does not involve server side components to troubleshooting. For that, please see the [ssh-troubleshooting document](http://sitaramc.github.com/gitolite/doc/ssh-troubleshooting.html).**
|
||||
|
||||
<a name="msysgit_setup"/>
|
||||
|
||||
<a name="_msysgit_setup"></a>
|
||||
|
||||
### msysgit setup
|
||||
|
||||
Provided you have putty sessions msysgit should give you the option of specifying a location to plink. If it did not then you will need to add an environment variable named "GIT\_SSH" to point at plink.exe, wherever you have that sitting.
|
||||
|
||||
How to do that on your version of windows will likely vary, and is not covered here. For purposes of example, on a 64 bit Windows Vista machine the GIT\_SSH value could be:
|
||||
|
||||
C:\Program Files (x86)\PuTTY\plink.exe
|
||||
|
||||
Note the lack of quotes.
|
||||
|
||||
Testing that msysgit is properly configured can be done from the git bash shell. Simply type (case sensitive, include the quotes):
|
||||
|
||||
"$GIT_SSH" -V
|
||||
|
||||
You should get a response similar to this:
|
||||
|
||||
plink: Release 0.60
|
||||
|
||||
If instead you get a "command not found" type error you likely have a typo in your environment variable.
|
||||
|
||||
<a name="Going_back_to_OpenSSH"/>
|
||||
|
||||
<a name="_Going_back_to_OpenSSH"></a>
|
||||
|
||||
### Going back to OpenSSH
|
||||
|
||||
If you wish to go back to OpenSSH all you need to do is delete the GIT\_SSH environment variable. This will vary by your version of windows and thus is not covered here.
|
||||
|
||||
<a name="Putty_keys"/>
|
||||
|
||||
<a name="_Putty_keys"></a>
|
||||
|
||||
### Putty keys
|
||||
|
||||
If you do not already have putty private key files (.ppk) you will need to make at least one. You can either make a new one or convert an existing key to putty private key format.
|
||||
|
||||
Either way, you will want to use puttygen. Note that you can go the other way if you want to stop using putty but keep the key by exporting the key to OpenSSH format.
|
||||
|
||||
<a name="Creating_a_new_key"/>
|
||||
|
||||
<a name="_Creating_a_new_key"></a>
|
||||
|
||||
#### Creating a new key
|
||||
|
||||
To make it simple, I suggest SSH-2 RSA and a bit size of at least 1024. Larger keys will take longer to generate and will take longer to authenticate you on most systems. Making the key is as simple at hitting "Generate".
|
||||
|
||||
It is recommended to give the key a meaningful comment.
|
||||
|
||||
<a name="Importing_an_existing_key"/>
|
||||
|
||||
<a name="_Importing_an_existing_key"></a>
|
||||
|
||||
#### Importing an existing key
|
||||
|
||||
If you already have an OpenSSH or ssh.com key you can import it using the "Import" option on the "Conversions" menu.
|
||||
|
||||
If the key does not have a meaningful comment I would suggest adding one at this point.
|
||||
|
||||
<a name="Loading_an_existing_key"/>
|
||||
|
||||
<a name="_Loading_an_existing_key"></a>
|
||||
|
||||
#### Loading an existing key
|
||||
|
||||
If you need to load an existing key to edit or view it you can do so from the File menu.
|
||||
|
||||
<a name="Public_key"/>
|
||||
|
||||
<a name="_Public_key"></a>
|
||||
|
||||
#### Public key
|
||||
|
||||
To get your public key for use with gitolite, load (or generate, or import) your key into puttygen. There is a box labeled "Public key for pasting into OpenSSH `authorized_keys` file" there. Copy the text into your preferred text editor and save.
|
||||
|
||||
<a name="Putty_ageant"/>
|
||||
|
||||
<a name="_Putty_ageant"></a>
|
||||
|
||||
#### Putty ageant
|
||||
|
||||
Though not required in all cases you may wish to use the putty ageant, pageant, to load your key(s). This will allow for your key(s) to be passphrase protected but not have to enter the passphrase when you go to use them, provided you have already loaded the key into the ageant.
|
||||
|
||||
<a name="Sessionless_or_raw_hostname_usage"/>
|
||||
|
||||
<a name="_Sessionless_or_raw_hostname_usage"></a>
|
||||
|
||||
### Sessionless or raw hostname usage
|
||||
|
||||
When using plink without a putty session you pretty much have to load your keys with putty ageant, if only so that plink can find them.
|
||||
|
||||
<a name="Putty_sessions"/>
|
||||
|
||||
<a name="_Putty_sessions"></a>
|
||||
|
||||
### Putty sessions
|
||||
|
||||
In addition to hostnames msysgit can, when using putty, use putty sessions. This works in a manner similar to definitions in OpenSSH's `ssh_config` file. All settings in the session that apply to plink usage will be loaded, including the key file to use and even the username to connect to. Thus, instead of:
|
||||
|
||||
ssh://user@host.example.ext:port/repo
|
||||
|
||||
You can use:
|
||||
|
||||
ssh://session_name/repo
|
||||
|
||||
<a name="Host_key_authentication"/>
|
||||
|
||||
<a name="_Host_key_authentication"></a>
|
||||
|
||||
### Host key authentication
|
||||
|
||||
Whether you are using hostnames or sessions you still run into one potential problem. Plink currently wants to validate the server's SSH host key before allowing you to connect, and when git calls plink there is no way to tell it yes. Thus, you may get something like this:
|
||||
|
||||
The server's host key is not cached in the registry. You
|
||||
have no guarantee that the server is the computer you
|
||||
think it is.
|
||||
The server's rsa2 key fingerprint is:
|
||||
ssh-rsa 2048 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
|
||||
Connection abandoned.
|
||||
fatal: The remote end hung up unexpectedly
|
||||
|
||||
Or, in the case of the host key changing, something like this:
|
||||
|
||||
WARNING - POTENTIAL SECURITY BREACH!
|
||||
The server's host key does not match the one PuTTY has
|
||||
cached in the registry. This means that either the
|
||||
server administrator has changed the host key, or you
|
||||
have actually connected to another computer pretending
|
||||
to be the server.
|
||||
The new rsa2 key fingerprint is:
|
||||
ssh-rsa 2048 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
|
||||
Connection abandoned.
|
||||
fatal: The remote end hung up unexpectedly
|
||||
|
||||
The solution is to call plink directly, or start putty and connect with it first. To use plink, open the Git Bash shell and enter:
|
||||
|
||||
"$GIT_SSH" hostname_or_session_name
|
||||
|
||||
When you do you will see something like this:
|
||||
|
||||
The server's host key is not cached in the registry. You
|
||||
have no guarantee that the server is the computer you
|
||||
think it is.
|
||||
The server's rsa2 key fingerprint is:
|
||||
ssh-rsa 2048 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
|
||||
If you trust this host, enter "y" to add the key to
|
||||
PuTTY's cache and carry on connecting.
|
||||
If you want to carry on connecting just once, without
|
||||
adding the key to the cache, enter "n".
|
||||
If you do not trust this host, press Return to abandon the
|
||||
connection.
|
||||
Store key in cache? (y/n)
|
||||
|
||||
Or, in the case of a changed key, a response like this:
|
||||
|
||||
WARNING - POTENTIAL SECURITY BREACH!
|
||||
The server's host key does not match the one PuTTY has
|
||||
cached in the registry. This means that either the
|
||||
server administrator has changed the host key, or you
|
||||
have actually connected to another computer pretending
|
||||
to be the server.
|
||||
The new rsa2 key fingerprint is:
|
||||
ssh-rsa 2048 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
|
||||
If you were expecting this change and trust the new key,
|
||||
enter "y" to update PuTTY's cache and continue connecting.
|
||||
If you want to carry on connecting but without updating
|
||||
the cache, enter "n".
|
||||
If you want to abandon the connection completely, press
|
||||
Return to cancel. Pressing Return is the ONLY guaranteed
|
||||
safe choice.
|
||||
Update cached key? (y/n, Return cancels connection)
|
||||
|
||||
In either case hit y and the key will be stored.
|
||||
|
||||
<a name="Debugging_multiple_putty_ageant_keys"/>
|
||||
|
||||
<a name="_Debugging_multiple_putty_ageant_keys"></a>
|
||||
|
||||
### Debugging multiple putty ageant keys
|
||||
|
||||
In the event you are using putty ageant with multiple keys loaded you may see the wrong key being used. In general, pageant keys are tried in the order they were loaded into the ageant. If you have descriptive comment on each of your keys you can try connecting with plink in verbose mode to see what keys are being tried. Simply open the Git bash shell and run:
|
||||
|
||||
"$GIT_SSH" -v user@hostname
|
||||
|
||||
Or, if using sessions with a pre-entered username:
|
||||
|
||||
"$GIT_SSH" -v session_name
|
||||
|
||||
In either case, you should look for lines like:
|
||||
|
||||
Trying Pageant key #0
|
||||
Authenticating with public key "My Key" from agent
|
||||
|
||||
The first says which (numerical) key the ageant is trying. The second tells you the key comment for the authenticating key. To my knowledge the second line should only show up once, for the valid key.
|
||||
|
||||
<a name="Setperms_and_other_commands"/>
|
||||
|
||||
<a name="_Setperms_and_other_commands"></a>
|
||||
|
||||
### Setperms and other commands
|
||||
|
||||
When using wildcard repos the setperms command is very important, and other commands can come in handy as well. See their documentation for how to use them, but where they use:
|
||||
|
||||
ssh user@host command etc etc
|
||||
|
||||
You will want to use:
|
||||
|
||||
"$GIT_SSH" user@host command etc etc
|
||||
|
||||
Otherwise everything should be identical.
|
||||
|
||||
<a name="About_this_document"/>
|
||||
|
||||
<a name="_About_this_document"></a>
|
||||
|
||||
### About this document
|
||||
|
||||
This document was written by Thomas Berezansky (tsbere (at) mvlc (dot) org) in the hopes that it would be useful to those using putty on windows and wishing to use git/gitolite with their putty keys and sessions.
|
|
@ -1,74 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# update "hooklet" to detect duplicate public keys
|
||||
|
||||
# This particular hooklet also serves as an example for people writing others.
|
||||
# [It should be quite easy to figure out what parts apply to any hooklet and
|
||||
# what parts are specific to *this* hooklet and its function.]
|
||||
|
||||
# see hooks/common/update.secondary.sample for instructions on *enabling*
|
||||
# hooklets
|
||||
|
||||
# a hooklet is called as follows:
|
||||
# git-receive-pack --> 'update' --> 'update.secondary' --> this script
|
||||
# note: the same three arguments that git passes to the update hook are passed
|
||||
# along to each hooklet.
|
||||
|
||||
# the update hook, and therefore the hooklets, are called for *every* repo out
|
||||
# there. If you want this hooklet to run only for certain repos, here's how:
|
||||
[ "$GL_REPO" = "gitolite-admin" ] || exit 0
|
||||
|
||||
# superfluous, since update.secondary already did it, but I'd like to
|
||||
# emphasise that all output MUST go to STDERR
|
||||
exec >&2
|
||||
|
||||
# ----
|
||||
|
||||
# the main functionality of the hooklet starts here. In this one (and I
|
||||
# suspect many others) we want to examine the actual files from the commit
|
||||
# that was pushed.
|
||||
|
||||
# get the tip commit being pushed
|
||||
sha=$3
|
||||
|
||||
# git sets this; and we don't want it at this point...
|
||||
unset GIT_DIR
|
||||
|
||||
# paranoia
|
||||
set -e
|
||||
|
||||
# setup the temp area
|
||||
export TMPDIR=$GL_REPO_BASE_ABS
|
||||
export tmp=$(mktemp -d -t gl-internal-temp-repo.XXXXXXXXXX);
|
||||
trap "rm -rf $tmp" EXIT;
|
||||
|
||||
# now get the files into $tmp.
|
||||
# (note: if your task does not require the actual files, and you can
|
||||
# manage with "git cat-file -s" and so on, then you may not even need a
|
||||
# $tmp; you may be able to do it all right in the repo.git directory)
|
||||
|
||||
git archive $sha keydir | tar -C $tmp -xf -
|
||||
# DO NOT try, say, 'GIT_WORK_TREE=$tmp git checkout $sha'. It'll screw up
|
||||
# both the 'index' and 'HEAD' of the repo.git. Screwing up the index is
|
||||
# BAD because now it goes out of sync with $GL_ADMINDIR. Think of a push
|
||||
# that had a deleted pubkey but failed a hooklet for some reason. A
|
||||
# subsequent push that fixes the error will now result in a $GL_ADMINDIR
|
||||
# that still *has* that deleted pubkey!!
|
||||
|
||||
# And this is equally applicable to cases where you're using a
|
||||
# post-receive or similar hook to live update a web site or something,
|
||||
# which is a pretty common usage, I am given to understand.
|
||||
|
||||
cd $tmp
|
||||
|
||||
# ----
|
||||
|
||||
# *finally*, the actual check you need to do in this hook: look for duplicate
|
||||
# pubkeys and exit 1 if dups are found
|
||||
for f in `find keydir -name "*.pub"`
|
||||
do
|
||||
ssh-keygen -l -f "$f"
|
||||
done | perl -ane '
|
||||
die "$F[2] is a duplicate of $seen{$F[1]}\n" if $seen{$F[1]};
|
||||
$seen{$F[1]} = $F[2];
|
||||
'
|
|
@ -1,69 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# Technical notes:
|
||||
|
||||
# Gitolite specific script to check "author email" field of every commit
|
||||
# pushed and to disallow if this email does not match the email that the
|
||||
# user pushing is expected to have.
|
||||
|
||||
# Use without gitolite is also possible; just substitute your access
|
||||
# control system's notion of "user" for the env var GL_USER in the code
|
||||
# below and probably call it "update" if you dont already have an update
|
||||
# hook.
|
||||
|
||||
# Mapping between "username" and "email address" is encapsulated in a
|
||||
# subroutine for ease of changing; see code below.
|
||||
|
||||
# Philosophical notes:
|
||||
|
||||
# Doing this breaks the "D" in "DVCS", forcing all your developers to work
|
||||
# to a centralised model as far as pushes are concerned. It prevents
|
||||
# amending someone else's commit and pushing (this includes rebasing,
|
||||
# cherry-picking, and so on, which are all impossible now). It also makes
|
||||
# *any* off-line collabaration between two developers useless, because
|
||||
# neither of them can push the result to the server.
|
||||
|
||||
# PHBs should note that validating the committer ID is NOT the same as
|
||||
# reviewing the code and running QA/tests on it. If you're not
|
||||
# reviewing/QA-ing the code, it's probably worthless anyway. Conversely,
|
||||
# if you *are* going to review the code and run QA/tests anyway, then you
|
||||
# don't really need to validate the author email!
|
||||
|
||||
# In a DVCS, if you *pushed* a series of commits, you have -- in some
|
||||
# sense -- signed off on them. The most formal way to "sign" a series is
|
||||
# to tack on and push a gpg-signed tag, although most people don't go that
|
||||
# far. Gitolite's log files are designed to preserve that accountability
|
||||
# to *some* extent, though; see contrib/adc/who-pushed for an admin
|
||||
# defined command that quickly and easily tells you who *pushed* a
|
||||
# particular commit.
|
||||
|
||||
# Anyway, the point is that the only purpose of this script is to
|
||||
# - pander to someone who still has not grokked *D*VCS
|
||||
# OR
|
||||
# - tick off an item in some stupid PHB's checklist
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# mapping between gitolite userid and correct email address is encapsulated in
|
||||
# this subroutine; change as you like
|
||||
sub email_ok
|
||||
{
|
||||
my ($author_email) = shift;
|
||||
my $expected_email = "$ENV{GL_USER}\@atc.tcs.com";
|
||||
return $author_email eq $expected_email;
|
||||
}
|
||||
|
||||
# print STDERR "SECONDARY HOOK:\n" . join(",", @ARGV, "\n");
|
||||
|
||||
my ($ref, $old, $new) = @ARGV;
|
||||
for my $rev ( `git log --format="%ae\t%h\t%s" $new --not --all` ) {
|
||||
chomp($rev);
|
||||
my ($author_email, $hash, $subject) = split /\t/, $rev;
|
||||
|
||||
die "$ENV{GL_USER}, you can't push $hash authored by $author_email\n" .
|
||||
"\t(subject of commit was $subject)\n"
|
||||
unless email_ok($author_email);
|
||||
}
|
||||
|
||||
exit 0;
|
|
@ -1,11 +0,0 @@
|
|||
## Vim Syntax Highlight
|
||||
|
||||
[Vim][] Syntax highlight for `gitolite.conf` can be found from:
|
||||
|
||||
- [vim.org script page][vim.org] (Releases)
|
||||
- [GitHub][] (Sources)
|
||||
|
||||
|
||||
[Vim]: http://www.vim.org/
|
||||
[vim.org]: http://www.vim.org/scripts/script.php?script_id=2900
|
||||
[GitHub]: http://github.com/tmatilai/gitolite.vim
|
127
convert-gitosis-conf
Executable file
127
convert-gitosis-conf
Executable file
|
@ -0,0 +1,127 @@
|
|||
#!/usr/bin/perl -w
|
||||
#
|
||||
# migrate gitosis.conf to gitolite.conf format
|
||||
#
|
||||
# Based on gl-conf-convert by: Sitaram Chamarty
|
||||
# Rewritten by: Behan Webster <behanw@websterwood.com>
|
||||
#
|
||||
|
||||
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 (/^\[gitosis\]$/) {
|
||||
$groupname = '';
|
||||
$reponame = '@all';
|
||||
} 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";
|
||||
#}
|
||||
}
|
|
@ -1,429 +0,0 @@
|
|||
# gitolite installatation
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_please_read_this_first">please read this first</a>
|
||||
* <a href="#_important_notes">important notes</a>
|
||||
* <a href="#_requirements">requirements</a>
|
||||
* <a href="#_client_workstation">client/workstation</a>
|
||||
* <a href="#_server">server</a>
|
||||
* <a href="#_technical_skills">technical skills</a>
|
||||
* <a href="#_getting_the_gitolite_software">getting the gitolite software</a>
|
||||
* <a href="#_getting_a_tar_file_from_a_clone">getting a tar file from a clone</a>
|
||||
* <a href="#_installation_and_setup">installation and setup</a>
|
||||
* <a href="#_install_methods_and_deciding_which_one_to_use">install methods and deciding which one to use</a>
|
||||
* <a href="#_conventions_used">conventions used</a>
|
||||
* <a href="#_package_method_directly_on_the_server_using_RPM_DEB">(package method) directly on the server, using RPM/DEB</a>
|
||||
* <a href="#_root_method_directly_on_the_server_manually_with_root_access">(root method) directly on the server, manually, with root access</a>
|
||||
* <a href="#_non_root_method_directly_on_the_server_manually_without_root_access">(non-root method) directly on the server, manually, without root access</a>
|
||||
* <a href="#_from_client_method_install_from_the_client_to_the_server">(from-client method) install from the client to the server</a>
|
||||
* <a href="#_URLs_for_gitolite_managed_repos">URLs for gitolite-managed repos</a>
|
||||
* <a href="#_special_cases_multiple_gitolite_servers">special cases -- multiple gitolite servers</a>
|
||||
* <a href="#_package_method_and_root_method">package method and root method</a>
|
||||
* <a href="#_from_client_method">from-client method</a>
|
||||
* <a href="#_upgrading">upgrading</a>
|
||||
* <a href="#_uninstalling">uninstalling</a>
|
||||
* <a href="#_cleaning_out_a_botched_install">cleaning out a botched install</a>
|
||||
* <a href="#_uninstalling_gitolite_completely">uninstalling gitolite completely</a>
|
||||
|
||||
----
|
||||
|
||||
<a name="_please_read_this_first"></a>
|
||||
|
||||
### please read this first
|
||||
|
||||
<a name="_important_notes"></a>
|
||||
|
||||
#### important notes
|
||||
|
||||
Please make sure you understand the following points first.
|
||||
|
||||
* gitolite runs as a single (real) user on a server, and is invoked via ssh.
|
||||
Traditionally, this "hosting user" is "git" or "gitolite".
|
||||
|
||||
* there is *usually* only one hosting user per server (machine), but
|
||||
gitolite makes it trivial to have as many as you want. In fact, every
|
||||
user on the server is a potential hosting user. Advanced users can
|
||||
look [here][mgs]!)
|
||||
|
||||
* using this single user and sshd (or httpd) authentication, gitolite allows
|
||||
you to create any number of "virtual" users. Virtual user names only mean
|
||||
something to gitolite, and they need not be the same as any real userid on
|
||||
the server or any of the clients accessing it.
|
||||
|
||||
* the first such virtual user is the "admin user", created during the
|
||||
install sequence.
|
||||
|
||||
* gitolite, in its most commonly used form, depends **heavily** on ssh
|
||||
pubkey (passwordless) access. Do not assume you know all about ssh --
|
||||
most people **don't**. If in doubt, use a dedicated userid on both client
|
||||
and server for installation and administration of gitolite.
|
||||
|
||||
To make matters worse, ssh problems in gitolite don't always look like ssh
|
||||
problems. See [doc/ssh-troubleshooting.mkd][doc6] for help.
|
||||
|
||||
* gitolite **does NOT** like it when people with shell access to the server
|
||||
fiddle with files and directories it controls.
|
||||
|
||||
Apparently this was not obvious to some people.
|
||||
|
||||
Thus a bare minimum gitolite setup has:
|
||||
|
||||
* a server
|
||||
* a real "hosting user" on the server -- usually "git" or "gitolite"
|
||||
* a virtual "admin user" -- the user who sets up gitolite and configures it.
|
||||
* the admin user's client or workstation, from which he does all his work
|
||||
|
||||
It is possible to have the server and the client be the same machine, and even
|
||||
the admin user be also the hosting user, (i.e., `sitaram@server` can install
|
||||
and administer a gitolite setup running under `sitaram@server`, a situation
|
||||
that is common with some hosting services). It's actually fairly easy and
|
||||
**safe** to do, **as long as you have password access to the server** for
|
||||
emergency use. However, I will not be documenting it because (a) if you know
|
||||
ssh you'll know how to extrapolate my instructions to do this and (b) if you
|
||||
don't know ssh it'll be a nightmare to support you.
|
||||
|
||||
<a name="_requirements"></a>
|
||||
|
||||
#### requirements
|
||||
|
||||
<a name="_client_workstation"></a>
|
||||
|
||||
##### client/workstation
|
||||
|
||||
* git version 1.6.2 or greater
|
||||
* even msysgit on Windows is fine; please don't ask me for help if
|
||||
you're using putty, plink, puttygen, etc., for ssh; I recommend
|
||||
msysgit for Windows and the openssh that comes with it
|
||||
* if you're using the "from-client" method of install (see below), the bash
|
||||
shell is needed
|
||||
* again, msysgit on Windows is fine
|
||||
|
||||
<a name="_server"></a>
|
||||
|
||||
##### server
|
||||
|
||||
* any Unix system with a posix compatible "sh".
|
||||
* people using "csh" or derivatives please don't ask me for help -- tell
|
||||
your admin csh is not posix compatible
|
||||
* git version 1.6.2 or greater
|
||||
* can be in a non-PATH location if you are unable to install it
|
||||
normally; see the `$GIT_PATH` variable in the "rc" file
|
||||
* perl (but since git requires it anyway, you probably have it)
|
||||
* openssh or any ssh that can understand the `authorized_keys` file format
|
||||
|
||||
<a name="_technical_skills"></a>
|
||||
|
||||
##### technical skills
|
||||
|
||||
* if you're installing gitolite, you're a "system admin", like it or not.
|
||||
Ssh is therefore a necessary skill. Please take the time to learn at
|
||||
least enough to get passwordless access working.
|
||||
|
||||
* you also need to be somewhat familiar with git itself. You cannot
|
||||
administer a whole bunch of git repositories if you don't know the basics
|
||||
of git.
|
||||
|
||||
* some familiarity with Unix and shells is probably required
|
||||
|
||||
* regular expressions are a big part of gitolite in many places but
|
||||
familiarity is not necessary to do basic access control.
|
||||
|
||||
<a name="_getting_the_gitolite_software"></a>
|
||||
|
||||
### getting the gitolite software
|
||||
|
||||
You can get the latest version of gitolite from github or indefero using the
|
||||
'git clone' command:
|
||||
|
||||
git clone git://github.com/sitaramc/gitolite.git
|
||||
# (OR)
|
||||
git clone git://sitaramc.indefero.net/sitaramc/gitolite.git
|
||||
|
||||
<a name="_getting_a_tar_file_from_a_clone"></a>
|
||||
|
||||
#### getting a tar file from a clone
|
||||
|
||||
If you are on an internal network and cannot clone the gitolite repo, you can
|
||||
do the clone on some other machine and create a tar file from it to use on the
|
||||
internal network. Here's how:
|
||||
|
||||
git clone git://github.com/sitaramc/gitolite.git
|
||||
# (OR)
|
||||
git clone git://sitaramc.indefero.net/sitaramc/gitolite.git
|
||||
cd gitolite
|
||||
make master.tar
|
||||
# or maybe "make pu.tar"
|
||||
|
||||
Please use the make command as shown, not a plain "git archive", because the
|
||||
Makefile adds a file called `.GITOLITE-VERSION` that will help you identify
|
||||
which version you are using.
|
||||
|
||||
<a name="_installation_and_setup"></a>
|
||||
|
||||
### installation and setup
|
||||
|
||||
<a name="methods"></a>
|
||||
|
||||
<a name="_install_methods_and_deciding_which_one_to_use"></a>
|
||||
|
||||
#### install methods and deciding which one to use
|
||||
|
||||
Gitolite has 4 install methods:
|
||||
|
||||
* **package method** if you have a gitolite RPM or a DEB available
|
||||
* **root method** if you have root access to the server, and you plan to
|
||||
have multiple "hosting users" on it
|
||||
* **non-root method** if you don't have root access to the server, but you
|
||||
do have at least one account with a password
|
||||
* **from-client method** if you are not comfortable with public keys and
|
||||
server side commands
|
||||
|
||||
Here's how you install using these 3 methods. Future upgrades are equally
|
||||
easy -- the steps required for upgrading are marked "(U)".
|
||||
|
||||
<a name="_conventions_used"></a>
|
||||
|
||||
#### conventions used
|
||||
|
||||
Throughout the documentation, we use "YourName" as the admin user, and his
|
||||
workstation is called "client". The hosting user is "git", and the server is
|
||||
called "server". **Please substitute your values as needed**.
|
||||
|
||||
**If you're using DEB or RPM**, the installer creates a user called
|
||||
"gitolite", so substitute that for "git" anywhere in the docs where the
|
||||
"hosting user" is mentioned as "git".
|
||||
|
||||
Also, we often say "the rc file". This means `~/.gitolite.rc` on the server.
|
||||
And when we say the "access control rules", or "conf file", or "config file",
|
||||
we mean `conf/gitolite.conf` on your gitolite-admin clone.
|
||||
|
||||
<a name="_package_method_directly_on_the_server_using_RPM_DEB"></a>
|
||||
|
||||
#### (package method) directly on the server, using RPM/DEB
|
||||
|
||||
* from your workstation, copy your `~/.ssh/id_rsa.pub` file to the server.
|
||||
Put it in `/tmp/YourName.pub`.
|
||||
|
||||
* (U) on the server, as root, do the install (urpmi, yum, apt-get, etc.).
|
||||
|
||||
* on the server, "su - gitolite", then as "gitolite" user, run `gl-setup
|
||||
/tmp/YourName.pub`.
|
||||
|
||||
* on the client, run `cd; git clone gitolite@server:gitolite-admin`
|
||||
|
||||
<a name="_root_method_directly_on_the_server_manually_with_root_access"></a>
|
||||
|
||||
#### (root method) directly on the server, manually, with root access
|
||||
|
||||
* from your workstation, copy your `~/.ssh/id_rsa.pub` file to the server.
|
||||
Put it in `/tmp/YourName.pub`.
|
||||
|
||||
* (U) on the server, as root, do the following:
|
||||
|
||||
cd $HOME
|
||||
git clone git://github.com/sitaramc/gitolite gitolite-source
|
||||
cd gitolite-source
|
||||
# now checkout whatever branch you want; for early adopters I suggest
|
||||
# "pu", as in "git checkout -t origin/pu" for recent gits
|
||||
mkdir -p /usr/local/share/gitolite/conf /usr/local/share/gitolite/hooks
|
||||
src/gl-system-install /usr/local/bin /usr/local/share/gitolite/conf /usr/local/share/gitolite/hooks
|
||||
|
||||
* on the server, as root, run "su - git", then as "git" user, run `which
|
||||
gl-setup`. This should respond with `/usr/local/bin/gl-setup`. If this
|
||||
is not what you get, you have some `$PATH` issues. Make sure
|
||||
`/usr/local/bin` is in the `$PATH` for the git user, and that no prior
|
||||
components of the path contain another copy of `gl-setup`. You *must* run
|
||||
the one in the directory that is the first argument of `gl-system-install`
|
||||
above.
|
||||
|
||||
* on the server, still as "git", run `gl-setup /tmp/YourName.pub`.
|
||||
|
||||
* on the client, run `cd; git clone git@server:gitolite-admin`
|
||||
|
||||
<a name="_non_root_method_directly_on_the_server_manually_without_root_access"></a>
|
||||
|
||||
#### (non-root method) directly on the server, manually, without root access
|
||||
|
||||
**WARNING: if you want to use this method your shell access to the git account
|
||||
on the server should be via `su - git` from some other userid. If that is not
|
||||
possible, you should (a) know the password in case you screw up the keys AND
|
||||
(b) know how to force ssh to ask for a password if required, AND (c) know how
|
||||
to handle multiple keys in ssh.**
|
||||
|
||||
* from your workstation, copy your `~/.ssh/id_rsa.pub` file to the server.
|
||||
Put it in `/tmp/YourName.pub`.
|
||||
|
||||
* if `$HOME/bin` is not on the default PATH for the "git" user, fiddle with
|
||||
the `.bashrc` or `.bash_profile` or similar files and add it somehow.
|
||||
|
||||
* (U) on the server, as "git", do the following:
|
||||
|
||||
cd $HOME
|
||||
git clone git://github.com/sitaramc/gitolite gitolite-source
|
||||
# now checkout whatever branch you want; for early adopters I suggest
|
||||
# "pu", as in "git checkout -t origin/pu" for recent gits
|
||||
cd gitolite-source
|
||||
mkdir -p $HOME/bin $HOME/share/gitolite/conf $HOME/share/gitolite/hooks
|
||||
src/gl-system-install $HOME/bin $HOME/share/gitolite/conf $HOME/share/gitolite/hooks
|
||||
|
||||
* on the server, still as "git", run `gl-setup /tmp/YourName.pub`.
|
||||
|
||||
* on the client, run `cd; git clone git@server:gitolite-admin`
|
||||
|
||||
<a name="fc"></a>
|
||||
|
||||
<a name="_from_client_method_install_from_the_client_to_the_server"></a>
|
||||
|
||||
#### (from-client method) install from the client to the server
|
||||
|
||||
The advantage of this method is that it forces you to solve the ssh pubkey
|
||||
problem **before** attempting to install. It works best if you have dedicated
|
||||
userids, one on the server for installing gitolite, and one on the client for
|
||||
administering it.
|
||||
|
||||
The disadvantage is that the admin user ends up with [two keys][twokeys] --
|
||||
one for shell access (that he started with) and one for gitolite access (which
|
||||
the script creates if needed).
|
||||
|
||||
This in turn forces the admin to use a different URL to access gitolite repos
|
||||
than normal users, which seems to confuse a heck of a lot of people who don't
|
||||
read the prominently displayed messages and/or the documentation.
|
||||
|
||||
This method is verbosely documented in this [transcript][], including
|
||||
*outputs* of the commands concerned.
|
||||
|
||||
<a name="_URLs_for_gitolite_managed_repos"></a>
|
||||
|
||||
### URLs for gitolite-managed repos
|
||||
|
||||
The URL for normal users (i.e., users other than the admin) is always of the
|
||||
form "git@server:reponame". So, for instance, `git clone git@server:testing`
|
||||
gets any valid user a copy of the "testing" repo.
|
||||
|
||||
In the first 3 install methods, the admin user will also use the same URL
|
||||
format, like `git clone git@server:gitolite-admin`.
|
||||
|
||||
However, in the fourth ("from-client") method, the admin user needs a
|
||||
different URL (`gitolite:reponame`) to gain access to the gitolite
|
||||
repositories. Check [here][twokeys] for why.
|
||||
|
||||
<a name="_special_cases_multiple_gitolite_servers"></a>
|
||||
|
||||
### special cases -- multiple gitolite servers
|
||||
|
||||
(**Advanced users only, please!**)
|
||||
|
||||
There is no gitolite "daemon"; it gets invoked via sshd which calls
|
||||
"gl-auth-command" via the "command=" option in the authkeys file (see
|
||||
[gitolite and ssh][gash] for more).
|
||||
|
||||
If you think about it, this means every real (unix) user on the system can
|
||||
host her own gitolite server!
|
||||
|
||||
Of course, one doesn't normally do that in the interests of sanity, but let's
|
||||
say you want to create one gitolite instance for each department on some
|
||||
company-wide mega-server.
|
||||
|
||||
<a name="_package_method_and_root_method"></a>
|
||||
|
||||
#### package method and root method
|
||||
|
||||
With the first two methods of installation, it's trivial to create multiple
|
||||
gitolite instances. You can even do this without giving shell access to the
|
||||
admins. Here's an example with just two "departments", and their admins Alice
|
||||
and Bob:
|
||||
|
||||
* create userids `webbrowser_repos` and `webserver_repos`
|
||||
* ask Alice and Bob for their pubkeys; copy them to the respective home
|
||||
directories for convenience
|
||||
* run `su - webbrowser_repos`, then `gl-setup alice.pub`
|
||||
* (similarly with `webserver_repos` and `bob.pub`, and so on for others)
|
||||
|
||||
That's it. The URL for all web browser projects is now something like
|
||||
`webbrowser_repos@server:reponame`, and similarly for the others.
|
||||
|
||||
Notice that you only have to do this once for each "department", and it's
|
||||
really just one command after creating the userid. None of these admins need
|
||||
to have a command line on the server, so don't give them the passwords if you
|
||||
don't need to -- the pubkey will allow them to be gitolite admins on their
|
||||
domain, and that's quite enough for normal operations.
|
||||
|
||||
<a name="_from_client_method"></a>
|
||||
|
||||
#### from-client method
|
||||
|
||||
You can do the same thing using this method also, but it's a little more
|
||||
cumbersome. Instead, I'll describe a different scenario -- one "admin"
|
||||
installing gitolite on different servers. You can adapt that to the above
|
||||
case quite easily if you wish.
|
||||
|
||||
Thanks to Matt Perzel, the easy-install command now takes an optional 4th
|
||||
parameter, which is the "nickname" of the gitolite server. It gets defined in
|
||||
`~/.ssh/config`, and if not used it defaults to "gitolite".
|
||||
|
||||
So if you used the following command to install gitolite to 2 different
|
||||
servers:
|
||||
|
||||
./src/gl-easy-install -q git my.1st.git.server admin_user1 gitolite_server_1
|
||||
./src/gl-easy-install -q git my.2nd.git.server admin_user1 gitolite_server_2
|
||||
|
||||
you will find that `~/gitolite_server_1-admin` and `~/gitolite_server_2-admin`
|
||||
have been created as respective clones. Or you can re-clone elsewhere:
|
||||
|
||||
cd ~/admin1; git clone gitolite_server_1:gitolite-admin.git
|
||||
cd ~/admin2; git clone gitolite_server_2:gitolite-admin.git
|
||||
|
||||
<a name="_upgrading"></a>
|
||||
|
||||
### upgrading
|
||||
|
||||
Upgrading gitolite is easy. In each method above, just re-do the step that is
|
||||
marked "(U)". Also, if you're using either of the two methods that use the
|
||||
`src/gl-system-install` command, please make sure you give it the same
|
||||
arguments!
|
||||
|
||||
If you've added any new hooks, please also run the next step (`gl-setup`)
|
||||
also.
|
||||
|
||||
Also, remember that some new features may require additional settings in your
|
||||
`~/.gitolite.rc` file.
|
||||
|
||||
<a name="_uninstalling"></a>
|
||||
|
||||
### uninstalling
|
||||
|
||||
<a name="_cleaning_out_a_botched_install"></a>
|
||||
|
||||
#### cleaning out a botched install
|
||||
|
||||
When people have trouble installing gitolite, they often try to change a bunch
|
||||
of things manually on the server. This usually makes things worse ;-) so
|
||||
here's how to clean the slate.
|
||||
|
||||
* client-side
|
||||
* edit `~/.ssh/config` and delete the paragraph starting with `host
|
||||
gitolite`, if present.
|
||||
* remove `~/gitolite-admin`
|
||||
* server-side
|
||||
* edit `~/.ssh/authorized_keys` and delete all lines between `# gitolite
|
||||
start` and `# gitolite end` inclusive.
|
||||
* remove `~/.gitolite`, `~/.gitolite.rc` and
|
||||
`~/repositories/gitolite-admin.git`
|
||||
|
||||
<a name="_uninstalling_gitolite_completely"></a>
|
||||
|
||||
#### uninstalling gitolite completely
|
||||
|
||||
There's some duplication between this and the previous section, but
|
||||
uninstalling gitolite is described in great detail in
|
||||
[doc/uninstall.mkd][doc9unin]
|
||||
|
||||
----
|
||||
|
||||
[doc6]: http://sitaramc.github.com/gitolite/doc/ssh-troubleshooting.html
|
||||
[doc9unin]: http://sitaramc.github.com/gitolite/doc/uninstall.html
|
||||
[twokeys]: http://sitaramc.github.com/gitolite/doc/ssh-troubleshooting.html#twokeys
|
||||
[transcript]: http://sitaramc.github.com/gitolite/doc/install-transcript.html
|
||||
[mgs]: http://sitaramc.github.com/gitolite/doc/1-INSTALL.html#_special_cases_multiple_gitolite_servers
|
||||
[gash]: http://sitaramc.github.com/gitolite/doc/gitolite-and-ssh.html
|
383
doc/2-admin.mkd
383
doc/2-admin.mkd
|
@ -1,383 +0,0 @@
|
|||
# administering and running gitolite
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_please_read_this_first">please read this first</a>
|
||||
* <a href="#_adding_users_and_repos">adding users and repos</a>
|
||||
* <a href="#_using_hooks">using hooks</a>
|
||||
* <a href="#_custom_hooks">custom hooks</a>
|
||||
* <a href="#_gl_post_init_hook">"gl-post-init" hook</a>
|
||||
* <a href="#_gl_pre_git_hook">"gl-pre-git" hook</a>
|
||||
* <a href="#_hook_chaining">hook chaining</a>
|
||||
* <a href="#_environment_variables_available_to_hooks">environment variables available to hooks</a>
|
||||
* <a href="#_other_features">other features</a>
|
||||
* <a href="#_moving_pre_existing_repos_into_gitolite">moving pre-existing repos into gitolite</a>
|
||||
* <a href="#_moving_the_whole_thing_from_one_server_to_another">moving the whole thing from one server to another</a>
|
||||
* <a href="#_specifying_gitweb_and_daemon_access">specifying gitweb and daemon access</a>
|
||||
* <a href="#_custom_git_config">custom git config</a>
|
||||
|
||||
----
|
||||
|
||||
<a name="_please_read_this_first"></a>
|
||||
|
||||
### please read this first
|
||||
|
||||
Unless you know what you're doing, do not do **anything** manually on the
|
||||
server (except when the documentation says you should, for example to add
|
||||
custom hooks). In particular, adding new repositories or users or changing
|
||||
the access control rules should not be done directly on the server. Things
|
||||
will break. For example, if you manually create a repo on the server, it will
|
||||
not have the required "update" hook, without which there is no access control
|
||||
for pushes.
|
||||
|
||||
Most normal (day-to-day) gitolite admin work is done by cloning the
|
||||
gitolite-admin repo from the server to your workstation, making changes to the
|
||||
clone, and pushing those changes back.
|
||||
|
||||
The installation steps in the previous section include the steps to do this
|
||||
clone, so you should already have one on your workstation, in
|
||||
`~/gitolite-admin`. You can of course clone it anywhere else you want and use
|
||||
that clone.
|
||||
|
||||
Either way, make sure you `cd` into this clone first.
|
||||
|
||||
*Note*: some of the paths in this document use variable names. Just refer to
|
||||
`~/.gitolite.rc` for the correct values for *your* installation.
|
||||
|
||||
Once you've cloned it, you're ready to add users and repos.
|
||||
|
||||
<a name="_adding_users_and_repos"></a>
|
||||
|
||||
### adding users and repos
|
||||
|
||||
* ask each user who will get access to send you a public key. See other
|
||||
sources (for example [here][genpub]) for how to do this
|
||||
|
||||
* rename each public key according to the user's name, with a `.pub`
|
||||
extension, like `sitaram.pub` or `john-smith.pub`. You can also use
|
||||
periods and underscores
|
||||
|
||||
* copy all these `*.pub` files to `keydir` in your gitolite-admin repo
|
||||
clone. You can also organise them into various subdirectories of `keydir`
|
||||
if you wish, since the entire tree is searched.
|
||||
|
||||
* edit the config file (`conf/gitolite.conf` in your admin repo clone). See
|
||||
`doc/gitolite.conf.mkd` in the gitolite source for details on what goes in
|
||||
that file, syntax, etc. Just add new repos as needed, and add new users
|
||||
and give them permissions as required. The users names should be exactly
|
||||
the same as their keyfile names, but without the `.pub` extension
|
||||
|
||||
* when done, commit your changes and push. Any new repos you specified will
|
||||
automatically be created (empty, but clonable) and users' access will be
|
||||
updated as needed.
|
||||
|
||||
<a name="_using_hooks"></a>
|
||||
|
||||
### using hooks
|
||||
|
||||
<a name="_custom_hooks"></a>
|
||||
|
||||
#### custom hooks
|
||||
|
||||
You can supply your own, custom, hook scripts if you wish. Install gitolite
|
||||
as usual, then:
|
||||
|
||||
* if you installed using "from-client" method (gl-easy-install):
|
||||
* go to the gitolite *source* clone from which you did the original
|
||||
install
|
||||
* add your new hook into "hooks/common"
|
||||
* run src/gl-easy-install with the same arguments as you ran the first
|
||||
time
|
||||
* if you installed using one of the other methods
|
||||
* go to ~/.gitolite/hooks/common on the server and put your new hook
|
||||
there
|
||||
* now run "gl-setup" again
|
||||
|
||||
You can use this procedure to install new hooks as well as to update hooks
|
||||
that you had previously installed.
|
||||
|
||||
**VERY IMPORTANT SECURITY NOTE: the `update` hook in `hooks/common` is what
|
||||
implements all the branch-level permissions in gitolite. If you fiddle with
|
||||
the hooks directory, please make sure you do not mess with this file
|
||||
accidentally, or all your fancy per-branch permissions will stop working.**
|
||||
|
||||
<a name="_gl_post_init_hook"></a>
|
||||
|
||||
#### "gl-post-init" hook
|
||||
|
||||
Sometimes it is necessary to do something whenever a new repo is created. If
|
||||
you need this functionality, just supply a hook called "gl-post-init" with
|
||||
whatever code you want in it.
|
||||
|
||||
<a name="_gl_pre_git_hook"></a>
|
||||
|
||||
#### "gl-pre-git" hook
|
||||
|
||||
Although git has lots of nice hooks you can tap into, they all run only on a
|
||||
push. There's nothing that runs on a fetch or a clone, and there's no way to
|
||||
run something *before* git-receive-pack or git-upload-pack, (as the case may
|
||||
be) are invoked.
|
||||
|
||||
That's what the `gl-pre-git` hook is for. If an executable hook called
|
||||
`gl-pre-git` is present, it will be invoked with the current directory set to
|
||||
`repo.git`, and with a single argument which will be either `R` or `W`
|
||||
depending on what the client is trying to do. The environment variables
|
||||
`GL_USER` and `GL_REPO` are available. STDOUT will be forced to STDERR before
|
||||
it is called, to avoid confusing the client.
|
||||
|
||||
If the code returns anything other than 0, gitolite will terminate the
|
||||
operation (i.e., not run git at all), just like many git hooks do, so make
|
||||
sure you end with `exit 0` or equivalent.
|
||||
|
||||
<a name="_hook_chaining"></a>
|
||||
|
||||
#### hook chaining
|
||||
|
||||
Gitolite basically takes over the update hook for all repos, but some setups
|
||||
really need the update hook functionality for their own purposes too. In
|
||||
order to allow this, Gitolite now exec's a hook called `update.secondary` when
|
||||
it's own "update" hook is done and everything is ready to go.
|
||||
|
||||
You can create this `update.secondary` hook manually on selected repos on the
|
||||
server, or use the mechanism in the previous section to make gitolite put it
|
||||
on *all* your repos.
|
||||
|
||||
Similarly, gitolite also takes over the post-update hook for the special
|
||||
"gitolite-admin" repo. This hook will also chain to a `post-update.secondary`
|
||||
if such a hook exists. People wishing to do exotic things on the server side
|
||||
when the admin repo is pushed should see doc/shell-games.notes for how to
|
||||
exploit this :-)
|
||||
|
||||
In addition, gitolite now contains the basic infrastructure to support
|
||||
multiple such hooks without having to remember to chain them yourself. You
|
||||
can look in `hooks/common/update.secondary.sample` for instructions.
|
||||
|
||||
Finally, these names (`update.secondary` and `post-update.secondary`) are
|
||||
merely the defaults. You can change them to anything you want; look in
|
||||
conf/example.gitolite.rc for details.
|
||||
|
||||
<a name="_environment_variables_available_to_hooks"></a>
|
||||
|
||||
#### environment variables available to hooks
|
||||
|
||||
The following environment variables are set, and may be useful for any custom
|
||||
processing you wish to do in your hook code:
|
||||
|
||||
* `GL_USER` -- the user doing the push
|
||||
* `GL_REPO` -- the reponame
|
||||
* `GL_REPO_BASE_ABS` -- the absolute base path where all the repos are kept
|
||||
|
||||
The following variables are also set, but are generally less useful:
|
||||
|
||||
* `GL_BINDIR` -- where all the binaries live
|
||||
* `GL_ADMINDIR` -- common directory for many gitolite things
|
||||
|
||||
<a name="_other_features"></a>
|
||||
|
||||
### other features
|
||||
|
||||
<a name="_moving_pre_existing_repos_into_gitolite"></a>
|
||||
|
||||
#### moving pre-existing repos into gitolite
|
||||
|
||||
One simple way to add a pre-existing repo to gitolite is to let gitolite
|
||||
create it as a brand new repo as in the previous section, then do the
|
||||
following:
|
||||
|
||||
cd your-copy-of-the-repo
|
||||
# make sure all the branches are correct and no extra stuff, "temp"
|
||||
# branches, etc., are present
|
||||
git push --all git@server:reponame
|
||||
git push --tags git@server:reponame
|
||||
|
||||
(You could also use "git push --mirror" instead of separately doing branches
|
||||
and tags, but that will carry across *your* remote refs also, and typically
|
||||
you may not want that. Anyway please do a `git ls-remote git@server:repo` to
|
||||
make sure all the stuff you want went through, and is named correctly).
|
||||
|
||||
All this is actually very simple and easily done. However, if you have many
|
||||
existing repos to add, this can be time-consuming and error-prone. Here's how
|
||||
to take a bunch of existing repos and add them to gitolite:
|
||||
|
||||
* make sure they're *bare* repos ;-)
|
||||
|
||||
* log on to the server and copy the repos to `$REPO_BASE` (which defaults to
|
||||
`~/repositories`), making sure that the directory names end in ".git".
|
||||
|
||||
* back on your workstation, add each repo (without the `.git` suffix) to
|
||||
`conf/gitolite.conf` in your gitolite-admin repo clone. Then add, commit,
|
||||
push.
|
||||
|
||||
<a name="_moving_the_whole_thing_from_one_server_to_another"></a>
|
||||
|
||||
#### moving the whole thing from one server to another
|
||||
|
||||
[**NOTE**: I would appreciate help testing these instructions]
|
||||
|
||||
Just copying everything won't work unless everything on the new server is
|
||||
exactly the same. I suggest you don't try it unless you know what you're
|
||||
doing.
|
||||
|
||||
**Assumptions**
|
||||
|
||||
* you have not changed `$REPO_BASE` on either of the servers; if you did,
|
||||
substitute accordingly
|
||||
* the admin's name is "YourName" -- again, substitute accordingly!
|
||||
* the "hosting user" on both servers is "git". Substitute whatever you're
|
||||
actually using (for example, if you're installing using RPM/DEB, this
|
||||
would be "gitolite")
|
||||
|
||||
There are many ways of doing this, but the most *generic* set of steps are
|
||||
given below. Please follow all the steps; do not skip or improvise! Ask me
|
||||
if things are not clear -- you can help me fine tune this document :-)
|
||||
|
||||
* (old server) **disable** the old server so your users will not push any
|
||||
changes to it. There are several ways to do this, but the simplest is to
|
||||
insert this line at the top of `~/.gitolite.rc` on the old server:
|
||||
|
||||
exit 1;
|
||||
|
||||
* (new server) **copy** the repos to the new server, **except** the
|
||||
`gitolite-admin` repo and files called `gitolite-hooked` in the `hooks`
|
||||
directory of each repo.
|
||||
|
||||
That sounds complicated but it's not. It's just:
|
||||
|
||||
cd $HOME
|
||||
rsync -a olduser@oldhost:repositories .
|
||||
mv repositories/gitolite-admin.git $HOME/old-gitolite-admin.git
|
||||
find repositories -name gitolite-hooked | xargs rm
|
||||
|
||||
* (workstation) if your old server was installed using the "from-client"
|
||||
method, and you intend to use the same method to install the new server,
|
||||
then
|
||||
|
||||
* edit `~/.ssh/config` and change the line that says `host gitolite` to
|
||||
`host old-gitolite`, or in fact anything that does not match the
|
||||
string "host gitolite" :-)
|
||||
|
||||
* (workstation, new server) **install** gitolite normally on your new
|
||||
server. Use whatever install method suits you, but you must use the
|
||||
**same** name for the admin ("YourName" in the install instructions). You
|
||||
may use a different keypair if you need to, or use the same one that
|
||||
currently gets access to the old server.
|
||||
|
||||
* (new server) **edit** the `~/.gitolite.rc` file to match the settings on
|
||||
the old server, if needed. Do not copy the entire file outright -- some
|
||||
of the variables (notably `GL_PACKAGE_CONF` and `GL_PACKAGE_HOOKS`) are
|
||||
installation dependent and should not be touched! Do a diff or a vimdiff
|
||||
and copy across only what you know *you* changed on the old server.
|
||||
|
||||
* (workstation) **push** the config to the new server. To do this, go to
|
||||
your admin clone, and:
|
||||
|
||||
* if you used a different keypair when installing to the new server,
|
||||
copy that pubkey to this clone into `keydir/Yourname.pub`, then add
|
||||
and commit the change to the pubkey
|
||||
|
||||
cd gitolite-admin
|
||||
cp path/to/new/YourName.pub keydir/YourName.pub
|
||||
git add keydir
|
||||
git commit -m "new server, new key"
|
||||
|
||||
* if you did *not* use a different keypair, just make a dummy commit
|
||||
|
||||
git commit -m "new server" --allow-empty
|
||||
|
||||
* set the URL for the new server
|
||||
|
||||
git remote --set-url origin git@newserver:gitolite-admin
|
||||
# if you used easy install this will be "gitolite:gitolite-admin"
|
||||
|
||||
* push the config, including past history
|
||||
|
||||
git push -f
|
||||
|
||||
And that should be that!
|
||||
|
||||
<a name="gwd"></a>
|
||||
|
||||
<a name="_specifying_gitweb_and_daemon_access"></a>
|
||||
|
||||
#### specifying gitweb and daemon access
|
||||
|
||||
This is a feature that I personally do not use (corporate environments don't
|
||||
like unauthenticated access of any kind to any repo!), but someone wanted it,
|
||||
so here goes.
|
||||
|
||||
Gitolite has two pre-defined, "special", usernames: `daemon` and `gitweb`.
|
||||
|
||||
To make a repo or repo group accessible via "git daemon", just give read
|
||||
permission to the special user "daemon". Similarly, give read permission to
|
||||
`gitweb` to allow the gitweb CGI to show the repo. Something like this:
|
||||
|
||||
repo foo bar baz
|
||||
R = gitweb daemon
|
||||
|
||||
This gives you a quick way to offer multiple repos up for gitweb and/or daemon
|
||||
access.
|
||||
|
||||
However, setting a description for the project also enables gitweb permissions
|
||||
so you can do it that way if you want. Of course in this case you have to
|
||||
deal with each repo separately. Add lines like this to gitolite.conf:
|
||||
|
||||
foo = "some description"
|
||||
bar = "some other description"
|
||||
baz = "yet another description"
|
||||
|
||||
You can also specify an owner for gitweb to show, if you like; for example I
|
||||
might use:
|
||||
|
||||
gitolite "Sitaram Chamarty" = "fast, secure, fine-grained, access control for git"
|
||||
|
||||
Note that gitolite does **not** install or configure gitweb/git-daemon -- that
|
||||
is a one-time setup you must do separately. All gitolite does is:
|
||||
|
||||
* for daemon, create the file `git-daemon-export-ok` in the repository
|
||||
* for gitweb, add the repo (plus owner name, if given) to the list of
|
||||
projects to be served by gitweb (see the config file variable
|
||||
`$PROJECTS_LIST`, which should have the same value you specified for
|
||||
`$projects_list` when setting up gitweb)
|
||||
* put the description, if given, in `$repo/description`
|
||||
|
||||
The "compile" script will keep these files consistent with the config settings
|
||||
-- this includes removing such settings/files if you remove "read" permissions
|
||||
for the special usernames or remove the description line.
|
||||
|
||||
Please **note** that giving permissions to these special users via `@all`
|
||||
(that is, using either `repo @all` or `R = @all`), will not work unless you
|
||||
set the rc-file variable `$GL_ALL_INCLUDES_SPECIAL` to `1`. Also, **NOTE**
|
||||
that giving them read access to `repo @all` means the `gitolite-admin` repo is
|
||||
also accessible. **It is upto you to decide if that is OK in your
|
||||
environment**.
|
||||
|
||||
<a name="_custom_git_config"></a>
|
||||
|
||||
#### custom git config
|
||||
|
||||
The custom hooks feature is a blunt instrument -- all repos get the hook you
|
||||
specified and will run it. In order to make it a little more fine-grained,
|
||||
you could set your hooks to only work if a certain "gitconfig" variable was
|
||||
set. Which means we now need a way to specify "git config" settings on a per
|
||||
repository basis.
|
||||
|
||||
[Note: this feature is disabled by default. Read the comments around a
|
||||
variable called `GL_GITCONFIG_KEYS` in the rc file, then set it to some
|
||||
appropriate value, to enable this feature.]
|
||||
|
||||
Thanks to Teemu (teemu dot matilainen at iki dot fi), gitolite now does this
|
||||
very easily. For security reasons, this can only be done from the master
|
||||
config file (i.e., if you're using delegation, the delegated admins cannot
|
||||
specify git config settings).
|
||||
|
||||
Please see `doc/gitolite.conf.mkd` for syntax. Note that this only supports the
|
||||
basic forms of the "git config" command:
|
||||
|
||||
git config section.key value # value may be an empty string
|
||||
git config --unset-all section.key
|
||||
|
||||
It does not (currently) support other options like `--add`, the `value_regex`,
|
||||
etc.
|
||||
|
||||
[genpub]: http://sitaramc.github.com/0-installing/2-access-gitolite.html#generating_a_public_key
|
||||
|
|
@ -1,534 +0,0 @@
|
|||
# assorted faqs, tips, and notes on gitolite
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_common_errors_and_mistakes">common errors and mistakes</a>
|
||||
* <a href="#_other_errors_warnings_notes_">other errors, warnings, notes...</a>
|
||||
* <a href="#_cloning_an_empty_repo">cloning an empty repo</a>
|
||||
* <a href="#_all_syntax_for_repos">`@all` syntax for repos</a>
|
||||
* <a href="#_features">features</a>
|
||||
* <a href="#_syntax_and_normal_usage">syntax and normal usage</a>
|
||||
* <a href="#_one_user_many_keys">one user, many keys</a>
|
||||
* <a href="#_security_access_control_and_auditing">security, access control, and auditing</a>
|
||||
* <a href="#_two_levels_of_access_rights_checking">two levels of access rights checking</a>
|
||||
* <a href="#_better_logging">better logging</a>
|
||||
* <a href="#_delegating_parts_of_the_config_file">delegating parts of the config file</a>
|
||||
* <a href="#_convenience_features">convenience features</a>
|
||||
* <a href="#_what_repos_do_I_have_access_to_">what repos do I have access to?</a>
|
||||
* <a href="#_support_for_git_installed_outside_default_PATH">support for git installed outside default PATH</a>
|
||||
* <a href="#_personal_branches">"personal" branches</a>
|
||||
* <a href="#_custom_hooks_and_custom_git_config">custom hooks and custom git config</a>
|
||||
* <a href="#_bypassing_gitolite">bypassing gitolite</a>
|
||||
* <a href="#_disabling_write_access_to_take_backups">disabling write access to take backups</a>
|
||||
* <a href="#_INconvenience_features">INconvenience features</a>
|
||||
* <a href="#_deleting_a_repo">deleting a repo</a>
|
||||
* <a href="#_renaming_a_repo">renaming a repo</a>
|
||||
* <a href="#_helping_with_gitweb">helping with gitweb</a>
|
||||
* <a href="#_easier_to_link_gitweb_authorisation_with_gitolite">easier to link gitweb authorisation with gitolite</a>
|
||||
* <a href="#_umask_setting">umask setting</a>
|
||||
* <a href="#_advanced_features">advanced features</a>
|
||||
* <a href="#_repos_named_with_wildcards">repos named with wildcards</a>
|
||||
* <a href="#_admin_defined_commands">admin defined commands</a>
|
||||
* <a href="#_access_control_for_external_commands">access control for external commands</a>
|
||||
* <a href="#_svnserve">svnserve</a>
|
||||
* <a href="#_design_choices">design choices</a>
|
||||
* <a href="#_keeping_the_parser_and_the_access_control_separate">keeping the parser and the access control separate</a>
|
||||
|
||||
----
|
||||
|
||||
<a name="_common_errors_and_mistakes"></a>
|
||||
|
||||
### common errors and mistakes
|
||||
|
||||
* adding `repositories/` at the start of the repo name in the `git clone`.
|
||||
This error is typically made by the *admin* himself -- because he knows
|
||||
what `$REPO_BASE` is set to and thinks he has to provide that prefix on
|
||||
the client side also :-) In fact gitolite prepends `$REPO_BASE`
|
||||
internally, so you shouldn't also do the same thing!
|
||||
|
||||
* being able to clone but getting errors on push. Most likely caused by a
|
||||
combination of:
|
||||
|
||||
* you already have shell access to the server, not just "gitolite"
|
||||
access, *and*
|
||||
|
||||
* you cloned using `git clone git@server:repositories/repo.git` (notice
|
||||
there's an extra "repositories/" in there?)
|
||||
|
||||
In other words, you used a key that completely bypassed gitolite and went
|
||||
straight to the shell to do the clone.
|
||||
|
||||
Please see doc/ssh-troubleshooting.mkd for what all this means.
|
||||
|
||||
<a name="_other_errors_warnings_notes_"></a>
|
||||
|
||||
### other errors, warnings, notes...
|
||||
|
||||
<a name="_cloning_an_empty_repo"></a>
|
||||
|
||||
#### cloning an empty repo
|
||||
|
||||
Cloning an empty repo is only possible with clients greater than 1.6.2. So at
|
||||
least one of your clients needs to have a recent git. Once at least one
|
||||
commit has been made, older clients can also use it
|
||||
|
||||
When you clone an empty repo, git seems to complain about `fatal: The remote
|
||||
end hung up unexpectedly`. However, you can ignore this, since it doesn't
|
||||
seem to hurt anything. [Update 2009-09-14; this has been fixed in git
|
||||
1.6.4.3]
|
||||
|
||||
<a name="_all_syntax_for_repos"></a>
|
||||
|
||||
#### `@all` syntax for repos
|
||||
|
||||
There *is* a way to use the `@all` syntax for repos also, as described in
|
||||
`doc/gitolite.conf.mkd`. However, there are a couple of minor cautions:
|
||||
|
||||
* don't use `NAME/` or such restrictions on the special `@all` repo. Due to
|
||||
the potential for defeating a crucial optimisation and slowing down *all*
|
||||
access, we do not support this.
|
||||
|
||||
<a name="_features"></a>
|
||||
|
||||
### features
|
||||
|
||||
Apart from the big ones listed in the top level README, and subjective ones
|
||||
like "better config file format", gitolite has evolved to have many useful
|
||||
features than the original goal of branch-level access control.
|
||||
|
||||
<a name="_syntax_and_normal_usage"></a>
|
||||
|
||||
#### syntax and normal usage
|
||||
|
||||
<a name="multikeys"></a>
|
||||
|
||||
<a name="_one_user_many_keys"></a>
|
||||
|
||||
##### one user, many keys
|
||||
|
||||
I have a laptop and a desktop I need to access the server from. I have
|
||||
different private keys on them, but as far as gitolite is concerned both of
|
||||
them should be treated as "sitaram". How does this work?
|
||||
|
||||
The way it works is that you copy one pubkey as "sitaram@laptop.pub" and the
|
||||
other as "sitaram@desktop.pub". The part before the "@" is the username, so
|
||||
gitolite knows these two keys belong to the same person. The part after the
|
||||
"@" can be anything you like, of course; gitolite doesn't care.
|
||||
|
||||
Note that you don't say "sitaram@laptop" and so on in the **config** file --
|
||||
as far as the config file is concerned there's just **one** user called
|
||||
"sitaram" -- so you only say "sitaram" there.
|
||||
|
||||
I think this is easier to maintain if you have to delete or change one of
|
||||
those keys.
|
||||
|
||||
However, now that `sitaramc@gmail.com` is also a valid username, we need to
|
||||
distinguish between `sitaramc@gmail.com.pub` and `sitaramc@desktop.pub`. We
|
||||
do that by requiring that the multi-key suffix you use (like "desktop" and
|
||||
"laptop") should not have a `"."` in it. If it does, it looks like an email
|
||||
address. The following table lists sample pubkey filenames and the
|
||||
corresponding derived usernames (which is what goes into the
|
||||
`conf/gitolite.conf` file):
|
||||
|
||||
* old style multikeys; not mistaken for emails because there is no "." in
|
||||
hostname part
|
||||
|
||||
sitaramc.pub sitaramc
|
||||
sitaramc@laptop.pub sitaramc
|
||||
sitaramc@desktop.pub sitaramc
|
||||
|
||||
* new style, email keys; there is a "." in hostname part; so it's an email
|
||||
address
|
||||
|
||||
sitaramc@gmail.com.pub sitaramc@gmail.com
|
||||
|
||||
* multikeys *with* email address
|
||||
|
||||
sitaramc@gmail.com@laptop.pub sitaramc@gmail.com
|
||||
sitaramc@gmail.com@desktop.pub sitaramc@gmail.com
|
||||
|
||||
<a name="_security_access_control_and_auditing"></a>
|
||||
|
||||
#### security, access control, and auditing
|
||||
|
||||
<a name="_two_levels_of_access_rights_checking"></a>
|
||||
|
||||
##### two levels of access rights checking
|
||||
|
||||
Gitolite has two levels of access checks. The **first check** is what I will
|
||||
call the **pre-git** level. At this stage, the `gl-auth-command` has been
|
||||
invoked by `sshd`, and it knows just three things:
|
||||
|
||||
* who,
|
||||
* what repository, and
|
||||
* what type of access (R or W)
|
||||
|
||||
Note that at this point no git program has entered the picture, and we have no
|
||||
way of knowing what **ref** (branch, tag, etc) he is trying to update, even if
|
||||
it is a "write" operation.
|
||||
|
||||
For a "read" operation to pass this check, the username (or `@all`) must have
|
||||
read permission (i.e., R, RW, or RW+) on at least one branch of the repo.
|
||||
|
||||
For a "write" operation, there is an additional restriction: lines specifying
|
||||
only `R` (read access) don't count. *The user must have write access to
|
||||
**some** ref in the repo in order to pass this stage!*
|
||||
|
||||
The **second check** is via a git `update hook`. This check only happens for
|
||||
write operations. By this time we know what "ref" he is trying to update, as
|
||||
well as the old and the new SHAs of that ref (by which we can also deduce
|
||||
whether it's a rewind or not). This is where the "per-branch" permissions
|
||||
come into play.
|
||||
|
||||
Each refex that allows `W` access (or `+` if this is a rewind) for *this*
|
||||
user, on *this* repo, is matched against the actual refname being updated. If
|
||||
any of the refexes match, the push succeeds. If none of them match, it fails.
|
||||
|
||||
Gitolite also allows "exclude" or "deny" rules. See later in this document
|
||||
for details.
|
||||
|
||||
<a name="_better_logging"></a>
|
||||
|
||||
##### better logging
|
||||
|
||||
If you have been too liberal with the permission to rewind, it has built-in
|
||||
logging as an emergency fallback if someone goes too far, or for audit
|
||||
purposes [`*`]. The logfile names and location are configurable, and can
|
||||
include the year/month/day etc in the filename for easy archival or further
|
||||
processing. The log file even tells you which pattern in the config file
|
||||
matched to allow that specific access to proceed.
|
||||
|
||||
> [`*`] setting `core.logAllRefUpdates true` does provide a safety net
|
||||
> against over-zealous rewinds, but it does not tell you "who". And
|
||||
> strangely, management does not seem to share the view that "blame" is just
|
||||
> a synonym for "annotate" ;-)]
|
||||
|
||||
The log lines look like this:
|
||||
|
||||
2009-09-19.10:24:37 + b4e76569659939 4fb16f2a88d8b5 myrepo refs/heads/master user2 refs/heads/master
|
||||
|
||||
The "+" at the start indicates a non-fast forward update, in this case from
|
||||
b4e76569659939 to 4fb16f2a88d8b5. So b4e76569659939 is the one to restore!
|
||||
Can it get easier?
|
||||
|
||||
The other parts of the log line are the name of the repo, the refname being
|
||||
updated, the user updating it, and the refex pattern (from the config file)
|
||||
that matched, in case you need to debug the config file itself.
|
||||
|
||||
<a name="_delegating_parts_of_the_config_file"></a>
|
||||
|
||||
##### delegating parts of the config file
|
||||
|
||||
You can now split up the config file and delegate the authority to specify
|
||||
access control for their own pieces. See [delegation][] for details.
|
||||
|
||||
<a name="_convenience_features"></a>
|
||||
|
||||
#### convenience features
|
||||
|
||||
<a name="_what_repos_do_I_have_access_to_"></a>
|
||||
|
||||
##### what repos do I have access to?
|
||||
|
||||
Sometimes there are too many repos, maybe even named similarly, or with the
|
||||
potential for typos, confusion about hyphens/underscores or upper/lower case,
|
||||
etc. You'd just like a simple way to know what repos you have access to.
|
||||
|
||||
Gitolite provides two commands (`info` and `expand`) to help you find this
|
||||
information; please check [doc/report-output.mkd][repout] for details.
|
||||
|
||||
<a name="_support_for_git_installed_outside_default_PATH"></a>
|
||||
|
||||
##### support for git installed outside default PATH
|
||||
|
||||
The normal solution is to add to the system default PATH somehow, either by
|
||||
munging `/etc/profile` or by enabling `PermitUserEnvironment` in
|
||||
`/etc/ssh/sshd_config` and then setting the PATH in `~/.ssh/.environment`.
|
||||
All these are security risks because they allow a lot more than just you and
|
||||
your git install :-)
|
||||
|
||||
And if you don't have root, you can't do this anyway.
|
||||
|
||||
The only solution till now has been to ask every client to set the config
|
||||
parameters `remote.<name>.receivepack` and `remote.<name>.uploadpack`. But
|
||||
telling *every* client to do so is a pain...
|
||||
|
||||
Gitolite lets you specify the directory in which git binaries are to be found,
|
||||
via a new variable (`$GIT_PATH`) in the "rc" file. If this variable is
|
||||
non-empty, it will be appended to the PATH environment variable before
|
||||
attempting to run git stuff.
|
||||
|
||||
Very easy, very simple, and completely transparent to the users :-)
|
||||
|
||||
**Note**: sometimes you have a system that already has an older "git"
|
||||
installed in one of the system PATHs, but you've installed a newer git in some
|
||||
non-standard location and want that picked up. Because of security reasons,
|
||||
gitolite will not prepend `GIT_PATH` to the PATH variable, so the older git
|
||||
comes first and it gets kinda frustrating!
|
||||
|
||||
Here's a simple workaround. Ignore the `GIT_PATH` variable, and directly set
|
||||
the full PATH in the rc file, like so:
|
||||
|
||||
$ENV{PATH} = "/home/sitaram/bin:$ENV{PATH}";
|
||||
|
||||
<a name="_personal_branches"></a>
|
||||
|
||||
##### "personal" branches
|
||||
|
||||
"personal" branches are great for corporate environments, where
|
||||
unauthenticated pull/clone is a no-no. Since a dev workstation cannot do
|
||||
authentication, even work shared just between 2 devs has to go *via* the
|
||||
server. This causes 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 (e.g., `refs/personal/<devname>/*`). Just add a line like:
|
||||
|
||||
RW+ personal/USER/ = @userlist
|
||||
|
||||
This means I (user "sitaram") can do anything to any branch whose name starts
|
||||
with `personal/sitaram/` assuming I'm in "userlist".
|
||||
|
||||
You can have any number of such lines with different prefixes (for example,
|
||||
using topic names instead of "personal") or even suffixes if you like. The
|
||||
important thing is that the "branch" name should contain `/USER/` (including
|
||||
the slashes). At runtime this will match whoever is the current user. Access
|
||||
is still determined by the right hand side of course.
|
||||
|
||||
<a name="_custom_hooks_and_custom_git_config"></a>
|
||||
|
||||
##### custom hooks and custom git config
|
||||
|
||||
You can specify hooks that you want to propagate to all repos, as well as
|
||||
per-repo "gitconfig" settings. Please see `doc/2-admin.mkd` and
|
||||
`doc/gitolite.conf.mkd` for details.
|
||||
|
||||
<a name="_bypassing_gitolite"></a>
|
||||
|
||||
##### bypassing gitolite
|
||||
|
||||
Sometimes you'll need to access one of the gitolite-managed repos directly on
|
||||
the server, without going through gitolite. Reasons may be some automatic
|
||||
updates or some other ad hoc purposes you can dream up.
|
||||
|
||||
Cloning a gitolite-controlled repo is easy enough -- just use the full path
|
||||
(typically `~/repositories/reponame.git`) instead of just `reponame`, to
|
||||
compensate for gitolite not sitting in between and adding those things to the
|
||||
repo path.
|
||||
|
||||
But when you push, the update hook (which git will invoke anyway) will fail
|
||||
because it needs all sorts of access control info that it now doesn't have,
|
||||
because the push was invoked without going through gitolite.
|
||||
|
||||
In order to bypass the update hook, just set the `GL_BYPASS_UPDATE_HOOK`
|
||||
environment variable to "1" or something, export it, and push. I prefer not
|
||||
to set that variable permanently, preferring this mode instead:
|
||||
|
||||
GL_BYPASS_UPDATE_HOOK=1 git push
|
||||
|
||||
**WARNING**: Do **NOT** try this with the special `gitolite-admin` repo. That
|
||||
repo also runs a `post-update` hook which needs additional information which
|
||||
is NOT available if you bypass gitolite. Mucking with that repo in this
|
||||
manner is strongly discouraged, as in "are you feeling lucky today?". Use
|
||||
`gl-dont-panic` if you need to do some server-side surgery for that repo.
|
||||
|
||||
<a name="_disabling_write_access_to_take_backups"></a>
|
||||
|
||||
##### disabling write access to take backups
|
||||
|
||||
If you want to take normal, OS-level, backups of the system, you might want
|
||||
git to be quiescent during that time, so that the backup is clean. The best
|
||||
way to do this is to disable write-access to the server for the duration of
|
||||
the backup.
|
||||
|
||||
Here's how:
|
||||
|
||||
cd $HOME # if running as "git" user, else "cd ~git" or whatever
|
||||
echo writes disabled during backup window > .gitolite.down
|
||||
|
||||
# << RUN YOUR BACKUP COMMAND(s) HERE >>
|
||||
|
||||
rm .gitolite.down
|
||||
|
||||
I leave it to you to
|
||||
|
||||
* make sure that if the backup script fails, the `.gitolite.down` file is
|
||||
still removed (or not; maybe your policy is that if the backup failed, no
|
||||
further writes are allowed. Whatever...)
|
||||
* if you're extremely paranoid (even I wouldn't worry about this!) make sure
|
||||
that no push is *in progress* by checking for any `git-receive-pack`
|
||||
processes in a `ps` output.
|
||||
|
||||
<a name="_INconvenience_features"></a>
|
||||
|
||||
#### INconvenience features
|
||||
|
||||
<a name="_deleting_a_repo"></a>
|
||||
|
||||
##### deleting a repo
|
||||
|
||||
By design, there is no code in gitolite to *delete* a repo if the repo was
|
||||
specified by name in the config file. (Wildcard repos *can* be deleted by the
|
||||
user; see [here][rmrepo] for details).
|
||||
|
||||
If you *do* want to permanently delete a *non*-wildcard repo, here's what you
|
||||
do:
|
||||
|
||||
* remove the repo from the gitolite-admin repo clone's `conf/gitolite.conf`
|
||||
file. "add" the change, commit, and push.
|
||||
|
||||
* *then* remove the repo from `~/repositories` on the server (or whatever
|
||||
you set `$GL_REPO_BASE` to in the `~/.gitolite.rc`)
|
||||
|
||||
<a name="_renaming_a_repo"></a>
|
||||
|
||||
##### renaming a repo
|
||||
|
||||
This is similar; there's no code to do this in gitolite. What you do is:
|
||||
|
||||
* log on to the server, `cd $REPO_BASE` (default: `cd ~/repositories`), and
|
||||
`mv old-name.git new-name.git`
|
||||
* back on your gitolite-admin clone, edit `conf/gitolite.conf` and replace
|
||||
all occurrences of `old-name` with `new-name`. Then add, commit, and push
|
||||
as usual.
|
||||
|
||||
The order of these 2 steps is important; do not reverse them :-)
|
||||
|
||||
<a name="_helping_with_gitweb"></a>
|
||||
|
||||
#### helping with gitweb
|
||||
|
||||
Although gitweb is a completely separate program, gitolite can do quite a
|
||||
lot to help you manage gitweb access as well; once the initial setup is
|
||||
complete, you can do it all from within the gitolite config file!
|
||||
|
||||
If you just want gitweb to show some repositories, see [gwd] for how to
|
||||
specify which repos to show. Other advanced uses are described here.
|
||||
|
||||
[gwd]: http://sitaramc.github.com/gitolite/doc/2-admin.html#gwd
|
||||
|
||||
<a name="_easier_to_link_gitweb_authorisation_with_gitolite"></a>
|
||||
|
||||
##### easier to link gitweb authorisation with gitolite
|
||||
|
||||
Over and above whether a repo is even *shown* by gitweb, you may want to
|
||||
further restrict people, allowing them to view *only* those repos for which
|
||||
they have been given read access by gitolite.
|
||||
|
||||
This requires that:
|
||||
|
||||
* you have to have some sort of HTTP auth on your web server (out of my
|
||||
scope, sorry!)
|
||||
* the HTTP auth should use the same username (like "sitaram") as used in the
|
||||
gitolite config (for the corresponding user)
|
||||
|
||||
Normally a superuser sets up passwords for users using the "htpasswd" command,
|
||||
but this is an administrative chore.
|
||||
|
||||
Robin Smidsrød had the *great* idea that, since each user already has pubkey
|
||||
access to `git@server`, this gives us a very neat way of using gitolite to let
|
||||
the users *manage their own HTTP passwords*. Here's how:
|
||||
|
||||
* setup apache so that the htaccess file it looks for is owned by the "git"
|
||||
user
|
||||
* in the `~/.gitolite.rc` file, look for the variable `$HTPASSWD_FILE` and
|
||||
point it to this file
|
||||
* tell your users to type in `ssh git@server htpasswd` to set or change
|
||||
their HTTP passwords
|
||||
|
||||
Of course some other authentication method can be used (e.g. `mod_ldap`) as
|
||||
long as the usernames match.
|
||||
|
||||
Gitweb allows you to specify a subroutine to decide on access. We use that
|
||||
feature and tie it to gitolite. Configuration example can be found in
|
||||
`contrib/gitweb/`.
|
||||
|
||||
<a name="_umask_setting"></a>
|
||||
|
||||
##### umask setting
|
||||
|
||||
Gitweb not able to read your repos? You can change the umask for newly
|
||||
created repos to something more relaxed -- see the `~/.gitolite.rc` file
|
||||
|
||||
<a name="_advanced_features"></a>
|
||||
|
||||
#### advanced features
|
||||
|
||||
<a name="_repos_named_with_wildcards"></a>
|
||||
|
||||
##### repos named with wildcards
|
||||
|
||||
Please see `doc/wildcard-repositories.mkd` for all the details.
|
||||
|
||||
<a name="_admin_defined_commands"></a>
|
||||
|
||||
##### admin defined commands
|
||||
|
||||
This requires the wildcards feature to be enabled, but is then an extremely
|
||||
powerful feature. See `doc/admin-defined-commands.mkd`.
|
||||
|
||||
<a name="_access_control_for_external_commands"></a>
|
||||
|
||||
##### access control for external commands
|
||||
|
||||
Gitolite now has a mechanism for allowing access control for arbitrary
|
||||
external commands, as long as they are invoked via ssh and present a
|
||||
server-side command that contains enough information to make an access control
|
||||
decision.
|
||||
|
||||
Note that this is incompatible with giving people shell access as described in
|
||||
`doc/ssh-troubleshooting.mkd` -- people who have shell access are not
|
||||
subject to this mechanism (it wouldn't make sense to try and control someone
|
||||
who has shell access anyway).
|
||||
|
||||
In general, external commands require changes in one or both the config files;
|
||||
the sample files in `conf/` double as documentation, so you should look there
|
||||
for examples and usage.
|
||||
|
||||
Commands implemented so far are:
|
||||
|
||||
* rsync
|
||||
* svnserve (see next section for a brief description; this has been
|
||||
contributed by Simon and Vladimir)
|
||||
|
||||
<a name="_svnserve"></a>
|
||||
|
||||
###### svnserve
|
||||
|
||||
If you are transitioning from SVN to gitolite, and have a lot of users using
|
||||
public-key authentication with SVN, this feature may be useful to you. Once
|
||||
you migrate all users' public keys into gitolite, you can set the `$SVNSERVE`
|
||||
variable in `~/.gitolite.rc` to tie `svnserve` with gitolite's authentication
|
||||
system. Assuming you installed gitolite to the same user as the one you used
|
||||
for SVN, SVN connectivity will be retained, and users will be able to use
|
||||
both SVN and git using the same SSH configuration.
|
||||
|
||||
<a name="_design_choices"></a>
|
||||
|
||||
### design choices
|
||||
|
||||
<a name="_keeping_the_parser_and_the_access_control_separate"></a>
|
||||
|
||||
#### keeping the parser and the access control separate
|
||||
|
||||
There are two programs concerned with access control:
|
||||
|
||||
* `gl-auth-command`, the program that is run via `~/.ssh/authorized_keys`;
|
||||
this decides whether git should even be allowed to run (basic R/W/no
|
||||
access). (This one cannot decide on the branch-level access; it is not
|
||||
known at this point what branch is being accessed)
|
||||
* the update-hook on each repo, which decides the per-branch permissions
|
||||
|
||||
I have chosen to keep the relatively complex task of parsing the config file
|
||||
out of them to keep them simpler (and faster). So any changes to the config
|
||||
have to be first "compiled", and the access control programs use this
|
||||
"compiled" version of the config. (The compile step also refreshes
|
||||
`~/.ssh/authorized_keys`).
|
||||
|
||||
If you choose the "easy install" method, all this is quite transparent to you
|
||||
anyway. If you cannot use the easy install and must install manually, I have
|
||||
clear instructions on how to set it up.
|
||||
|
||||
[repout]: http://sitaramc.github.com/gitolite/doc/report-output.html
|
||||
[delegation]: http://sitaramc.github.com/gitolite/doc/delegation.html
|
||||
[rmrepo]: http://sitaramc.github.com/gitolite/doc/admin-defined-commands.html#rmrepo
|
241
doc/CHANGELOG
241
doc/CHANGELOG
|
@ -1,241 +0,0 @@
|
|||
Major changes to gitolite, master branch only, most recent first, no dates but
|
||||
the tags can help you position stuff approximately
|
||||
[NYD = not yet documented due to lack of time...]
|
||||
|
||||
- v2.0.1
|
||||
|
||||
- "hooklets" allow you to have any number of site-local 'update hook'
|
||||
scripts play nicely with gitolite
|
||||
|
||||
- the "include" statement can now use globs -- makes some types of setups
|
||||
sooooo easy!
|
||||
|
||||
- mirroring finally tested properly after v2
|
||||
|
||||
- 'hub' adc (pull requests etc)
|
||||
|
||||
- warn() and die() are now logged
|
||||
|
||||
- v2.0
|
||||
|
||||
- gl-pre-git hook added
|
||||
|
||||
- 'hub' adc added
|
||||
|
||||
- v2.0rc2
|
||||
|
||||
*** V1.5.9.1 -- IMPORTANT SECURITY FIX; PLEASE UPGRADE IF YOU'RE USING
|
||||
SOMETHING OLDER THAN THIS ONE
|
||||
|
||||
- supercool new 'git' adc; so cool it's disabled by default
|
||||
|
||||
- '-prune' added to find commands; makes a big diff if REPO_BASE is NFS/CIFS
|
||||
mounted
|
||||
|
||||
- first python ADC contributed -- 'perms' makes setperms etc easier to do
|
||||
|
||||
- 'set-head' ADC added
|
||||
|
||||
- v2.0rc1; major refactor
|
||||
|
||||
- v1.5.9
|
||||
|
||||
- Nokia MeeGo team contributed ldap scripts
|
||||
|
||||
- large configs should now be twice as fast (except when gl-perms exists)
|
||||
due to my finding and eliminating a wasted parse_acl
|
||||
|
||||
- major change: split the config file when in big-config mode
|
||||
(includes a data format change)
|
||||
|
||||
- GL_ALL_READ_ALL to make things much, (MUCH!) faster for sites where all
|
||||
can read all repos (like Fedora)
|
||||
|
||||
- rc file revamp -- was getting too big and unwieldy; now the documentation
|
||||
is in a new file instead of inline
|
||||
|
||||
- allow gitolite to be used even when users have real IDs (thus $HOME is not
|
||||
valid to find the rc file); allow /etc/gitolite/gitolite.rc then
|
||||
|
||||
- BIG one for adc writers -- full blown access checks (ref level) can be
|
||||
done from an ADC now (though it has to be in perl, not shell)!
|
||||
|
||||
- allow full access checks from perl (shell can only do level 1 checks);
|
||||
useful in hooks or ADCs
|
||||
|
||||
- v1.5.8
|
||||
|
||||
- Jeff from KDE contributed the watch ADC
|
||||
- allow disabling gitolite (write access only) to take backups
|
||||
- document how to move gitolite from one server to another
|
||||
|
||||
- custom permissions categories (default being READERS and WRITERS) for
|
||||
setperms (thanks to Jeff from KDE for the idea/need)
|
||||
|
||||
- v1.5.7
|
||||
|
||||
- "help" adc can allow site local help text to be shown
|
||||
- "who-pushed" adc to find out who pushed a given commit
|
||||
- rmrepo adc replaced by lock/unlock/rm and trash/list-trash/restore
|
||||
families of commands
|
||||
|
||||
- v1.5.6
|
||||
|
||||
- new method for passing usergroup info (minor backward compat breakage);
|
||||
see commit message and doc/big-config.mkd for more on this
|
||||
|
||||
- added "sudo" (adc)
|
||||
- added "gl-reflog" (adc) to get a fake reflog from the server!
|
||||
- added support for a post-repo-create hook called "gl-post-init"
|
||||
|
||||
- (BIG ONE!) SMART HTTP SUPPORT!
|
||||
|
||||
- @all can now include gitweb/daemon also (default, not include)
|
||||
- allow @groups in setperms
|
||||
- gitweb/daemon now work within setperms
|
||||
|
||||
- log elapsed time (optional)
|
||||
|
||||
- more than one wildcard may match a repo, plus it can also be matched by a
|
||||
normal repo line
|
||||
|
||||
- test suite has lots of new tests for the below
|
||||
- (big change) all combinations of wild repos and big configs, including
|
||||
daemon/gitweb/git-config settings, should work now!
|
||||
|
||||
- v1.5.5
|
||||
|
||||
- mirroring support
|
||||
|
||||
- setup_authkeys is now separate; can be called from outside also; useful
|
||||
for people who want to maintain ssh keys via LDAP or something, and not
|
||||
within gitolite
|
||||
|
||||
- (two months too late for towel day) gl-dont-panic!
|
||||
[replaces the old "gl-emergency-addkey" program. It does more (including
|
||||
recovering from a botched push, not just lost keys), is cleaner, and works
|
||||
for all install methods]
|
||||
|
||||
- document on how to create a mob branch
|
||||
|
||||
- info command now takes a parameter to limit output; this is mandatory if
|
||||
GL_BIG_CONFIG is on
|
||||
|
||||
- v1.5.4
|
||||
|
||||
- new RC variables: GL_NO_CREATE_REPOS and GL_NO_SETUP_AUTHKEYS (inspired by
|
||||
the specific needs that Fedora have, but made as generic as possible)
|
||||
- separating push branch rights from create branch rights changed to use the
|
||||
same mechanism as the (older) mechanism for separating rewind from delete
|
||||
|
||||
- v1.5.3
|
||||
|
||||
- log file format changed; minor backward compat breakage if you've been
|
||||
doing any automated log processing
|
||||
- some small but important doc updates
|
||||
- adc "fork" now much faster and more space-efficient (uses git clone -l)
|
||||
|
||||
- v1.5.2
|
||||
|
||||
- added test suite
|
||||
|
||||
- v1.5.1
|
||||
|
||||
- disallow creation of new refs if you want (while allowing push of the
|
||||
same)
|
||||
|
||||
- adc "able" command added to contrib
|
||||
- easy-install now takes a host-nickname parameter for convenience in
|
||||
installing more than one gitolite server
|
||||
- major doc revamp; contrib/autotoc added to make docs look nicer
|
||||
- eliminate the need to run gl-setup on data version change, thus hopefully
|
||||
obsoleting the upgrade note for v1.5 (just below).
|
||||
|
||||
- v1.5 -- IMPORTANT UPGRADE NOTES below
|
||||
|
||||
Upgrading to v1.5 from any version prior to v1.5 requires an extra step
|
||||
for people who installed gitolite using the "system install / user setup"
|
||||
method described in doc/0-INSTALL.mkd. For such installations, after the
|
||||
administrator has upgraded gitolite system-wide, each "gitolite host" user
|
||||
must run `gl-setup` once (this time without any arguments).
|
||||
|
||||
- "deny" rules should now work even in "big-config" due to previous change
|
||||
- proper rule sequencing (required major format change)
|
||||
|
||||
- allow usergroup info to be passed in from outside, say via LDAP; see
|
||||
doc/big-config.mkd for details
|
||||
- (new) big-config is now part of mainline (old one had bitrotted); see
|
||||
doc/big-config.mkd for details
|
||||
|
||||
- gl-system-install: help people simulate an RPM/DEB install by just running
|
||||
that commmand with appropriate arguments; see doc/0-INSTALL.mkd
|
||||
|
||||
- admin-defined commands; see doc/admin-defined-commands.mkd
|
||||
|
||||
- v1.4.2 (prep for major refactor on rights queries
|
||||
- v1.4.1 (security fix)
|
||||
|
||||
- REFUSE TO RUN ON SERVER GIT < 1.6.2 (do NOT upgrade gitolite to or beyond
|
||||
this point if you are unable to upgrade git itself to at least 1.6.2)
|
||||
|
||||
- "D" must be combined with RW or RW+ (warning: minor backward compat breakage)
|
||||
|
||||
- v1.4
|
||||
|
||||
- recurse through keydir for pubkeys
|
||||
- bypass update hook if GL_BYPASS_UPDATE_HOOK is available in ENV
|
||||
- new server-side program "gl-tool", subcommand "shell-add"
|
||||
- new "D" permission (makes RW+ no longer imply "D" if used)
|
||||
- @all for repos is now a true @all
|
||||
- allow setperms to specify @all
|
||||
- post-update hook and gl-setup should be dash compat now
|
||||
- workaround for a Data::Dumper crash; see 412a691
|
||||
- both hooks chain to "<hookname>.secondary" now
|
||||
|
||||
- new style personal branches (see 2456cc1 for advantages)
|
||||
|
||||
- v1.3
|
||||
|
||||
- easier to move repos into gitolite
|
||||
- pattern for expand is no longer anchored
|
||||
|
||||
- v1.2
|
||||
|
||||
- distro packaging support -- easy to install systemwide now
|
||||
|
||||
- v1.1
|
||||
|
||||
- contrib directory added
|
||||
- expand now lists non-wildcard repos also
|
||||
- refs also have groups now
|
||||
- allow admins to get "info" for other users
|
||||
|
||||
- wildrepos merged
|
||||
- getdesc and setdesc for wildrepos
|
||||
- htpasswd subcommand
|
||||
- access control for rsync
|
||||
|
||||
- v1.0
|
||||
|
||||
- sshkeys-lint program added, doc/6 revamped
|
||||
- @SHELL in config changed to $SHELL_USERS in rc
|
||||
- "include" mechanism
|
||||
- delegation now uses NAME/ instead of branches
|
||||
- PATH/ changed to NAME/
|
||||
|
||||
- @SHELL in config
|
||||
- use of @all for repos also (see doc for caveat)
|
||||
- config entries for repos
|
||||
|
||||
- deny rules (no more "rebel" branch!)
|
||||
- PATH/
|
||||
- specify gitweb owner
|
||||
|
||||
- v0.95
|
||||
- easy install can run from msysgit also
|
||||
- v0.90
|
||||
- allow admin defined hooks
|
||||
- specify gitweb desc
|
||||
- v0.85
|
||||
- emergency addkey program
|
||||
- v0.80
|
|
@ -1,227 +0,0 @@
|
|||
## admin defined commands
|
||||
|
||||
**WARNING: Use this feature only if you really really know what you're doing.
|
||||
If you come back to me saying this feature caused a problem, I will only
|
||||
laugh. The worse the problem, the louder I will laugh. You won't actually
|
||||
hear me laughing, but you'll feel it in your bones, trust me!**
|
||||
|
||||
There may be other such **WARNING** sections below. **Read all of them**.
|
||||
|
||||
----
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_background">background</a>
|
||||
* <a href="#_setting_it_up">setting it up</a>
|
||||
* <a href="#_anatomy_of_a_command">anatomy of a command</a>
|
||||
* <a href="#_example_uses_and_sample_commands_in_contrib">example uses and sample commands in contrib</a>
|
||||
* <a href="#_fork">fork</a>
|
||||
* <a href="#_deleting_trashing_repos">deleting/trashing repos</a>
|
||||
* <a href="#_enable_disable_push_access_temporarily">enable/disable push access temporarily</a>
|
||||
* <a href="#_bonus_restricted_admin">(bonus) restricted admin</a>
|
||||
|
||||
----
|
||||
|
||||
<a name="_background"></a>
|
||||
|
||||
### background
|
||||
|
||||
Gitolite was named to be short for "gitosis-lite". Someone now wants to turn
|
||||
it into a "github-lite" :-) and even had some code to start me off thinking.
|
||||
|
||||
Since my first impulse on being asked for a feature is to say no, I was
|
||||
casting about for a reason when he gave me one: he first made some noises
|
||||
about perl, then said something about rewriting it all in scheme. Nice... I
|
||||
resisted the urge to point him to [this][xkcd224], told him that's a great
|
||||
idea and he should go for it, mentally blessing him for letting me off the
|
||||
hook on coding it ;-) [Laziness][lazy] *is* the first virtue you know!
|
||||
|
||||
And that was that. For a couple of days.
|
||||
|
||||
Soon, though, I realised that there could be a pretty big bonus in this for
|
||||
tightly controlled setups, so I went and coded it all anyway. See the section
|
||||
on "restricted admin" for what's really exciting about this for *me*.
|
||||
|
||||
----
|
||||
|
||||
It may be a good idea to read [doc/wildcard-repositories.mkd][wild] before
|
||||
you continue here though, because most of the uses of this feature also need
|
||||
wildcard repos. (This also means you must set `$GL_WILDREPOS` to "1" in the
|
||||
rc file).
|
||||
|
||||
The wildcard repo feature is a way to create repositories matching a pattern
|
||||
(even if it as simple as `personal/CREATOR/.+`), and a way to specify two
|
||||
categories of permissions for each such user-created repo.
|
||||
|
||||
What we want now is more than that, as you'll see in the examples below. And
|
||||
I'm sure if you think of more uses you'll send them to me as "contrib"
|
||||
entries, right?
|
||||
|
||||
<a name="_setting_it_up"></a>
|
||||
|
||||
### setting it up
|
||||
|
||||
This can only be setup by someone who has shell access to the server. Edit
|
||||
the rc file and update the `$GL_ADC_PATH` variable to point to, say,
|
||||
`/home/git/bin/adc`. *Nothing happens unless this variable is set and
|
||||
pointing to a directory*. Then put in whatever such commands you create into
|
||||
that directory. If you have a command called "foo" in that directory, then a
|
||||
user can invoke it by saying:
|
||||
|
||||
ssh git@server foo argument list
|
||||
|
||||
**WARNING: When gitolite takes control, this directory is checked first, and
|
||||
if the requested command exists, it is executed. It is therefore quite easy
|
||||
to inadvertently *hide* some of the "official" commands (like "info",
|
||||
"expand", "setperms", etc., or worse, say "git-upload-pack"!) by creating
|
||||
executable files with those names in this directory. So don't do that -- you
|
||||
have been warned!**
|
||||
|
||||
#### configuring ADCs
|
||||
|
||||
I didn't want to put configuration variables for ADCs also into the main 'rc'
|
||||
file, so I chose to put them in the `adc.common-functions` file instead. Take
|
||||
a look at it sometime.
|
||||
|
||||
<a name="_anatomy_of_a_command"></a>
|
||||
|
||||
### anatomy of a command
|
||||
|
||||
You can basically do whatever you want in such a command -- go wild! It's
|
||||
upto you to check the permissions of *each* repo that the user is manipulating
|
||||
using your command -- you can `rm -rf $GL_REPO_BASE_ABS` if you like and
|
||||
gitolite wouldn't stop you.
|
||||
|
||||
The current directory (`$PWD`) will be set to the `$HOME` of `git@server` (or
|
||||
whatever id you're using). It won't be any specific repo, it won't even be
|
||||
the base directory of all the repos.
|
||||
|
||||
Gitolite defines a few environment variables, as well as allows you to
|
||||
directly query the ownership and access permissions of any repository.
|
||||
|
||||
The environment variables available are:
|
||||
|
||||
* `GL_USER` -- the name of the user invoking the command
|
||||
* `GL_BINDIR` -- the directory containing all the binaries (in particular,
|
||||
`gitolite.pm`, which is all we really care about here)
|
||||
* `GL_REPO_BASE_ABS` -- the absolute path of the base directory containing
|
||||
all the repos
|
||||
|
||||
There are a few other variables also available but the above are the only ones
|
||||
you should rely on. Please treat any other variables you notice as being
|
||||
internal/undocumented/subject to change.
|
||||
|
||||
[Implementation note: some of the distro packagers don't seem to like
|
||||
`GL_BINDIR`. I have not tested this in those scenarios, but they probably put
|
||||
`gitolite.pm` somewhere in perl's lib path anyway, so it ought to work].
|
||||
|
||||
In addition, all the arguments of the command are also available to you, so
|
||||
you can define your own command syntaxes. Gitolite checks these arguments to
|
||||
make sure they fit a very conservative pattern (see `$ADC_CMD_ARGS_PATT` in
|
||||
`src/gitolite.pm`), so take that into consideration when designing your
|
||||
commands and usage.
|
||||
|
||||
Finally, you can call gitolite to query ownership and permissions for the
|
||||
current user (which may not necessarily be the owner). This is done loosely
|
||||
as follows (don't use this exact code yet though):
|
||||
|
||||
perl -I$GL_BINDIR -Mgitolite -e "cli_repo_rights('reponame')"
|
||||
|
||||
which will print two space-separated words, something like `_____R__W u1` or
|
||||
maybe `____@R_@W <gitolite>`. (The former is the response for a wildcard repo
|
||||
created by user `u1`, the latter is for a non-wildcard repo)
|
||||
|
||||
But that's cumbersome. There's a bash shell function called
|
||||
`get_rights_and_owner` in `contrib/adc/adc.common-functions` that is much more
|
||||
convenient. See any of the other samples for how to use it.
|
||||
|
||||
If you don't like this, roll your own. If you don't like bash, do the eqvt in
|
||||
your language of choice.
|
||||
|
||||
<a name="_example_uses_and_sample_commands_in_contrib"></a>
|
||||
|
||||
### example uses and sample commands in contrib
|
||||
|
||||
<a name="_fork"></a>
|
||||
|
||||
#### fork
|
||||
|
||||
A user would use the fork command like this:
|
||||
|
||||
ssh git@server fork from to
|
||||
|
||||
where "from" is a repo to which the user invoking the fork has "R" access, and
|
||||
"to" is a repo that does not yet exist and to which he has "C" access.
|
||||
|
||||
(Reminder: these access checks are done by the "fork" script, **not** within
|
||||
gitolite -- once again, you are responsible for making sure your scripts
|
||||
maintain the security of the system!)
|
||||
|
||||
Strictly speaking this command is not really needed. Even without all this
|
||||
"admin-defined commands" setup you could still do the following, purely from
|
||||
the client side:
|
||||
|
||||
git clone git@server:from
|
||||
cd from
|
||||
git remote add new git@server:to
|
||||
git push new refs/*:refs/*
|
||||
|
||||
or some such incantation.
|
||||
|
||||
<a name="rmrepo"></a>
|
||||
|
||||
<a name="_deleting_trashing_repos"></a>
|
||||
|
||||
#### deleting/trashing repos
|
||||
|
||||
See [contrib/adc/repo-deletion.README][rdR] for details about this.
|
||||
|
||||
[rdR]: http://github.com/sitaramc/gitolite/blob/pu/contrib/adc/repo-deletion.README
|
||||
|
||||
<a name="_enable_disable_push_access_temporarily"></a>
|
||||
|
||||
#### enable/disable push access temporarily
|
||||
|
||||
If you want to disable push access to gitolite temporarily (maybe for
|
||||
maintenance), anyone with write access to the gitolite-admin repo can do this:
|
||||
|
||||
ssh git@server able dis @all # able dis ==> dis able
|
||||
|
||||
To re-enable after the maint work is done:
|
||||
|
||||
ssh git@server able en @all # able en ==> en able
|
||||
|
||||
You can also do this for one or more individual repos; in place of `@all`,
|
||||
just use a space separated list of reponames (exactly as they would appear in
|
||||
the config file). Wildcards are not supported; patches welcome ;-)
|
||||
|
||||
Note: please see [this][diswr] for more on this.
|
||||
|
||||
[diswr]: http://sitaramc.github.com/gitolite/doc/3-faq-tips-etc.html#_disabling_write_access_to_take_backups
|
||||
|
||||
<a name="_bonus_restricted_admin"></a>
|
||||
|
||||
#### (bonus) restricted admin
|
||||
|
||||
It's rather important to me (and presumably others in the "corporate" world)
|
||||
to separate permission to push to the "gitolite-admin" repo from unrestricted
|
||||
shell access to the server. This issue has been visited often in the past.
|
||||
|
||||
Until now, though, this was binary -- you either had full shell access or none
|
||||
at all. If there were tasks that legitimately needed to be done from the
|
||||
shell on the server, it often meant you had to break that separation or load
|
||||
the few people who did have shell access already.
|
||||
|
||||
Now, however, it is possible to provide scripts to do what you want, and put
|
||||
them in `$GL_ADC_PATH`. `contrib/adc/restrict-admin` is a commented sample --
|
||||
as you can see, it cleverly makes use of the fact that you can now check for
|
||||
the invoking uses access to any repo in the system. In this case it checks if
|
||||
he has "W" access to the gitolite-admin repo, and if he does, allows the
|
||||
script to proceed.
|
||||
|
||||
[Note that this particular use does not require `$GL_WILDREPOS` to be enabled,
|
||||
because it's not using any wildcard repos].
|
||||
|
||||
[xkcd224]: http://xkcd.com/224/
|
||||
[lazy]: http://c2.com/cgi/wiki?LazinessImpatienceHubris
|
||||
[wild]: http://sitaramc.github.com/gitolite/doc/wildcard-repositories.html
|
|
@ -1,430 +0,0 @@
|
|||
## what is a "big-config"
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_when_why_do_we_need_it_">when/why do we need it?</a>
|
||||
* <a href="#_how_do_we_use_it_">how do we use it?</a>
|
||||
* <a href="#_access_rules_for_groups">access rules for groups</a>
|
||||
* <a href="#_access_rules_for_individual_repos_split_config_">access rules for individual repos (split config)</a>
|
||||
* <a href="#_other_optimisations">other optimisations</a>
|
||||
* <a href="#_disabling_various_defaults">disabling various defaults</a>
|
||||
* <a href="#_optimising_the_authkeys_file">optimising the authkeys file</a>
|
||||
* <a href="#_what_are_the_downsides_">what are the downsides?</a>
|
||||
* <a href="#_storing_usergroup_information_outside_gitolite_like_in_LDAP_">storing usergroup information outside gitolite (like in LDAP)</a>
|
||||
* <a href="#_why">why</a>
|
||||
* <a href="#_how">how</a>
|
||||
* <a href="#_implementation_notes">implementation notes</a>
|
||||
|
||||
<a name="_when_why_do_we_need_it_"></a>
|
||||
|
||||
### when/why do we need it?
|
||||
|
||||
A "big config" is anything that has a few thousand users and a few thousand
|
||||
repos, resulting in a very large 'compiled' config file.
|
||||
|
||||
To understand the problem, consider what happens if you have something like
|
||||
this in your gitolite conf file:
|
||||
|
||||
@wbr = lynx firefox
|
||||
@devs = alice bob
|
||||
|
||||
repo @wbr
|
||||
RW+ next = @devs
|
||||
RW master = @devs
|
||||
|
||||
Without the 'big config' setting, gitolite internally translates this to:
|
||||
|
||||
repo lynx firefox
|
||||
RW+ next = alice bob
|
||||
RW master = alice bob
|
||||
|
||||
and then generates the actual config rules once for each user-repo-ref
|
||||
combination (there are 8 combinations above); the compiled config file looks
|
||||
somewhat like this:
|
||||
|
||||
%repos = (
|
||||
'firefox' => {
|
||||
'R' => {
|
||||
'alice' => 1,
|
||||
'bob' => 1
|
||||
},
|
||||
'W' => {
|
||||
'alice' => 1,
|
||||
'bob' => 1
|
||||
},
|
||||
'alice' => [
|
||||
[
|
||||
0,
|
||||
'refs/heads/next',
|
||||
'RW+'
|
||||
],
|
||||
[
|
||||
4,
|
||||
'refs/heads/master',
|
||||
'RW'
|
||||
]
|
||||
],
|
||||
'bob' => [
|
||||
[
|
||||
1,
|
||||
'refs/heads/next',
|
||||
'RW+'
|
||||
],
|
||||
[
|
||||
5,
|
||||
'refs/heads/master',
|
||||
'RW'
|
||||
]
|
||||
]
|
||||
},
|
||||
'lynx' => {
|
||||
'R' => {
|
||||
'alice' => 1,
|
||||
'bob' => 1
|
||||
},
|
||||
'W' => {
|
||||
'alice' => 1,
|
||||
'bob' => 1
|
||||
},
|
||||
'alice' => [
|
||||
[
|
||||
2,
|
||||
'refs/heads/next',
|
||||
'RW+'
|
||||
],
|
||||
[
|
||||
6,
|
||||
'refs/heads/master',
|
||||
'RW'
|
||||
]
|
||||
],
|
||||
'bob' => [
|
||||
[
|
||||
3,
|
||||
'refs/heads/next',
|
||||
'RW+'
|
||||
],
|
||||
[
|
||||
7,
|
||||
'refs/heads/master',
|
||||
'RW'
|
||||
]
|
||||
]
|
||||
}
|
||||
);
|
||||
|
||||
Phew!
|
||||
|
||||
Of course, the output is the same whether you used groups (like `@wbr` and
|
||||
`@devs` in the example above) or listed the repos directly on the 'repo'
|
||||
lines.
|
||||
|
||||
Anyway, you can imagine what that does when you have 10,000 users and 10,000
|
||||
repos. Let's just say it's not pretty :)
|
||||
|
||||
<a name="_how_do_we_use_it_"></a>
|
||||
|
||||
### how do we use it?
|
||||
|
||||
Just set
|
||||
|
||||
$GL_BIG_CONFIG = 1;
|
||||
|
||||
in the `~/.gitolite.rc` file on the server (see next section for more
|
||||
variables). When you do that, and push this configuration, one of two things
|
||||
happens.
|
||||
|
||||
<a name="_access_rules_for_groups"></a>
|
||||
|
||||
#### access rules for groups
|
||||
|
||||
If you used group names in the 'repo' lines (as in `repo @wbr`), then the
|
||||
compiled config looks like this:
|
||||
|
||||
%repos = (
|
||||
'@wbr' => {
|
||||
'@devs' => [
|
||||
[
|
||||
0,
|
||||
'refs/heads/next',
|
||||
'RW+'
|
||||
],
|
||||
[
|
||||
1,
|
||||
'refs/heads/master',
|
||||
'RW'
|
||||
]
|
||||
],
|
||||
'R' => {
|
||||
'@devs' => 1
|
||||
},
|
||||
'W' => {
|
||||
'@devs' => 1
|
||||
}
|
||||
}
|
||||
);
|
||||
%groups = (
|
||||
'@devs' => {
|
||||
'alice' => 'master',
|
||||
'bob' => 'master'
|
||||
},
|
||||
'@wbr' => {
|
||||
'firefox' => 'master',
|
||||
'lynx' => 'master'
|
||||
}
|
||||
);
|
||||
|
||||
That's a lot smaller, and allows orders of magintude more repos and groups to
|
||||
be supported.
|
||||
|
||||
<a name="_access_rules_for_individual_repos_split_config_"></a>
|
||||
|
||||
#### access rules for individual repos (split config)
|
||||
|
||||
If, on the other hand, you had the repos listed individually, (as in `repo
|
||||
lynx firefox`), then the main config file would now look like this:
|
||||
|
||||
%repos = ();
|
||||
%split_conf = (
|
||||
'firefox' => 1,
|
||||
'lynx' => 1
|
||||
);
|
||||
|
||||
And each individual repo's configuration would go its own directory. For
|
||||
instance, `~/repositories/lynx.git/gl-conf` would look like this:
|
||||
|
||||
%one_repo = (
|
||||
'lynx' => {
|
||||
'R' => {
|
||||
'alice' => 1,
|
||||
'bob' => 1
|
||||
},
|
||||
'W' => {
|
||||
'alice' => 1,
|
||||
'bob' => 1
|
||||
},
|
||||
'alice' => [
|
||||
[
|
||||
0,
|
||||
'refs/heads/next',
|
||||
'RW+'
|
||||
],
|
||||
[
|
||||
4,
|
||||
'refs/heads/master',
|
||||
'RW'
|
||||
]
|
||||
],
|
||||
'bob' => [
|
||||
[
|
||||
1,
|
||||
'refs/heads/next',
|
||||
'RW+'
|
||||
],
|
||||
[
|
||||
5,
|
||||
'refs/heads/master',
|
||||
'RW'
|
||||
]
|
||||
]
|
||||
}
|
||||
);
|
||||
|
||||
That does not reduce the overall size of the repo config (because you did not
|
||||
group the repos), but the main repo config is now even smaller!
|
||||
|
||||
<a name="_other_optimisations"></a>
|
||||
|
||||
### other optimisations
|
||||
|
||||
<a name="_disabling_various_defaults"></a>
|
||||
|
||||
#### disabling various defaults
|
||||
|
||||
The default RC file contains the following lines (we've already discussed the
|
||||
first one):
|
||||
|
||||
$GL_BIG_CONFIG = 0;
|
||||
$GL_NO_DAEMON_NO_GITWEB = 0;
|
||||
$GL_NO_CREATE_REPOS = 0;
|
||||
$GL_NO_SETUP_AUTHKEYS = 0;
|
||||
|
||||
`GL_NO_DAEMON_NO_GITWEB` is a very useful optimisation that you *must* enable
|
||||
if you *do* have a large number of repositories, and do *not* use gitolite's
|
||||
support for gitweb or git-daemon access (see "[this][gwd]" for details). This will save a
|
||||
lot of time when you push the gitolite-admin repo with changes. This variable
|
||||
also controls whether "git config" lines (such as `config hooks.emailprefix =
|
||||
"[gitolite]"`) will be processed or not.
|
||||
|
||||
You should be a lot more careful with `GL_NO_CREATE_REPOS` and
|
||||
`GL_NO_SETUP_AUTHKEYS`. These are meant for installations where some backend
|
||||
system already exists that does all the actual repo creation, (including
|
||||
setting up the proper hooks -- very important for access control), and all the
|
||||
authentication setup (ssh auth keys), respectively.
|
||||
|
||||
Summary: Please **leave those two variables alone** unless you're initials are
|
||||
"JK" ;-)
|
||||
|
||||
<a name="_optimising_the_authkeys_file"></a>
|
||||
|
||||
#### optimising the authkeys file
|
||||
|
||||
Sshd does a linear scan of the `~/.ssh/authorized_keys` file when an incoming
|
||||
connection shows up. This means that keys found near the top get served
|
||||
faster than keys near the bottom. On my laptop, it takes about 2500 keys
|
||||
before I notice the delay; on a typical server it could be double that, so
|
||||
don't worry about all this unless your user-count is in that range.
|
||||
|
||||
One way to deal with 5000+ keys is to use customised, database-backed ssh
|
||||
daemons, but many people are uncomfortable with taking non-standard versions
|
||||
of such a critical piece of the security infrastructure. In addition, most
|
||||
distributions do not make it painless to use them.
|
||||
|
||||
So what do you do?
|
||||
|
||||
The following trick uses the Pareto principle (a.k.a the "80-20 rule")
|
||||
to get an immediate boost in response for the most frequent or prolific
|
||||
developers. It can allow you to ignore the problem until the next big
|
||||
increase in your user counts!
|
||||
|
||||
Here's how:
|
||||
|
||||
* create subdirectories of keydir/ called 0, 1, (maybe 2, 3, etc., also),
|
||||
and 9.
|
||||
* in 0/, put in the pubkeys of the most frequent users
|
||||
* in 1/, add the next most important set of users, and so on for 2, 3, etc.
|
||||
* finally, put all the rest in 9/
|
||||
|
||||
Make sure "9" contains at least 70-90% of the total number of pubkeys,
|
||||
otherwise this doesn't really help.
|
||||
|
||||
You can easily determine who your top users are by runnning something like
|
||||
this (note the clever date command that always gets you last months log file!)
|
||||
|
||||
cat .gitolite/logs/gitolite-`date +%Y-%m -d -30days`.log |
|
||||
cut -f2 | sort | uniq -c | sort -n -r
|
||||
|
||||
<a name="_what_are_the_downsides_"></a>
|
||||
|
||||
### what are the downsides?
|
||||
|
||||
There are some downsides. The first one applies in all cases:
|
||||
|
||||
* If you use the delegation feature, you can no longer define or extend
|
||||
@groups in a fragment, for security reasons. It will also not let you use
|
||||
any group other than the @fragname itself (specifically, groups which
|
||||
contained a subset of the allowed @fragname, which would work normally, do
|
||||
not work now).
|
||||
|
||||
(If you didn't understand all that, you're probably not using delegation,
|
||||
so feel free to ignore it!)
|
||||
|
||||
The following apply if individual ("split") conf files are written, which in
|
||||
turn only happens if you used repo names instead of group names on the `repo`
|
||||
lines:
|
||||
|
||||
* the compile (gitolite-admin push) is now slower, because it potentially
|
||||
has to write a few thousand small files instead of one large one. Since
|
||||
the compile should be relatively infrequent compared to developer access,
|
||||
this is ok -- the main config file is parsed much faster now, so every hit
|
||||
to the server will benefit.
|
||||
|
||||
* we can no longer distinguish 'repo not found on disk' from 'you dont have
|
||||
access'. They both now look like 'you dont have access'.
|
||||
|
||||
<a name="_storing_usergroup_information_outside_gitolite_like_in_LDAP_"></a>
|
||||
|
||||
### storing usergroup information outside gitolite (like in LDAP)
|
||||
|
||||
[Please NOTE: this is all about *user* groups, not *repo* groups]
|
||||
|
||||
[WARNING: the earlier method of doing this has been discontinued; please see
|
||||
the commit message for details]
|
||||
|
||||
Gitolite now allows usergroup information to be stored outside its own config
|
||||
file. We'll see "why" first, then the "how".
|
||||
|
||||
<a name="_why"></a>
|
||||
|
||||
#### why
|
||||
|
||||
Large sites often have LDAP servers that already contain user and group
|
||||
information, including group membership details. Such sites may prefer that
|
||||
gitolite just pick up that info instead of having to redundantly put it in
|
||||
gitolite's config file.
|
||||
|
||||
Consider this example config for one repo:
|
||||
|
||||
repo foo
|
||||
RW+ = @lead_devs
|
||||
RW = @devs
|
||||
R = @interns
|
||||
|
||||
Normally, you would also need to specify:
|
||||
|
||||
@lead_devs = dilbert alice
|
||||
@devs = wally
|
||||
@interns = ashok
|
||||
|
||||
However, if the corporate LDAP server already tags these people correctly, and
|
||||
if there is some way of getting that information out **at run time**, that
|
||||
would be cool.
|
||||
|
||||
<a name="_how"></a>
|
||||
|
||||
#### how
|
||||
|
||||
All you need is a script that, given a username, queries your LDAP or similar
|
||||
server, and returns a space-separated list of all the groups she is a member
|
||||
of. If an invalid user name is sent in, or the user is valid but is not part
|
||||
of any groups, it should print nothing.
|
||||
|
||||
This script will probably be specific to your site. (See contrib/ldap for some
|
||||
example scripts that were contributed by the Nokia MeeGo team.)
|
||||
|
||||
Then set the `$GL_GET_MEMBERSHIPS_PGM` variable in the rc file to the full
|
||||
path of this program, set `$GL_BIG_CONFIG` to 1, and that will be that.
|
||||
|
||||
[gwd]: http://sitaramc.github.com/gitolite/doc/2-admin.html#gwd
|
||||
|
||||
<a name="_implementation_notes"></a>
|
||||
|
||||
### implementation notes
|
||||
|
||||
To understand how big-config works (at least when you're using grouped repos),
|
||||
we'll first look at how it works without this setting. Think back to the
|
||||
example at the top, and assume 'alice' is accessing the 'lynx' repo. The
|
||||
various rights are governed by the following hash elements:
|
||||
|
||||
# for the first level checks
|
||||
$repos{'lynx'}{'R'}{'alice'} = 1
|
||||
$repos{'lynx'}{'W'}{'alice'} = 1
|
||||
|
||||
# for the second level checks
|
||||
$repos{'lynx'}{'alice'}{'refs/heads/master'} = 'RW';
|
||||
$repos{'lynx'}{'alice'}{'refs/heads/next'} = 'RW+';
|
||||
|
||||
Those elements are explicitly specified in the compiled hash, as you can see
|
||||
(you don't need to know perl too much to read a hash; just make some educated
|
||||
guesses if needed!)
|
||||
|
||||
Now look at the compiled hash produced when `GL_BIG_CONFIG` is set. In place
|
||||
of both 'firefox' and 'lynx' you have '@wbr', and similarly '@devs' for both
|
||||
'alice' and 'bob'. In addition, there is a group hash at the bottom that
|
||||
lists each group and its members.
|
||||
|
||||
When 'alice' tries to access the 'lynx' repo, gitolite collects all the group
|
||||
names that these names belong to, so '@devs' is added to the list of 'user'
|
||||
names that 'alice' inherits permissions from, and '@wbr' is added to the list
|
||||
of 'repo' names that 'lynx' inherits from. This means that the final access
|
||||
inherits all permissions pertaining to the following combinations:
|
||||
|
||||
alice, lynx
|
||||
alice, @wbr
|
||||
@devs, lynx
|
||||
@devs, @wbr
|
||||
|
||||
(Actually there are 3 more... try and guess what they may be!)
|
||||
|
||||
Anyway, all ACL rules for these combinations are clubbed together to make the
|
||||
composite set of rules that 'alice' accessing 'lynx' is subject to.
|
|
@ -1,144 +0,0 @@
|
|||
## delegating access control responsibilities
|
||||
|
||||
[Thanks to jeromeag for forcing me to think through this...]
|
||||
|
||||
----
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_lots_of_repos_lots_of_users">lots of repos, lots of users</a>
|
||||
* <a href="#_splitting_up_the_set_of_repos_into_groups">splitting up the set of repos into groups</a>
|
||||
* <a href="#_delegating_ownership_of_groups_of_repos">delegating ownership of groups of repos</a>
|
||||
* <a href="#_other_notes">other notes</a>
|
||||
* <a href="#_security_philosophy_note">security/philosophy note</a>
|
||||
|
||||
----
|
||||
|
||||
<a name="_lots_of_repos_lots_of_users"></a>
|
||||
|
||||
### lots of repos, lots of users
|
||||
|
||||
Gitolite tries to make it easy to manage access to lots of users and repos,
|
||||
exploiting commonalities wherever possible. It lets you specify bits and
|
||||
pieces of the access control separately -- i.e., *all* the access specs for a
|
||||
certain repo need not be together; they can be scattered, which makes it
|
||||
easier to manage the sort of slice and dice needed in that example.
|
||||
|
||||
But eventually the config file will become too big. If you let only one
|
||||
person have control, he could become a bottleneck. If you give it to multiple
|
||||
people, they might make mistakes or stomp on each others' work accidentally.
|
||||
|
||||
The best way is to divide up the config file and give parts of it to different
|
||||
people.
|
||||
|
||||
Ideally, we would delegate authority for *groups* of repos, not individual
|
||||
repos, otherwise it doesn't scale. It would also be nice if we could prevent
|
||||
an admin from creating access rules for *any* repo in the system -- i.e., set
|
||||
limits on what repos he can control. This would be a nice "security" feature.
|
||||
|
||||
Delegation offers a way to do all that. Note that delegated admins cannot
|
||||
create or remove users, nor can they define new repos. They can only define
|
||||
access control rules for a set of repos they have been given authority for.
|
||||
|
||||
----
|
||||
|
||||
It's easier to show how it all works with an example instead of long
|
||||
descriptions.
|
||||
|
||||
<a name="_splitting_up_the_set_of_repos_into_groups"></a>
|
||||
|
||||
### splitting up the set of repos into groups
|
||||
|
||||
To start with, recall that gitolite allows you to specify **groups** (of users
|
||||
or repos, same syntax). So the basic idea is that the main config file
|
||||
(`conf/gitolite.conf` in your admin repo clone) will specify some repo groups:
|
||||
|
||||
# group your projects/repos however you want
|
||||
@webbrowser_repos = firefox lynx
|
||||
@webserver_repos = apache nginx
|
||||
@malware_repos = conficker storm
|
||||
|
||||
# any other config as usual, including access control lines for any of the
|
||||
# above projects or groups
|
||||
|
||||
<a name="_delegating_ownership_of_groups_of_repos"></a>
|
||||
|
||||
### delegating ownership of groups of repos
|
||||
|
||||
Once the repos are grouped, give each person charge of one or more groups.
|
||||
For example, Alice may be in charge of all web browser development projects,
|
||||
Bob takes care of web servers, and Mallory, as [tradition][abe] dictates, is
|
||||
in charge of malware ;-)
|
||||
|
||||
[abe]: http://en.wikipedia.org/wiki/Alice_and_Bob#List_of_characters
|
||||
|
||||
You do this by adding files with specific names to the `gitolite-admin` repo:
|
||||
|
||||
# the admin repo access was probably like this to start with:
|
||||
repo gitolite-admin
|
||||
RW+ = sitaram
|
||||
# now add these lines to the config for the admin repo
|
||||
RW = alice bob mallory
|
||||
RW+ NAME/ = sitaram
|
||||
RW NAME/conf/fragments/webbrowser_repos = alice
|
||||
RW NAME/conf/fragments/webserver_repos = bob
|
||||
RW NAME/conf/fragments/malware_repos = mallory
|
||||
|
||||
This uses gitolite's ability to restrict pushes by file/dir name being changed
|
||||
-- the syntax you see above ensures that, while "sitaram" does not have any
|
||||
NAME based restrictions, the other 3 users do. See `conf/example.conf` for
|
||||
syntax and notes.
|
||||
|
||||
As you can see, **for each repo group** you want to delegate authority over,
|
||||
there's a rule for a **corresponding file** in `conf/fragments` in the
|
||||
`gitolite-admin` repo. If you have write access to that file, you are allowed
|
||||
to define rules for repos in that repo group.
|
||||
|
||||
In other words, we use gitolite's file/dir NAME-based permissions to "enforce"
|
||||
the separation between the delegated configs!
|
||||
|
||||
Here's how to use this in practice:
|
||||
|
||||
* Alice clones the `gitolite-admin` repo, and adds a file called
|
||||
`conf/fragments/webbrowser_repos.conf`
|
||||
|
||||
* she writes in this file any access control rules for the "firefox" and
|
||||
"lynx" repos. She should not write access rules for any other project --
|
||||
they will be ignored
|
||||
|
||||
* Alice then commits and pushes to the `gitolite-admin` repo
|
||||
|
||||
Naturally, a successful push invokes the post-update hook that the admin repo
|
||||
has, which eventually runs the compile script. The **net effect** is as if
|
||||
you appended the contents of all the "fragment" files, in alphabetical order,
|
||||
to the bottom of the main file.
|
||||
|
||||
<a name="_other_notes"></a>
|
||||
|
||||
### other notes
|
||||
|
||||
The "include" statement cannot be used in fragment files, for security
|
||||
reasons.
|
||||
|
||||
----
|
||||
|
||||
<a name="_security_philosophy_note"></a>
|
||||
|
||||
### security/philosophy note
|
||||
|
||||
The delegation feature is meant only for access control rules, not pubkeys.
|
||||
Adding/removing pubkeys is a much more significant event than changing branch
|
||||
level permissions for people already on staff, and only the main admin should
|
||||
be allowed to do it.
|
||||
|
||||
Gitolite's "userids" all live in the same namespace. This is unlikely to
|
||||
change, so please don't ask -- it gets real complicated to do otherwise.
|
||||
Allowing delegated admins to add users means username collisions, which also
|
||||
means security problems (admin-A creates a pubkey for Admin-B, thus gaining
|
||||
access to all of Admin-B's stuff).
|
||||
|
||||
If you feel the need to delegate even that, please just go the whole hog and
|
||||
give them separate gitolite instances! It's pretty easy to setup the
|
||||
*software* itself system-wide, so that many users can use it without all the
|
||||
"easy install" fuss. See the "system install / user setup" section in
|
||||
doc/1-INSTALL.mkd for details.
|
|
@ -1,213 +0,0 @@
|
|||
## developer/patch maintainer notes
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_current_development_version">current development version</a>
|
||||
* <a href="#_testing_status_of_gitolite_v2_0rc1">testing status of gitolite v2.0rc1</a>
|
||||
* <a href="#_migration_to_gitolite_v2_x">migration to gitolite v2.x</a>
|
||||
* <a href="#_general_stuff">general stuff</a>
|
||||
* <a href="#_the_rc_file">the rc file</a>
|
||||
* <a href="#_modules">modules</a>
|
||||
* <a href="#_that_bindir_thing">that 'bindir' thing</a>
|
||||
* <a href="#_from_perl">from perl</a>
|
||||
* <a href="#_from_shell">from shell</a>
|
||||
* <a href="#_OUTLIER_">OUTLIER!</a>
|
||||
* <a href="#_special_types_of_setups">special types of setups</a>
|
||||
* <a href="#_Fedora">Fedora</a>
|
||||
|
||||
----
|
||||
|
||||
<a name="_current_development_version"></a>
|
||||
|
||||
### current development version
|
||||
|
||||
The current gitolite development version is v2.0rc1. Unless there is a
|
||||
serious security problem, *or* one of my large users [i.e., anyone whose name
|
||||
is in doc/who-uses-it.mkd (grin!)] needs it, all future changes will now
|
||||
happen here.
|
||||
|
||||
The commit looks *huge*, but it's mostly just large chunks of code moving
|
||||
around; there's not a whole lot of new code. However, I do apologise if
|
||||
anyone has their local changes conflicted when merging or rebasing against
|
||||
this version, and I promise to help as much as I can.
|
||||
|
||||
<a name="_testing_status_of_gitolite_v2_0rc1"></a>
|
||||
|
||||
#### testing status of gitolite v2.0rc1
|
||||
|
||||
Pretty much all the major features have been properly tested using the test
|
||||
suite. The following exceptions exist:
|
||||
|
||||
* basic, manual, testing only
|
||||
* most admin defined commands
|
||||
* smart http
|
||||
* mob branches
|
||||
* not yet tested
|
||||
* mirroring
|
||||
* things which I have no easy way to test
|
||||
* controlling gitweb authentication using gitolite (as described [here][gw])
|
||||
* SVN passthru
|
||||
|
||||
<a name="_migration_to_gitolite_v2_x"></a>
|
||||
|
||||
### migration to gitolite v2.x
|
||||
|
||||
In general, the procedure for migrating described in the install document
|
||||
should suffice. Even the rc file hasn't really changed much from the latest
|
||||
versions in v1.x, except that if you add a new variable to it you must also
|
||||
add it to the @EXPORT list in `src/gitolite_rc.pm`.
|
||||
|
||||
<a name="_general_stuff"></a>
|
||||
|
||||
### general stuff
|
||||
|
||||
* all scripts and libraries must be in the same directory. However, RPM/DEB
|
||||
packagers can put the libraries where they want, as long as they can be
|
||||
found in perl's default `@INC`.
|
||||
|
||||
* gl-auth-command **requires** an actual `~/.gitolite.rc` (except if your
|
||||
initials are "JK" or "DG", in which case `/etc/gitolite/gitolite.rc` also
|
||||
works!) It knows how to look around and set env vars etc correctly
|
||||
|
||||
* all programs except gl-auth-command **require** the environment variables
|
||||
`GL_RC` and `GL_BINDIR` set properly. Your best bet is to run them *via*
|
||||
gl-auth-command, like so:
|
||||
|
||||
path/to/gl-auth-command -e other_program other_program_arguments
|
||||
|
||||
In any case none of these programs are meant to be run manually -- pretty
|
||||
much all of them are run via gl-auth-command or from something that was
|
||||
forked from it so the variables *will* exist during normal operation.
|
||||
|
||||
<a name="_the_rc_file"></a>
|
||||
|
||||
### the rc file
|
||||
|
||||
The 'rc' file has one major change from v1: any new values in the rc file need
|
||||
to be added to the @EXPORT list in `src/gitolite_rc.pm`.
|
||||
|
||||
<a name="_modules"></a>
|
||||
|
||||
### modules
|
||||
|
||||
There are 3 "modules" (`gitolite_rc`, `gitolite_env`, and `gitolite` itself).
|
||||
Their purposes should be fairly obvious.
|
||||
|
||||
<a name="_that_bindir_thing"></a>
|
||||
|
||||
### that 'bindir' thing
|
||||
|
||||
The importance of `GL_BINDIR` is that the command= argument in
|
||||
`~/.ssh/authorized_keys` must be a full path, ideally, and the compile script
|
||||
gets this from `GL_BINDIR`.
|
||||
|
||||
<a name="_from_perl"></a>
|
||||
|
||||
#### from perl
|
||||
|
||||
* for frequently run perl programs, I prefer my method
|
||||
|
||||
* gl-auth-command -- this is invoked with a full path
|
||||
* gl-time -- same as above
|
||||
|
||||
* "their" ideal is "FindBin". I will use it only on manually or
|
||||
infrequently run programs
|
||||
|
||||
* gl-setup-authkeys (external shim to compile keys separately from PTA)
|
||||
|
||||
<a name="_from_shell"></a>
|
||||
|
||||
#### from shell
|
||||
|
||||
* a perl program called gl-query-rc finds its own BINDIR (using my perl
|
||||
method, not FindBin). This is suitable for calling from shell scripts
|
||||
as `${0%/*}/gl-query-rc GL_BINDIR`
|
||||
|
||||
* gl-mirror-shell (frequent use)
|
||||
* gl-setup
|
||||
* gl-tool
|
||||
|
||||
<a name="_OUTLIER_"></a>
|
||||
|
||||
#### OUTLIER!
|
||||
|
||||
* gl-dont-panic is an outlier. For some silly reason I have the notion that
|
||||
even if it runs from /tmp it should get the right values, so it is the
|
||||
only one that interrogates `~/.ssh/authorized_keys` to get the actual
|
||||
BINDIR in use!
|
||||
|
||||
<a name="_special_types_of_setups"></a>
|
||||
|
||||
### special types of setups
|
||||
|
||||
<a name="_Fedora"></a>
|
||||
|
||||
#### Fedora
|
||||
|
||||
Fedora has a very special setup, as follows:
|
||||
|
||||
* each user has his own userid and login
|
||||
* his/her ~/.ssh/authkeys file (containing only his/her key) has a
|
||||
"command=" clause invoking gl-auth-command
|
||||
* trusted users have "gl-auth-command -s" meaning they can get a shell if
|
||||
they want to
|
||||
|
||||
* actual git repos are under "git" (or some such), and include the chmod g+s
|
||||
(git init --shared) unix perms tricks for shared access
|
||||
|
||||
* but since they're coming through gl-auth, branch-level acls are in effect
|
||||
|
||||
* the gitolite config file is generated from some database and compiled (all
|
||||
via cron)
|
||||
|
||||
* the keydir/ is empty; in fact they probably don't use the admin repo at
|
||||
all, AFAIK
|
||||
|
||||
The most important implication of this setup is that **the RC file is no
|
||||
longer is `$HOME` of the 'git' user**. They keep it in
|
||||
`/etc/gitolite/gitolite.rc`. This means that a properly setup rc file must
|
||||
already be present in `/etc/gitolite/gitolite.rc` before doing any such
|
||||
installs.
|
||||
|
||||
----
|
||||
|
||||
# **Why v2?**
|
||||
|
||||
I went onto `#perl` to ask some question about setpriority() and got yelled at
|
||||
for writing "horrible code". And that was one of the kinder comments; my
|
||||
rather fragile ego is trying to forget the rest ;-)
|
||||
|
||||
They also gave me a link to a PDF book, "Modern Perl" by 'chromatic'. Nice
|
||||
book; one of the first things you learn from it is that you should not go to
|
||||
`#perl` for general help.
|
||||
|
||||
Anyway, the summary of the collective angst of `#perl` (well 2 people anyway)
|
||||
was: use Getopt::Long, FindBin, 'use lib', a library for HTTP stuff, stop
|
||||
prefixing subs with '&', and get rid of the huge number of 'our' declarations.
|
||||
|
||||
That last item is the only one I totally agree with, because it was on my long
|
||||
term todo list anyway. And 'use lib' sorta goes with it, so that's fine too.
|
||||
And as soon as I found that vim colors the sub names differently if you take
|
||||
out the '&' I decided I'd do that too :-) [But honestly, if `&sub` is so bad
|
||||
shouldn't "man perlsub" at least say something negative about it, other than
|
||||
"disables prototype checking", which doesn't matter here since I'm not using
|
||||
prototypes?]
|
||||
|
||||
As for the rest, FindBin brings in a good 1000+ lines for something that I do
|
||||
in a line or two (since I don't care about all the pathological edge cases).
|
||||
Getopt::Long is 2649 lines to replace the code below [note that there *is*
|
||||
only one possible option to this command, and it is *never* run manually
|
||||
either, so I don't need any fancy features]:
|
||||
|
||||
my $shell_allowed = 0;
|
||||
if (@ARGV and $ARGV[0] eq '-s') {
|
||||
$shell_allowed = 1;
|
||||
shift;
|
||||
}
|
||||
|
||||
Apparently TMTOWTDI has given way to TOOWTDI.
|
||||
|
||||
Anyway, I spent a few hours refactoring it. And I do thank them for pushing
|
||||
me to stop being lazy on the "our" business.
|
||||
|
||||
[gw]: https://github.com/sitaramc/gitolite/blob/pu/doc/3-faq-tips-etc.mkd#_easier_to_link_gitweb_authorisation_with_gitolite
|
|
@ -1,159 +0,0 @@
|
|||
# how gitolite uses ssh
|
||||
|
||||
Although other forms of authentications exist (see
|
||||
[doc/gitolite-without-ssh.mkd][ws]), ssh is the one that most git users use.
|
||||
|
||||
***Therefore, gitolite is (usually) heavily dependent on ssh***.
|
||||
|
||||
[ws]: http://sitaramc.github.com/gitolite/doc/gitolite-without-ssh.html
|
||||
|
||||
Most people didn't realise this, and even if they did they didn't know ssh
|
||||
well enough to help themselves. If you don't understand how ssh public key
|
||||
authentication works, or how the `~/.ssh/authorized_keys` file can be used to
|
||||
restrict users, etc., you will have endless amounts of trouble getting
|
||||
gitolite to work, because you'll be attacking the wrong problem.
|
||||
|
||||
So please please please understand this before tearing your hair out and
|
||||
blaming ***git/gitolite*** for whatever is going wrong with your setup :-)
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_ssh_basics">ssh basics</a>
|
||||
* <a href="#_how_does_gitolite_use_all_this_ssh_magic_">how does gitolite use all this ssh magic?</a>
|
||||
* <a href="#_restricting_shell_access_distinguishing_one_user_from_another">restricting shell access/distinguishing one user from another</a>
|
||||
* <a href="#_restricting_branch_level_actions">restricting branch level actions</a>
|
||||
|
||||
----
|
||||
|
||||
<a name="_ssh_basics"></a>
|
||||
|
||||
### ssh basics
|
||||
|
||||
Let's start with some basics, focusing *only* on the pieces relevant to
|
||||
`gitolite`. If this is not detailed enough, please use google and learn more
|
||||
from somewhere, or maybe buy the OReilly ssh book.
|
||||
|
||||
* You can login to an ssh server by typing a password, but ssh can also use
|
||||
***public-private keys*** (also called "key pairs") for authentication.
|
||||
`gitolite` *requires* you to use this mechanism for your users -- they
|
||||
cannot log in using passwords. Hopefully by the time you finish reading
|
||||
this document you will understand why :-)
|
||||
|
||||
The way you set this up is you generate a key pair on your workstation,
|
||||
and give the server the public key. (I need not add that the "private"
|
||||
key must be, well, kept *private*!)
|
||||
|
||||
* **generating a key pair on your workstation** is done by running the
|
||||
command `ssh-keygen -t rsa`. This produces two files in `~/.ssh`. One is
|
||||
`id_rsa`; this is the **private** key -- ***never*** let it out of your
|
||||
machine. The other is `id_rsa.pub`, which is the corresponding public
|
||||
key. This public key is usually just one long line of text.
|
||||
|
||||
* on Windows machines with msysgit installed, you should do this from
|
||||
within a "git bash" window. The command will report the full path where
|
||||
the files have been written; make a note of this, and use those files in
|
||||
any of the description that follows
|
||||
|
||||
* **adding your public key to the server**'s `~/.ssh/authorized_keys`
|
||||
file is how ssh uses pubkeys to authenticate users. Let's say
|
||||
sita@work.station is trying to log in as git@serv.er. What you have to do
|
||||
is take the `~/.ssh/id_rsa.pub` file for user sita on work.station and
|
||||
append its contents (remember it's only one line) to
|
||||
`~/.ssh/authorized_keys` for user git on serv.er.
|
||||
|
||||
The `authorized_keys` file can have multiple public keys (from many
|
||||
different people) added to it so any of them can log in to git@serv.er.
|
||||
|
||||
In the normal case (not gitolite, but your normal everyday shell access),
|
||||
there's a command that does this, `ssh-copy-id`, which also fixes up
|
||||
permissions etc., as needed, since sshd is a little picky about allowing
|
||||
pubkey access if permissions on the server are loose. Or you can do it
|
||||
manually, as long as you know what you're doing and you're careful not to
|
||||
erase or overwrite the existing contents of `~/.ssh/authorized_keys` on
|
||||
the server!
|
||||
|
||||
But in the gitolite case, it's different; we'll get to that in a minute.
|
||||
|
||||
* **troubleshooting pubkey authentication failures**: if you are unable to
|
||||
get ssh access to the server after doing all this, you'll have to look
|
||||
in `/var/log/secure` or `/var/log/auth.log` or some such file on the
|
||||
server to see what specific error `sshd` is complaining about.
|
||||
|
||||
* **restricting users to specific commands** is very important for gitolite.
|
||||
If you read `man sshd` and look for `authorized_keys file format`, you'll
|
||||
see a lot of options you can add to the public key line, which restrict
|
||||
the incoming user in various ways. In particular, note the `command=`
|
||||
option, which means "regardless of what the incoming user is asking to do,
|
||||
forcibly run this command instead".
|
||||
|
||||
Also note that when there are many public keys (i.e., lines) in the
|
||||
`authorized_keys` file, each line can have a *different* set of options
|
||||
and `command=` values.
|
||||
|
||||
**This is the backbone of what makes gitolite work; please make sure you
|
||||
understand this**
|
||||
|
||||
<a name="_how_does_gitolite_use_all_this_ssh_magic_"></a>
|
||||
|
||||
### how does gitolite use all this ssh magic?
|
||||
|
||||
These are two different questions you ought to be having by now:
|
||||
|
||||
* how does it distinguish between me and someone else, since we're all
|
||||
logging in as the same remote user "git"
|
||||
* how does it restrict what I can do within a repository
|
||||
|
||||
<a name="_restricting_shell_access_distinguishing_one_user_from_another"></a>
|
||||
|
||||
#### restricting shell access/distinguishing one user from another
|
||||
|
||||
The answer to the first question is the `command=` we talked about before. If
|
||||
you look in the `authorized_keys` file, you'll see entries like this (I chopped
|
||||
off the ends of course; they're pretty long lines):
|
||||
|
||||
command="[path]/gl-auth-command sitaram",[more options] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA18S2t...
|
||||
command="[path]/gl-auth-command usertwo",[more options] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEArXtCT...
|
||||
|
||||
First, it finds out which of the public keys in this file match the incoming
|
||||
login. That's crypto stuff, and I won't go into it. Once the match has been
|
||||
found, it will run the command given on that line; e.g., if I logged in, it
|
||||
would run `[path]/gl-auth-command sitaram`. So the first thing to note is
|
||||
that such users do not get "shell access", which is good!
|
||||
|
||||
Before running the command, however, sshd sets up an environment variable
|
||||
called `SSH_ORIGINAL_COMMAND` which contains the actual git command that your
|
||||
workstation sent out. This is the command that *would have run* if you did
|
||||
not have the `command=` part in the authorised keys file.
|
||||
|
||||
When `gl-auth-command` gets control, it looks at the first argument
|
||||
("sitaram", "usertwo", etc) to determine who you are. It then looks at the
|
||||
`SSH_ORIGINAL_COMMAND` variable to find out which repository you want to
|
||||
access, and whether you're reading or writing.
|
||||
|
||||
Now is has user, repository, and access requested (read/write), gitolite looks
|
||||
at its config file, and either allows or rejects the request.
|
||||
|
||||
But this cannot differentiate between different branches within a repo; that
|
||||
has to be done separately.
|
||||
|
||||
<a name="_restricting_branch_level_actions"></a>
|
||||
|
||||
#### restricting branch level actions
|
||||
|
||||
[If you look inside the git source tree, there's a file among the "howto"s in
|
||||
there called `update-hook-example.txt`, which was the inspiration for this
|
||||
part of gitolite.]
|
||||
|
||||
Git allows you to specify many "hooks", which get control as various events
|
||||
happen -- see `git help hooks` for details. One of those hooks is the
|
||||
`update` hook, which, if it is present, is invoked just before a branch or a
|
||||
tag is about to be updated. The hook is passed the name of the branch or tag,
|
||||
the old SHA1 value, and the new SHA1 value, as arguments. Hooks that are
|
||||
called *before* an action happens are allowed to prevent that action from
|
||||
happening y returning an error code.
|
||||
|
||||
When gitolite is told to create a new repository (by the admin), it installs
|
||||
a special update hook. This hook takes all the information presented, looks
|
||||
at the config file, and decides to allow or reject the update.
|
||||
|
||||
And that's basically it.
|
|
@ -1,75 +0,0 @@
|
|||
# gitolite without ssh
|
||||
|
||||
Gitolite does not actually need ssh. If you managed to read
|
||||
[doc/gitolite-and-ssh.mkd][gas], you may have realised that the crux of
|
||||
gitolite is that it be eventually invoked as
|
||||
|
||||
/full/path/to/gl-auth-command some-authenticated-gitolite-username
|
||||
|
||||
(where the "gitolite username" is a "virtual" username; it does not have to
|
||||
be, and usually *isn't*, an actual *unix* username).
|
||||
|
||||
[gas]: http://sitaramc.github.com/gitolite/doc/gitolite-and-ssh.html
|
||||
|
||||
### sidebar: authentication versus authorisation
|
||||
|
||||
> Just for completeness, I'd like to loosely define these two animals.
|
||||
|
||||
> **Authentication** is the process of verifying that you are who you claim
|
||||
> to be. An authentication system will establish that I am the user
|
||||
> "sitaram" on my work system. The one behind gmail will similarly
|
||||
> establish that I am "sitaramc". And so on...
|
||||
|
||||
> **Authorisation** is the process of asking what you want to do and
|
||||
> deciding if you're allowed to do it or not.
|
||||
|
||||
### what does gitolite actually do
|
||||
|
||||
With that background, here's the truth about gitolite:
|
||||
|
||||
> ***Gitolite does not do authentication. It only does authorisation.***
|
||||
|
||||
Yes, the default mode of using gitolite does use ssh keys, but all it's doing
|
||||
is helping you **setup** ssh-based authentication **as a convenience to you**.
|
||||
But nothing forces you to use it. The best example: there are no ssh keys
|
||||
involved if you setup [smart http][sh] mode.
|
||||
|
||||
[sh]: http://sitaramc.github.com/gitolite/doc/http-backend.html
|
||||
|
||||
In other words, authentication is the job of `sshd` or `httpd`, not gitolite.
|
||||
|
||||
### using other authentication systems with gitolite
|
||||
|
||||
The bottom line in terms of how to invoke gitolite has been described up at
|
||||
the top, and as long as you manage to do that gitolite won't even know how the
|
||||
authentication was done. Which in turn means you can use whatever
|
||||
authentication scheme you want.
|
||||
|
||||
[Side note: it also expects that the environment variable
|
||||
`SSH_ORIGINAL_COMMAND` contain the command that the client sent (typically a
|
||||
git-receive-pack or git-upload-pack command), or in some CGI variables when
|
||||
using [smart http][sh] mode.]
|
||||
|
||||
However, it has to be an authentication system that is compatible with sshd or
|
||||
httpd in some form. Why? Because the git *client* accessing the server only
|
||||
knows those 2 protocols to "speak git". (Well, the `git://` protocol is
|
||||
unauthenticated, and `file://` doesn't really apply to this discussion, so
|
||||
we're ignoring those).
|
||||
|
||||
One common example is LDAP. Let's say you have an LDAP-based authentication
|
||||
system somewhere. It is possible to make apache use that to authenticate
|
||||
users, so when a user accesses a git url using
|
||||
`http://sitaram:password@git.example.com/repo`, it is LDAP that does the
|
||||
actual authentication. [I wouldn't know how to do it but I know it is
|
||||
possible. Patches to this doc explaining how are welcome!]
|
||||
|
||||
There are also ssh daemons that use LDAP to store the authorised keys (instead
|
||||
of putting them all in `~/.ssh/authorized_keys`). The clients will still need
|
||||
to generate keypairs and send them to the admin, but they can be more
|
||||
centrally stored and perhaps used by other programs or tools simultaneously,
|
||||
which can be useful.
|
||||
|
||||
Finally, gitolite allows you to store *group* information externally too. See
|
||||
[here][ldap] for more on this.
|
||||
|
||||
[ldap]: http://sitaramc.github.com/gitolite/doc/big-config.html#_storing_usergroup_information_outside_gitolite_like_in_LDAP_
|
|
@ -1,489 +0,0 @@
|
|||
# the access control file `gitolite.conf`
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_syntax">syntax</a>
|
||||
* <a href="#_continuation_lines">continuation lines</a>
|
||||
* <a href="#_include_files">include files</a>
|
||||
* <a href="#_basic_access_control">basic access control</a>
|
||||
* <a href="#_how_rules_are_matched">how rules are matched</a>
|
||||
* <a href="#_branches_tags_and_specifying_refex_es">branches, tags, and specifying "refex"es</a>
|
||||
* <a href="#_groups">groups</a>
|
||||
* <a href="#_the_special_all_group">the special `@all` group</a>
|
||||
* <a href="#_advanced_access_control">advanced access control</a>
|
||||
* <a href="#_creating_and_deleting_branches">creating and deleting branches</a>
|
||||
* <a href="#_deny_rules">"deny" rules</a>
|
||||
* <a href="#_IMPORTANT_NOTES_ABOUT_DENY_RULES_">***IMPORTANT NOTES ABOUT "DENY" RULES***:</a>
|
||||
* <a href="#_summary_permissions">summary: permissions</a>
|
||||
* <a href="#_virtual_ref_types">virtual "ref"-types</a>
|
||||
* <a href="#_other_tips">other tips</a>
|
||||
* <a href="#_splitting_up_rules_into_rulesets">splitting up rules into rulesets</a>
|
||||
* <a href="#_gitweb_and_daemon">gitweb and daemon</a>
|
||||
* <a href="#_repo_specific_git_config_commands">repo specific `git config` commands</a>
|
||||
* <a href="#_repo_owner_description_line_for_gitweb">repo owner/description line for gitweb</a>
|
||||
|
||||
Gitolite has an advanced access control language that is designed to be
|
||||
powerful but easy to use. Other objectives were that it should be even easier
|
||||
to read, review and audit the rules, and it should scale to thousands of repos
|
||||
and users. There was also, in the author's mind, a desperate need to create
|
||||
something as different as possible from the brain-dead, nausea-inducing
|
||||
"Windows INI" style syntax that some other popular tools seem to favour.
|
||||
|
||||
This document describes the syntax and semantics of the access control rules
|
||||
and other configuration directives in the `gitolite.conf` file.
|
||||
|
||||
<a name="_syntax"></a>
|
||||
|
||||
### syntax
|
||||
|
||||
In general, everything is **space separated**; there are no commas,
|
||||
semicolons, etc., in the syntax.
|
||||
|
||||
**Comments** are in the usual shell-ish style.
|
||||
|
||||
**User names** and **repo names** are as simple as possible; they must start
|
||||
with an alphanumeric, but after that they can also contain `.`, `_`, or `-`.
|
||||
|
||||
Usernames can optionally be followed by an `@` and a domainname containing at
|
||||
least one `.` (this allows you to use an email address as someone's username).
|
||||
Reponames can contain `/` characters (this allows you to put your repos in a
|
||||
tree-structure for convenience)
|
||||
|
||||
<a name="_continuation_lines"></a>
|
||||
|
||||
#### continuation lines
|
||||
|
||||
There are no continuation lines -- gitolite does not process C-style
|
||||
backslash-escaped newlines as anything special. However, the section on
|
||||
"groups" will tell you how you can break up large lists of names in a group
|
||||
definition into multiple lines.
|
||||
|
||||
<a name="_include_files"></a>
|
||||
|
||||
#### include files
|
||||
|
||||
Gitolite allows you to break up the configuration into multiple files and
|
||||
include them in the main file for convenience.
|
||||
|
||||
include "foo.conf"
|
||||
|
||||
will include the contents of the file "foo.conf" from the same directory as
|
||||
the main config file. You can also use an absolute path if you like, although
|
||||
in the interests of cloning the admin-repo sanely you should avoid doing this!
|
||||
|
||||
You can also use a glob, as in:
|
||||
|
||||
include "*.conf"
|
||||
|
||||
which will include all the ".conf" files from the directory in which the main
|
||||
config file exists.
|
||||
|
||||
Files that have been already processed once are skipped, with a warning.
|
||||
|
||||
[Advanced users: the include statement cannot be used inside a delegated
|
||||
config file, for security reasons].
|
||||
|
||||
<a name="_basic_access_control"></a>
|
||||
|
||||
### basic access control
|
||||
|
||||
Here's a very basic set of rules:
|
||||
|
||||
repo gitolite-admin
|
||||
RW+ = sitaram
|
||||
|
||||
repo testing
|
||||
RW+ = @all
|
||||
|
||||
repo gitolite simplicity
|
||||
RW+ = sitaram dilbert
|
||||
RW = alice ashok
|
||||
R = wally
|
||||
|
||||
It should be easy to guess what most of this means:
|
||||
|
||||
* `R` means "read" permission
|
||||
* `RW` means "read and write", but no rewind
|
||||
* `RW+` means "read and write", with rewind allowed
|
||||
|
||||
A "rewind" is more often called a "non-fast forward push"; see git docs for
|
||||
what that is. The `+` was chosen because it is part of the "git push" syntax
|
||||
for non-ff pushes.
|
||||
|
||||
In a later section you'll see some more advanced permissions.
|
||||
|
||||
<a name="_how_rules_are_matched"></a>
|
||||
|
||||
#### how rules are matched
|
||||
|
||||
It's important to understand that there're two levels at which access control
|
||||
happens. Please see [this][l2] for details, especially about the first level
|
||||
check. Much of the complexity applies only to the second level check, so that
|
||||
is all we will be discussing here. This check is done by the update hook, and
|
||||
determines whether the push succeeds or fails.
|
||||
|
||||
[l2]: http://sitaramc.github.com/gitolite/doc/3-faq-tips-etc.html#_two_levels_of_access_rights_checking
|
||||
|
||||
For basic permissions like this, matching is simple. Gitolite already knows:
|
||||
|
||||
* the user
|
||||
* the repo
|
||||
* the branch or tag ("ref") being pushed
|
||||
* whether it is a normal (ff) push or a rewind (non-ff) push.
|
||||
|
||||
Gitolite goes down the list of rules matching the user, repo, and the ref.
|
||||
The first matching rule that has the permission you're looking for (`W` or
|
||||
`+`), results in success. A fallthrough results in failure.
|
||||
|
||||
<a name="_branches_tags_and_specifying_refex_es"></a>
|
||||
|
||||
#### branches, tags, and specifying "refex"es
|
||||
|
||||
One of the original goals of gitolite was to allow access control at the
|
||||
branch/tag (aka "ref") level. The git source code contains a sample update
|
||||
hook that has the following in it:
|
||||
|
||||
# from Documentation/howto/update-hook-example.txt:
|
||||
|
||||
refs/heads/master junio
|
||||
+refs/heads/pu junio
|
||||
refs/heads/cogito$ pasky
|
||||
refs/heads/bw/.* linus
|
||||
refs/heads/tmp/.* .*
|
||||
refs/tags/v[0-9].* junio
|
||||
|
||||
If you did this in gitolite, this is what the equivalents would be:
|
||||
|
||||
repo git
|
||||
RW master$ = junio # line 1
|
||||
RW+ pu$ = junio # line 2
|
||||
RW cogito$ = pasky # line 3
|
||||
RW bw/ = linus # line 4
|
||||
RW tmp/ = @all # line 5
|
||||
RW refs/tags/v[0-9] = junio # line 6
|
||||
|
||||
The following points will help you understand these rules. (Git recap:
|
||||
branches and tags together are called "ref"s in git. A branch ref usually
|
||||
looks like "refs/heads/foo", while a tag ref looks like "refs/tags/bar")
|
||||
|
||||
* the general syntax of a paragraph of rules is:
|
||||
|
||||
# start line:
|
||||
repo [one or more repos and/or repo groups]
|
||||
# followed by one or more permissions lines:
|
||||
[permission] [zero or more refexes] = [one or more users]
|
||||
|
||||
* a **refex** is a *perl regex* that matches a ref. When you try to push a
|
||||
commit to a branch or a tag, that "ref" is matched against the refex part
|
||||
of each rule
|
||||
|
||||
* if the refex does not start with `refs/`, gitolite assumes a prefix of
|
||||
`refs/heads/`. This is useful because *branch* matching is the most
|
||||
common case, as you can see this applies to lines 1 through 5 here.
|
||||
|
||||
* if no refex appears, the rule applies to all refs in that repo
|
||||
|
||||
* refexes are prefix-matched (they are internally anchored with `^` before
|
||||
being used). This means only the beginning of the actual ref needs to
|
||||
match the refex, unless the refex has an explicit `$` meta-character at
|
||||
the end (like the first 3 lines in our example do).
|
||||
|
||||
Line 5, for instance, allows anyone to push a branch inside the "tmp/"
|
||||
namespace, while line 6 provides the ability to push version tags; "v1",
|
||||
"v1.0", "v2.0rc1", all match the criterion specified by `v[0-9]` because
|
||||
this is a prefix match only.
|
||||
|
||||
<a name="_groups"></a>
|
||||
|
||||
#### groups
|
||||
|
||||
Gitolite allows you to define **groups** of repos. users, or even refexes. A
|
||||
group is semantically (but *not* syntactically) like a `#define` in C. Here
|
||||
is an example of each kind:
|
||||
|
||||
@oss_repos = gitolite linux git perl rakudo entrans vkc
|
||||
@staff = sitaram some_dev another-dev
|
||||
@important = master$ QA_done refs/tags/v[0-9]
|
||||
|
||||
The syntax of a group definition is simply:
|
||||
|
||||
@groupname = [one or more names]
|
||||
|
||||
A group can *accumulate* values. For example:
|
||||
|
||||
@staff = sitaram some_dev another-dev
|
||||
@staff = au.thor
|
||||
|
||||
is the same as
|
||||
|
||||
@staff = sitaram some_dev another-dev au.thor
|
||||
|
||||
This is more convenient than continuation lines, because it allows you to add
|
||||
to a group anywhere. Many people generate their gitolite.conf itself from
|
||||
some *other* database, and it is very useful to be able to do this sort of
|
||||
thing.
|
||||
|
||||
Groups can include other groups, and the included group will be expanded to
|
||||
whatever value it *currently* has:
|
||||
|
||||
@staff = sitaram some_dev another-dev # line 1
|
||||
@staff = au.thor # line 2
|
||||
@interns = indy james # line 3
|
||||
@alldevs = bob @interns @staff # line 4
|
||||
|
||||
"@alldevs" expands to 7 names now. However, remember that the config file is
|
||||
parsed in a single-pass, so later *additions* to a group name cannot affect
|
||||
earlier *uses* of it. If you moved line 2 to the end, "@alldevs" would only
|
||||
have 6 names in it.
|
||||
|
||||
<a name="_the_special_all_group"></a>
|
||||
|
||||
##### the special `@all` group
|
||||
|
||||
There's a special group called `@all` that includes all authenticated users
|
||||
when used as a username; you've seen examples of it earlier.
|
||||
|
||||
[Advanced users: also see the entry for `GL_ALL_INCLUDES_SPECIAL` in
|
||||
[doc/gitolite.rc.mkd][rcdoc].]
|
||||
|
||||
When used as a reponame, it includes all repos.
|
||||
|
||||
<a name="_advanced_access_control"></a>
|
||||
|
||||
### advanced access control
|
||||
|
||||
The previous section is sufficient for most common needs, but gitolite can go
|
||||
a lot further than that.
|
||||
|
||||
<a name="_creating_and_deleting_branches"></a>
|
||||
|
||||
#### creating and deleting branches
|
||||
|
||||
Since the beginning of gitolite, `RW` gave the ability, not only to update,
|
||||
but to *create* a branch (that matched the refex). Similarly, `RW+` meant
|
||||
being able to not only rewind, but also delete a ref. Conceptually, a rewind
|
||||
is almost the same as a delete+push (the only difference I can see is if you
|
||||
had core.logAllRefUpdates set, which is *not* a default setting).
|
||||
|
||||
However, there seem to be cases where it is useful to distinguish these cases.
|
||||
Arguments can be made on all sides if you're dealing with new users, so
|
||||
gitolite supports that.
|
||||
|
||||
We'll look at the delete/rewind case in detail first:
|
||||
|
||||
* if the rules for a repo do not contain a `D` anywhere, then `RW+` will
|
||||
allow both rewind and delete operations. Apart from being more convenient
|
||||
if you don't need this separation, this also ensures backward
|
||||
compatibility for setups created before this separation feature was added
|
||||
to gitolite).
|
||||
|
||||
* if, however, *any* of the rules for a repo contains a `D` (example: `RWD`,
|
||||
`RW+D`, etc) then `RW+` by itself will permit only a rewind, not a delete
|
||||
|
||||
The same thing applies to create/push, where if you have a permissions like
|
||||
`RWC` or `RW+C` anywhere, a simple `RW` or `RW+` can no longer *create* a new
|
||||
ref.
|
||||
|
||||
You can combine the `C` and `D` also. Thus, the set of permissions you now
|
||||
know about are, in regex syntax: `R|RW+?C?D?`. See a later section for the
|
||||
full set of permissions possible.
|
||||
|
||||
Some usage hints:
|
||||
|
||||
* if you find that `RW+` no longer allows creation/deletion but you can't
|
||||
see a `C`/`D` permission in the rules, remember that gitolite allows a
|
||||
repo config to be specified in multiple places for convenience, included
|
||||
delegated or included files. Be sure to search everywhere :)
|
||||
|
||||
* a quick way to make this the default for *all* your repos is:
|
||||
|
||||
repo @all
|
||||
RWCD dummy-branch = foo
|
||||
|
||||
where foo can be either the administrator, or if you can ignore the
|
||||
warning message when you push, a non-existant user.
|
||||
|
||||
<a name="_deny_rules"></a>
|
||||
|
||||
#### "deny" rules
|
||||
|
||||
Take a look at the following snippet, which *seems* to say that "bruce" can
|
||||
write versioned tags (anything containing `refs/tags/v[0-9]`), but the other
|
||||
staffers can't:
|
||||
|
||||
@staff = bruce whitfield martin
|
||||
[... and later ...]
|
||||
RW refs/tags/v[0-9] = bruce
|
||||
RW refs/tags = @staff
|
||||
|
||||
But that's not how the matching works. As long as any refex matches the
|
||||
refname being updated, it's a "yes". Since the second refex (which says
|
||||
"anything containing `refs/tags`") is a superset of the first one, it lets
|
||||
anyone on `@staff` create versioned tags, not just Bruce.
|
||||
|
||||
So how do we say "these people can create any tags except tags that look like
|
||||
this pattern"?
|
||||
|
||||
One way to fix this is to allow "deny" rules. We make a small addition to the
|
||||
permissions syntax, and define a more rigorous, ordered, interpretation.
|
||||
|
||||
Let's recap the **existing semantics**:
|
||||
|
||||
> The first matching refex that has the permission you're looking for (`W`
|
||||
> or `+`), results in success. A fallthrough results in failure.
|
||||
|
||||
Here are the **new semantics**, with changes from the "main" one in bold:
|
||||
|
||||
> The first matching refex that has the permission you're looking for (`W`
|
||||
> or `+`) **or a minus (`-`)**, results in success **or failure,
|
||||
> respectively**. A fallthrough **also** results in failure.
|
||||
|
||||
So the example we started with becomes, if you use "deny" rules:
|
||||
|
||||
RW refs/tags/v[0-9] = bruce
|
||||
- refs/tags/v[0-9] = @staff
|
||||
RW refs/tags = @staff
|
||||
|
||||
And here's how it works:
|
||||
|
||||
* for non-version tags, only the 3rd rule matches, so anyone on staff can
|
||||
push them
|
||||
* for version tags by bruce, the first rule matches so he can push them
|
||||
* for version tags by staffers *other than bruce*, the second rule matches
|
||||
before the third one, and it has a `-` as the permission, so the push
|
||||
fails
|
||||
|
||||
<a name="_IMPORTANT_NOTES_ABOUT_DENY_RULES_"></a>
|
||||
|
||||
##### ***IMPORTANT NOTES ABOUT "DENY" RULES***:
|
||||
|
||||
* deny rules do NOT affect read access. They only apply to write access.
|
||||
|
||||
* when using deny rules, the order of your rules starts to matter, where
|
||||
earlier it did not. If you're just starting to add a deny rule to an
|
||||
existing ruleset, it's a good idea to review the entire ruleset once, to
|
||||
make sure you're doing it right.
|
||||
|
||||
<a name="_summary_permissions"></a>
|
||||
|
||||
### summary: permissions
|
||||
|
||||
The full set of permissions, in regex syntax: `-|R|RW+?C?D?`. This expands to
|
||||
one of `-`, `R`, `RW`, `RW+`, `RWC`, `RW+C`, `RWD`, `RW+D`, `RWCD`, or
|
||||
`RW+CD`. and by now you know what they all mean.
|
||||
|
||||
[Side note: There is one more very important permissions to be dealt with --
|
||||
the standalone `C`, which is not really a "ref" level permission and can be
|
||||
found in doc/wildcard-repositories.mkd.]
|
||||
|
||||
<a name="_virtual_ref_types"></a>
|
||||
|
||||
### virtual "ref"-types
|
||||
|
||||
This is a highly advanced topic; see [doc/virtualrefs-and-scoring.mkd][vs] for
|
||||
details.
|
||||
|
||||
<a name="_other_tips"></a>
|
||||
|
||||
### other tips
|
||||
|
||||
<a name="_splitting_up_rules_into_rulesets"></a>
|
||||
|
||||
#### splitting up rules into rulesets
|
||||
|
||||
Gitolite lets you specify access rules for a repo in bits and pieces. This
|
||||
can be very convenient sometimes. Let's say you have a mix of open source and
|
||||
closed source projects, and "bosses" should have read access to all projects,
|
||||
and everyone should have read access to open source projects. Assuming the
|
||||
appropriate group definitions, this would work:
|
||||
|
||||
# all bosses have read access to all projects
|
||||
repo @open @closed @topsecret
|
||||
R = @bosses
|
||||
|
||||
# everyone has read access to "open" projects
|
||||
repo @open
|
||||
R = @bosses @devs @interns
|
||||
|
||||
If you notice that `@bosses` are given read access to `@open` via both rules,
|
||||
don't worry that this causes some duplication or inefficiency. It doesn't :-)
|
||||
|
||||
Elsewhere in the file, you would specify access for individual repos (like RW,
|
||||
RW+, etc). Gitolite combines all of these access rules, maintaining the
|
||||
textual order in which they occur, when authorising a push.
|
||||
|
||||
And although this example used groups, you can use reponames as well, or mix
|
||||
and match them. You can even distribute rulesets across multiple "include"
|
||||
files if you wish.
|
||||
|
||||
Just remember that if you use [deny rules][dr] anywhere then the *order of the
|
||||
rules matters*!
|
||||
|
||||
[dr]: http://sitaramc.github.com/gitolite/doc/gitolite.conf.html#_deny_rules
|
||||
|
||||
This feature also helps people who generate their gitolite.conf itself from
|
||||
some *other* database -- it allows them much more flexibility in how they
|
||||
generate rules.
|
||||
|
||||
<a name="_gitweb_and_daemon"></a>
|
||||
|
||||
#### gitweb and daemon
|
||||
|
||||
Gitolite allows you to specify access for git-daemon and gitweb. See
|
||||
[this][gwd] for more on this.
|
||||
|
||||
[gwd]: http://sitaramc.github.com/gitolite/doc/2-admin.html#gwd
|
||||
|
||||
<a name="_repo_specific_git_config_commands"></a>
|
||||
|
||||
#### repo specific `git config` commands
|
||||
|
||||
(Thanks to teemu dot matilainen at iki dot fi)
|
||||
|
||||
Sometimes you want to specify `git config` settings for some of your repos.
|
||||
For example, you may have a custom post-receive hook that sends an email when
|
||||
a push happens, and this hook needs to know whom to send the email to, etc.
|
||||
|
||||
You can set git config values by specifying something like this within a
|
||||
"repo" paragraph:
|
||||
|
||||
example usage: if you placed a hook in hooks/common that requires
|
||||
configuration information that is specific to each repo, you could do this:
|
||||
|
||||
repo gitolite
|
||||
config hooks.mailinglist = gitolite-commits@example.tld
|
||||
config hooks.emailprefix = "[gitolite] "
|
||||
config foo.bar = ""
|
||||
config foo.baz =
|
||||
|
||||
The syntax is simple:
|
||||
|
||||
config sectionname.keyname = [optional value_string]
|
||||
|
||||
This does either a plain "git config section.key value" (for the first 3
|
||||
examples above) or "git config --unset-all section.key" (for the last
|
||||
example). Other forms (--add, the `value_regex`, etc) are not supported.
|
||||
|
||||
**Note**: this won't work unless the rc file has the right settings; please
|
||||
see comments around the variable `$GL_GITCONFIG_KEYS` in doc/gitolite.rc.mkd
|
||||
for details and security information.
|
||||
|
||||
[rcdoc]: http://sitaramc.github.com/gitolite/doc/gitolite.rc.html
|
||||
|
||||
<a name="_repo_owner_description_line_for_gitweb"></a>
|
||||
|
||||
#### repo owner/description line for gitweb
|
||||
|
||||
Including a line like this:
|
||||
|
||||
gitolite "Sitaram Chamarty" = "fast, secure, access control for git in a corporate environment"
|
||||
|
||||
sets the owner name and description for gitweb. The general syntax is very
|
||||
simple, just use one of:
|
||||
|
||||
reponame = "some description string in double quotes"
|
||||
reponame "owner name" = "some description string in double quotes"
|
||||
|
||||
Note: setting a description also gives gitweb access; you do not have to give
|
||||
gitweb access explicitly (as described or linked above) if you're specifying a
|
||||
description.
|
|
@ -1,373 +0,0 @@
|
|||
# configuring gitolite's advanced features -- the `.gitolite.rc` file
|
||||
|
||||
This is the documentation for the contents of the "rc" file
|
||||
(`$HOME/.gitolite.rc`) on the server. Until now this documentation was
|
||||
inline, within the rc file itself, but it has grown too large, too unwieldy,
|
||||
and too difficult to grok for people new to gitolite.
|
||||
|
||||
The documentation follows approximately the same order as the sample variables
|
||||
in the (now reorganised) example "rc" file.
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_variables_that_should_not_be_touched_at_all">variables that should not be touched at all</a>
|
||||
* <a href="#_most_often_used_changed_variables">most often used/changed variables</a>
|
||||
* <a href="#_variables_with_an_efficiency_performance_impact">variables with an efficiency/performance impact</a>
|
||||
* <a href="#_variables_with_a_security_impact">variables with a security impact</a>
|
||||
* <a href="#_less_used_changed_variables">less used/changed variables</a>
|
||||
* <a href="#_rarely_changed_variables">rarely changed variables</a>
|
||||
* <a href="#_constants_that_aren_t_">constants that aren't!</a>
|
||||
|
||||
[Note: in perl, there is no actual boolean. The undefined value, the number
|
||||
'0', and the empty string, are all 'false'. Everything else is 'true'. It is
|
||||
thus common to use just 0/1 for false/true].
|
||||
|
||||
<a name="_variables_that_should_not_be_touched_at_all"></a>
|
||||
|
||||
### variables that should not be touched at all
|
||||
|
||||
The first section does not need too much elaboration. Let's just say bad
|
||||
things happen if you change them.
|
||||
|
||||
<a name="_most_often_used_changed_variables"></a>
|
||||
|
||||
### most often used/changed variables
|
||||
|
||||
* `$GL_WILDREPOS`, boolean, default 0
|
||||
|
||||
Setting this variable lets your users create repositories based on wild
|
||||
cards, hand out R and RW permissions to other users to collaborate, etc.
|
||||
|
||||
See [doc/wildcard-repositories.mkd][wild] for lots of info on this.
|
||||
|
||||
* `$PROJECTS_LIST`, filename, default `~/projects.list`
|
||||
|
||||
This is for gitweb users only. Gitweb setup has a variable called
|
||||
`$projects_list` (please see gitweb docs for more on this). Set this to
|
||||
the same value as that one.
|
||||
|
||||
* `$REPO_UMASK`, octal, default `0077`
|
||||
|
||||
The default UMASK that gitolite uses makes all the repos and their
|
||||
contents have `rwx------` permissions. People who want to run gitweb
|
||||
realise that this will not do. The correct way to deal with this is to
|
||||
change this variable to `0027` (which gets you `rwxr-x---`), then add the
|
||||
apache or httpd user running the webserver as a member of the 'gitolite'
|
||||
group.
|
||||
|
||||
Please note the syntax; the leading 0 is required. If you change it
|
||||
*after* the install is complete, you'll have to do some chmod's also to
|
||||
adjust permissions of files and directories that have already been
|
||||
created.
|
||||
|
||||
<a name="_variables_with_an_efficiency_performance_impact"></a>
|
||||
|
||||
### variables with an efficiency/performance impact
|
||||
|
||||
* `$GL_BIG_CONFIG`, boolean, default 0
|
||||
|
||||
This is the most common setting for efficiency in handling large repo/user
|
||||
groups. This is a very powerful setting; please read
|
||||
[doc/big-config.mkd][bc] for all the details you might need.
|
||||
|
||||
There are 3 other settings related to big configs. They are changed only
|
||||
in rare cases, however, so are described later.
|
||||
|
||||
* `$GL_NO_DAEMON_NO_GITWEB`, boolean, default 0
|
||||
|
||||
If you have *lots* of repos, and you're *not* using gitweb or daemon, you
|
||||
should probably set this on for efficiency. Despite the name, it also
|
||||
blocks repo config settings. Please read [doc/big-config.mkd][bc] for
|
||||
more details.
|
||||
|
||||
* `$GL_NICE_VALUE`, boolean, default undef
|
||||
|
||||
The nice value to run under. Applicable only if it is greater than 0.
|
||||
Please do NOT set it if your bits/resource.h does not define PRIO_PROCESS
|
||||
is 0. For Linux this is true...
|
||||
|
||||
* `$BIG_INFO_CAP`, number, default 20
|
||||
|
||||
See [using patterns to limit output][limit] for details.
|
||||
|
||||
<a name="_variables_with_a_security_impact"></a>
|
||||
|
||||
### variables with a security impact
|
||||
|
||||
**IMPORTANT NOTE**
|
||||
|
||||
This section describes variables that, if not carefully used, can cause
|
||||
security issues. It also includes variables which I personally do not use and
|
||||
do not have the ability to test thoroughly
|
||||
|
||||
Using non-default value for these variables voids the security reward in the
|
||||
README. This does *not* mean they are less important or that I will ignore
|
||||
problems; it just means *my* ability to catch problems may be limited by my
|
||||
test suite, my actual production use, my time, and sometimes (LDAP comes to
|
||||
mind) even my skill or resources available to me, and that therefore I depend
|
||||
on feedback from my users to find or fix issues.
|
||||
|
||||
* `$GL_ALL_READ_ALL`, boolean, default undef
|
||||
|
||||
Eliminates the access control check for read access. Makes things much
|
||||
(**much**!) faster when you have 10,000 projects and the compiled conf
|
||||
file is more than 20MB in size! **Double check with your boss or have a
|
||||
new job lined up before setting this on!**
|
||||
|
||||
* `$GIT_PATH`, string, default empty
|
||||
|
||||
If git on your server is on a standard path (that is `ssh git@server git
|
||||
--version` works), leave this setting as is. Otherwise, find out where it
|
||||
is and use that value here, for example `GIT_PATH="/opt/bin/";`
|
||||
|
||||
* `$GL_GITCONFIG_KEYS`, string, default empty
|
||||
|
||||
This setting allows the repo admin to define acceptable gitconfig keys.
|
||||
|
||||
Gitolite allows you to set git repo options using the "config" keyword;
|
||||
see doc/gitolite.conf.mkd for details and syntax.
|
||||
|
||||
However, if you are in an installation where the repo admin does not (and
|
||||
should not) have shell access to the server, then allowing him to set
|
||||
arbitrary repo config options *may* be a security risk -- some config
|
||||
settings allow executing arbitrary commands!
|
||||
|
||||
You have 3 choices. By default `$GL_GITCONFIG_KEYS` is left empty, which
|
||||
completely disables this feature (meaning you cannot set git configs via
|
||||
the repo config).
|
||||
|
||||
The second choice is to give it a space separated list of settings you
|
||||
consider safe. (These are actually treated as a set of perl regular
|
||||
expression patterns, and any one of them must match). For example:
|
||||
`$GL_GITCONFIG_KEYS = "core\\.logAllRefUpdates core\\..*compression";`
|
||||
allows repo admins to set one of those 3 config keys (yes, that second
|
||||
pattern matches two settings from "man git-config", if you look).
|
||||
|
||||
The third choice (which you may have guessed already if you're familiar
|
||||
with regular expressions) is to allow anything and everything:
|
||||
`$GL_GITCONFIG_KEYS = ".*";`
|
||||
|
||||
NOTE that due to some quoting and interpolation issues I have not been
|
||||
able to look at, a literal "." needs to be specified in this string as
|
||||
`\\.` (two backslashes and a dot). So this is how you'd allow any keys in
|
||||
the "foo" category: `$GL_GITCONFIG_KEYS = "foo\\..*";`
|
||||
|
||||
* `$GL_GITCONFIG_WILD`, boolean, default 0
|
||||
|
||||
This setting allows gitconfig keys even for wild repos. This is an
|
||||
efficiency issue more than a security issue, since this requires trawling
|
||||
through all of `$REPO_BASE` looking for stuff :)
|
||||
|
||||
* `$GL_NO_CREATE_REPOS`, boolean, default 0
|
||||
|
||||
DO NOT CHANGE THIS unless you have other means to create repos and
|
||||
correctly populate them with the required hooks. No hooks, no access
|
||||
control; you have been warned!
|
||||
|
||||
* `$GL_NO_SETUP_AUTHKEYS`, boolean, default 0
|
||||
|
||||
DO NOT CHANGE THIS unless you have other means to setup the authkeys file
|
||||
(`~/.ssh/authorized_keys`). In an extreme case, if you switch this on
|
||||
without also fixing up the authkeys file, users who you think you deleted
|
||||
may still have access. All in all, please be careful, as with any change
|
||||
that affects ssh.
|
||||
|
||||
* `$GL_WILDREPOS_DEFPERMS`, string, default undef
|
||||
|
||||
This sets default wildcard permissions for newly created wildcard repos.
|
||||
|
||||
If set, this value will be used as the default user-level permission rule
|
||||
of new wildcard repositories. The user can change this value with the
|
||||
setperms command as desired after repository creation; it is only a
|
||||
default.
|
||||
|
||||
Example: `$GL_WILDREPOS_DEFPERMS = 'R @all';`
|
||||
|
||||
* `$HTPASSWD_FILE`, string, default empty
|
||||
|
||||
Gitolite can help users run the htpasswd command in a secure manner (since
|
||||
gitolite has already identified them by an ssh key). If you want to
|
||||
enable this, give the variable the absolute path to whatever file apache
|
||||
(etc) expect to find the passwords in.
|
||||
|
||||
Look in [doc/3-faq-tips-etc.mkd][faq] ("easier to link gitweb
|
||||
authorisation with gitolite" section) for more details on using this
|
||||
feature.
|
||||
|
||||
* `$RSYNC_BASE`, string, default empty
|
||||
|
||||
Gitolite can be used to allow fine grained control of the rsync command.
|
||||
|
||||
This setting enables the rsync external command helper, by specifying the
|
||||
base path of all the files that are accessible via rsync. It must be an
|
||||
absolute path, like `$RSYNC_BASE = "/home/git/up-down";`. Leave it
|
||||
undefined or set to the empty string to disable the rsync helper.
|
||||
|
||||
When enabled, it runs rsync with specific arguments, all presumably filled
|
||||
in correctly by the client-side rsync. However, I am not an expert on how
|
||||
rsync may be abused, so if it breaks, you get to keep both pieces!
|
||||
|
||||
* `$SVNSERVE`, string, default empty
|
||||
|
||||
Gitolite can also be used to gate access (though not at a fine grained
|
||||
level) to SVN if needed, passing authentication information on to
|
||||
`svnserve`. This setting allows launching svnserve when requested by the
|
||||
ssh client. This allows using the same SSH setup for both SVN and git
|
||||
access. Leave it undefined or set to the empty string to disable svnserve
|
||||
access.
|
||||
|
||||
The setting will look something like (where the %u is substituted with the
|
||||
username):
|
||||
|
||||
$SVNSERVE = "/usr/bin/svnserve -r /var/svn/ -t --tunnel-user=%u";
|
||||
|
||||
* hook chaining
|
||||
|
||||
* `$UPDATE_CHAINS_TO`, string, default "hooks/update.secondary"
|
||||
* `$ADMIN_POST_UPDATE_CHAINS_TO`, string, default
|
||||
"hooks/post-update.secondary"
|
||||
|
||||
By default, the update hook in every repo chains to "update.secondary".
|
||||
Similarly, the post-update hook in the admin repo chains to
|
||||
"post-update.secondary". If you're fine with the defaults, there's no
|
||||
need to do anything here. However, if you want to use different names or
|
||||
paths, change these variables.
|
||||
|
||||
* `$GL_ADC_PATH`, string, default undef
|
||||
|
||||
This setting enables admin defined commands.
|
||||
|
||||
**WARNING**: Use this feature only if (a) you really know what you're
|
||||
doing and (b) you really, **really**, know what you're doing! Please read
|
||||
[doc/admin-defined-commands.mkd][adc] for details. This is an extremely
|
||||
powerful and flexible feature, and naturally anything that flexible can be
|
||||
a security risk!
|
||||
|
||||
* `$GL_GET_MEMBERSHIPS_PGM`, string, default undef
|
||||
|
||||
Some sites would like to store group membership outside gitolite, because
|
||||
they already have it in (usually) their LDAP server, and it doesn't make
|
||||
sense to be forced to duplicate this information.
|
||||
|
||||
Set the following variable to the name of a script that, given a username
|
||||
as argument, will return a list of groups that she is a member of. See
|
||||
[doc/big-config.mkd][bc] for more details.
|
||||
|
||||
Example: `$GL_GET_MEMBERSHIPS_PGM = "/usr/local/bin/expand-ldap-user-to-groups"`
|
||||
|
||||
* `$GL_HTTP_ANON_USER`, string, default undef
|
||||
|
||||
Analogous to running mob branches over ssh (as described in
|
||||
[doc/mob-branches.mkd][mob], this variable -- combined with appropriate
|
||||
setup described in [doc/http-backend.mkd][smart] -- lets you pretend to
|
||||
gitolite that unauthenticated HTTP users are actually authenticated as
|
||||
this user.
|
||||
|
||||
<a name="_less_used_changed_variables"></a>
|
||||
|
||||
### less used/changed variables
|
||||
|
||||
* `$GL_ALL_INCLUDES_SPECIAL`, boolean, default undef
|
||||
|
||||
Giving access to @all users (as in `R = @all`) in the config normally
|
||||
does *not* include the special users "gitweb" and "daemon". If you want
|
||||
@all to include these two users, set this variable.
|
||||
|
||||
* mirroring setup
|
||||
|
||||
These two variables enable mirroring support; see
|
||||
[doc/mirroring.mkd][mirr] for details. The two variables are
|
||||
`$GL_SLAVE_MODE`, (boolean, default undef), and `$ENV{GL_SLAVES}`,
|
||||
(environment variable, string, default undef)
|
||||
|
||||
Note on the second variable above: you must use single quotes to give it
|
||||
its value, not double quotes, (like `$ENV{GL_SLAVES} = 'gitolite@server2
|
||||
gitolite@server3';`). Also note that this is an environment variable, not
|
||||
a regular perl variable, so mind the syntax if you're not a perl guy :-)
|
||||
|
||||
* `$GL_WILDREPOS_PERM_CATS`, string, default "READERS WRITERS"
|
||||
|
||||
Originally, we only allowed "R" and "RW" in the setperms command. Now we
|
||||
allow the admin to define other categories as she wishes (example:
|
||||
MANAGERS, TESTERS, etc).
|
||||
|
||||
This variable is a space-separated list of the allowed categories.
|
||||
|
||||
PLEASE, *PLEASE*, read the section in
|
||||
[doc/wildcard-repositories.mkd][wild] for caveats and warnings. This is a
|
||||
VERY powerful feature and if you're not careful you could mess up the ACLs
|
||||
nicely.
|
||||
|
||||
This is the internal default if you don't set it (like if you didn't
|
||||
update your ~/.gitolite.rc with new variables when you upgraded gitolite):
|
||||
|
||||
$GL_WILDREPOS_PERM_CATS = "READERS WRITERS";
|
||||
|
||||
You can use your own categories in addition to the standard ones; I
|
||||
suggest you include READERS and WRITERS for backward compatbility though:
|
||||
|
||||
$GL_WILDREPOS_PERM_CATS = "READERS WRITERS MANAGERS TESTERS";
|
||||
|
||||
<a name="_rarely_changed_variables"></a>
|
||||
|
||||
### rarely changed variables
|
||||
|
||||
* `$GL_LOGT`, string, default `$GL_ADMINDIR/logs/gitolite-%y-%m.log`
|
||||
|
||||
This is the template for location of the log files and format of their
|
||||
names.
|
||||
|
||||
The default produces files like `~/.gitolite/logs/gitolite-2009-09.log`.
|
||||
If you make up your own templates, **PLEASE MAKE SURE** the directory
|
||||
exists and is writable; gitolite won't do that for you unless it is the
|
||||
default, ("$GL_ADMINDIR/logs")
|
||||
|
||||
* `$GL_PERFLOGT`, string, default undef
|
||||
|
||||
This gives the location of the performance log files. Uncomment and set
|
||||
this variable if you want performance logging. Performance log files are
|
||||
kept separate from access log files because they store different, usually
|
||||
much shorter term, information.
|
||||
|
||||
* `$GL_SITE_INFO`, string, default undef
|
||||
|
||||
Some installations would like to give their users customised information
|
||||
(like a link to their own websites, for example) so that users have a
|
||||
quick way to find some links or information.
|
||||
|
||||
If this variable is defined, the "info" command will print it at the end
|
||||
of the listing.
|
||||
|
||||
* `$REPO_BASE`, string, default "repositories"
|
||||
|
||||
This is where all the repos go. If it's not an absolute path, it is
|
||||
considered to be relative to $HOME. Moving all the repositories after the
|
||||
install has completed is doable: just [disable writes][dwr] to gitolite,
|
||||
move `~/repositories/*`, change this variable, then re-enable writes.
|
||||
|
||||
<a name="_constants_that_aren_t_"></a>
|
||||
|
||||
### constants that aren't!
|
||||
|
||||
The source file `src/gitolite_rc.pm` defines a few "constants", for example:
|
||||
|
||||
$R_COMMANDS=qr/^(git[ -]upload-pack|git[ -]upload-archive)$/;
|
||||
|
||||
Let's say you want to disallow the archive feature, you would need to change
|
||||
this constant.
|
||||
|
||||
As of this version, you can now change these "constants" also, simply by
|
||||
defining a new value for any or all of them in your `~/.gitolite.rc` file.
|
||||
|
||||
If you use this to relax some of the patterns involved (for example, the value
|
||||
of `ADC_CMD_ARGS_PATT`), please be sure you know what you're doing.
|
||||
|
||||
[wild]: http://sitaramc.github.com/gitolite/doc/wildcard-repositories.html
|
||||
[bc]: http://sitaramc.github.com/gitolite/doc/big-config.html
|
||||
[faq]: http://sitaramc.github.com/gitolite/doc/3-faq-tips-etc.html
|
||||
[adc]: http://sitaramc.github.com/gitolite/doc/admin-defined-commands.html
|
||||
[mirr]: http://sitaramc.github.com/gitolite/doc/mirroring.html
|
||||
[mob]: http://sitaramc.github.com/gitolite/doc/mob-branches.html
|
||||
[smart]: http://sitaramc.github.com/gitolite/doc/http-backend.html
|
||||
[dwr]: http://sitaramc.github.com/gitolite/doc/3-faq-tips-etc.html#_disabling_write_access_to_take_backups
|
||||
[limit]: http://sitaramc.github.com/gitolite/doc/report-output.html#_using_patterns_to_limit_output
|
|
@ -1,175 +0,0 @@
|
|||
## hook propagation in gitolite
|
||||
|
||||
Advanced users need to know how hooks propagate, and when. They also need to
|
||||
know where to place their hooks, and since there appear to be two places to
|
||||
put them, what takes precedence. I'll try and set out the logic here.
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_hooks_used_by_gitolite">hooks used by gitolite</a>
|
||||
* <a href="#_where_do_I_the_admin_put_the_hooks_">**where** do I (the admin) put the hooks?</a>
|
||||
* <a href="#_the_from_client_method">the "from-client" method</a>
|
||||
* <a href="#_the_other_3_methods">the other 3 methods</a>
|
||||
* <a href="#_the_GL_PACKAGE_HOOKS_directory">the `GL_PACKAGE_HOOKS` directory</a>
|
||||
* <a href="#_the_HOME_gitolite_directory">the `$HOME/.gitolite` directory</a>
|
||||
* <a href="#_why_two_places_">why two places?</a>
|
||||
* <a href="#_special_case_the_non_root_method">special case: the "non-root" method</a>
|
||||
* <a href="#_when_do_hooks_propagate_">**when** do hooks propagate?</a>
|
||||
|
||||
<a name="_hooks_used_by_gitolite"></a>
|
||||
|
||||
### hooks used by gitolite
|
||||
|
||||
Gitolite uses only 2 hooks. **All** repos have an `update` hook, without
|
||||
which there is no write-level access control (per-branch permissions). The
|
||||
special **gitolite-admin** repo has a special `post-update` hook, which is
|
||||
required to do its, umm, special things, like running the "compile" script,
|
||||
etc.
|
||||
|
||||
In addition there is a "sentinel file" -- an empty file called
|
||||
"gitolite-hooked". We'll see later what this does.
|
||||
|
||||
The final objective of all this is that each repo's `hooks/` directory should
|
||||
get all the hooks that it is meant to get.
|
||||
|
||||
<a name="_where_do_I_the_admin_put_the_hooks_"></a>
|
||||
|
||||
### **where** do I (the admin) put the hooks?
|
||||
|
||||
In general, **all** hooks go into the `hooks/common` directory. Only the
|
||||
special `post-update` hook meant for the admin repo goes into
|
||||
`hooks/gitolite-admin`.
|
||||
|
||||
Now we'll discuss the locations of these `hooks/common` and
|
||||
`hooks/gitolite-admin` directories. This depends on which install method you
|
||||
used.
|
||||
|
||||
(Please refer to [doc/1-INSTALL.mkd][0inst] for what these "methods" are).
|
||||
|
||||
<a name="_the_from_client_method"></a>
|
||||
|
||||
#### the "from-client" method
|
||||
|
||||
Let's get this out of the way first, because it is simple: if you're using the
|
||||
"from-client" method, there's only one place: the `hooks` directory in your
|
||||
gitolite clone on the client side. This is where you run
|
||||
`src/gl-easy-install` from. Nothing else in this section is relevant to this
|
||||
method; skip to the next section ("when do hooks propagate") if you installed
|
||||
using the "from-client" method.
|
||||
|
||||
<a name="_the_other_3_methods"></a>
|
||||
|
||||
#### the other 3 methods
|
||||
|
||||
<a name="_the_GL_PACKAGE_HOOKS_directory"></a>
|
||||
|
||||
##### the `GL_PACKAGE_HOOKS` directory
|
||||
|
||||
You might recall that the "root", and "non-root" methods run a command called
|
||||
`gl-system-install`, the third argument of which is some directory of your
|
||||
choice (like maybe `/usr/share/gitolite/hooks`). Even though it is not
|
||||
necessary to know this, internally this becomes the value of the
|
||||
`$GL_PACKAGE_HOOKS` variable, so in this document we will refer to that
|
||||
variable instead of the location (because you might choose any location you
|
||||
like for it).
|
||||
|
||||
The "package" method also has the same property, except that the packager has
|
||||
already decided what that location is, and the package creation/install
|
||||
process does the equivalent of `gl-system-install`.
|
||||
|
||||
So now we know there's a location called `$GL_PACKAGE_HOOKS` where you can
|
||||
place your hooks.
|
||||
|
||||
<a name="_the_HOME_gitolite_directory"></a>
|
||||
|
||||
##### the `$HOME/.gitolite` directory
|
||||
|
||||
You might also recall that, in these three methods, each **hosting user** has
|
||||
to run `gl-setup`. This sets up, among other things, `$HOME/.gitolite`
|
||||
directory, which also contains a `hooks/` directory.
|
||||
|
||||
So now there are two places you can put your hooks, apparently.
|
||||
|
||||
<a name="_why_two_places_"></a>
|
||||
|
||||
#### why two places?
|
||||
|
||||
Just think of the "package" and "root" methods for now, even if you're using
|
||||
the "non-root" method.
|
||||
|
||||
In these two methods, it is reasonable to assume that the entire site (or
|
||||
server) has certain policies that they want to implement using hooks. They
|
||||
want to enforce these hooks on *each hosting user*. These hooks go into
|
||||
`$GL_PACKAGE_HOOKS`.
|
||||
|
||||
Each hosting user then has the discretion to add his own hooks (modulo name
|
||||
clashes, which may necessitate hook chaining, etc., like we already do for the
|
||||
hooks that gitolite cares about). He adds these hooks to his
|
||||
`$HOME/.gitolite/hooks` directory.
|
||||
|
||||
When hooks propagate, the ones in `$GL_PACKAGE_HOOKS` override/overwrite the
|
||||
ones in `$HOME/.gitolite/hooks`. Otherwise it wouldn't make sense; you
|
||||
wouldn't be able to enforce site-wide hooks.
|
||||
|
||||
[NOTE: due to a minor quirk, the site-wide hooks in `$GL_PACKAGE_HOOKS` also
|
||||
get copied to `$HOME/.gitolite/hooks` when you "install". I need to fix and
|
||||
thoroughly test this later; for now, just ignore the extra files you see in
|
||||
there; they're harmless/redundant (TODO)]
|
||||
|
||||
<a name="_special_case_the_non_root_method"></a>
|
||||
|
||||
#### special case: the "non-root" method
|
||||
|
||||
This method was created later, just piggy-backing on everything that already
|
||||
existed to cater to the "package" and "root" methods. In this method, the
|
||||
`$GL_PACKAGE_HOOKS` is as accessible or under your control as
|
||||
`$HOME/.gitolite`, so it doesn't matter where you put your hooks. I
|
||||
*strongly* suggest putting them in `$GL_PACKAGE_HOOKS` and ignoring
|
||||
`$HOME/.gitolite` completely.
|
||||
|
||||
<a name="_when_do_hooks_propagate_"></a>
|
||||
|
||||
### **when** do hooks propagate?
|
||||
|
||||
First: realise that gitolite *wants to make sure* that all the hooks in your
|
||||
`hooks/common` directory get copied (symlinked, actually) to *every* repo that
|
||||
gets created. **Not doing so is generally a security risk; because the
|
||||
primary purpose of gitolite is access control, people generally *want* hooks
|
||||
to run.**
|
||||
|
||||
Here's how/when hooks are created/propagated:
|
||||
|
||||
1. anytime you do an install, gitolite trawls through *all* existing repos
|
||||
(using the unix `find` command) and force-links all the hooks in all the
|
||||
repos so they all get the latest and greatest hooks.
|
||||
|
||||
2. anytime you do a "compile" (meaning push changes to the admin repo),
|
||||
gitolite looks through all the repos named in the config. It first checks
|
||||
if the repo exists, creating it if needed. It then looks for a sentinel
|
||||
file called "gitolite-hooked" (an empty file in the hooks directory). If
|
||||
it doesn't find it, it will assume that hooks need to be propagated.
|
||||
|
||||
This is because people often copy a repo from elsewhere, add it to the
|
||||
config, and expect things to work. Without this step, those repos don't
|
||||
get the hooks, which is bad -- the access control would have failed
|
||||
silently!
|
||||
|
||||
3. anytime a new repo is created, the same force-linking of hooks happens.
|
||||
The 3 places a new repo is created are:
|
||||
|
||||
* the "compile" case mentioned above, where the admin added a normal
|
||||
repo to the config and pushed
|
||||
|
||||
* the wildrepos case, where you have "C" permissions and the repo does
|
||||
not already exist
|
||||
|
||||
* the `fork` command in `contrib/adc`. In this case the hooks are
|
||||
explicitly copied from the source repo using the `cp` command, not
|
||||
using the code internal to gitolite.
|
||||
|
||||
For people who do not want certain hooks to run for certain repos, one simple
|
||||
solution that will work right now is to check the value of `$GL_REPO` at the
|
||||
start of the hook, and `exit 0` based on what it contains/matches.
|
||||
|
||||
[0inst]: http://sitaramc.github.com/gitolite/doc/1-INSTALL.html
|
||||
|
|
@ -1,221 +0,0 @@
|
|||
# how to setup gitolite to use smart http mode
|
||||
|
||||
**Note**: "smart http" refers to the feature that came with git 1.6.6, late
|
||||
2009 or so. The base documentation for this is `man git-http-backend`. Do
|
||||
**NOT** read `Documentation/howto/setup-git-server-over-http.txt` and think
|
||||
that is the same or even relevant -- that is from 2006 and is quite different
|
||||
(and arguably obsolete).
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_WARNINGS_plus_stuff_I_need_help_with">WARNINGS, plus stuff I need help with</a>
|
||||
* <a href="#_additional_requirements">additional requirements</a>
|
||||
* <a href="#_detailed_instructions">detailed instructions</a>
|
||||
* <a href="#_install_gitolite_under_apache_">install gitolite under "apache"</a>
|
||||
* <a href="#_setup_apache">setup apache</a>
|
||||
* <a href="#_usage">usage</a>
|
||||
* <a href="#_allowing_anonymous_access">allowing anonymous access</a>
|
||||
* <a href="#_ssh_http_access_and_the_GIT_HTTP_EXPORT_ALL_variable">ssh + http access and the `GIT_HTTP_EXPORT_ALL` variable</a>
|
||||
|
||||
----
|
||||
|
||||
<a name="_WARNINGS_plus_stuff_I_need_help_with"></a>
|
||||
|
||||
### WARNINGS, plus stuff I need help with
|
||||
|
||||
* I have NOT converted the test suite to use this mode. Volunteers to
|
||||
convert it to http access are welcome :-)
|
||||
|
||||
* I have no idea how to handle the password issue other than creating a
|
||||
`~/.netrc` file and making it `chmod 600`. Anyway, http based access is
|
||||
inherently less secure than pubkeys so not much point worrying about it.
|
||||
|
||||
* I have not tested any of the ancillary standalone programs (like
|
||||
gl-dont-panic) in this mode. They're most likely going to crash and burn
|
||||
because `$HOME` is not defined or in the wrong place; manually set
|
||||
`HOME=$GITOLITE_HTTP_HOME` and hope for the best. Luckily most of them
|
||||
have to do with sshkeys so this may not matter. YMMV.
|
||||
|
||||
* tested on stock Fedora 14; if you test on other environments please let me
|
||||
know how it worked out and if we need to adjust this document
|
||||
|
||||
* tested https with dummy certs and `GIT_SSL_NO_VERIFY`; no reason why it
|
||||
shouldn't work on a proper setup with everything in place
|
||||
|
||||
* have not tried making repos available to both ssh *and* http mode clients;
|
||||
(I'd guess it ought to work fine if the "apache" user was made login-able
|
||||
and given a proper $HOME and `~/.ssh/authorized_keys` and all that). If
|
||||
anyone has the energy to try that please let me know how that went.
|
||||
|
||||
<a name="_additional_requirements"></a>
|
||||
|
||||
### additional requirements
|
||||
|
||||
* requires `GIT_PROJECT_ROOT` (see "man git-http-backend" for what this is)
|
||||
set explicitly (i.e., it is no longer optional). Please set it to some
|
||||
place outside apache's `DOCUMENT_ROOT`.
|
||||
|
||||
<a name="_detailed_instructions"></a>
|
||||
|
||||
### detailed instructions
|
||||
|
||||
I assume you've installed apache 2.x and git on the server.
|
||||
|
||||
I assume your httpd runs under the "apache" userid; adjust instructions below
|
||||
if it does not. Similarly for "/var/www" and other file names/locations.
|
||||
|
||||
<a name="_install_gitolite_under_apache_"></a>
|
||||
|
||||
#### install gitolite under "apache"
|
||||
|
||||
Follow the "non-root" method, but since you can't even "su - apache", make the
|
||||
following variations when doing this as root:
|
||||
|
||||
* `cd ~apache` first; this is `/var/www` on Fedora 14
|
||||
|
||||
* do this in the shell
|
||||
|
||||
mkdir gitolite-home
|
||||
export GITOLITE_HTTP_HOME
|
||||
GITOLITE_HTTP_HOME=/var/www/gitolite-home
|
||||
PATH=$PATH:$GITOLITE_HTTP_HOME/bin
|
||||
|
||||
* now run the following commands. These are really the first 3 steps of the
|
||||
"non-root" install (clone, mkdir, and gl-system-install), **except** you
|
||||
substitute `GITOLITE_HTTP_HOME` in place of `HOME`. Note that you do NOT
|
||||
run the gl-setup step yet.
|
||||
|
||||
cd gitolite-home
|
||||
git clone /tmp/gitolite.git gitolite-source
|
||||
# or wherever your local clone is, or directly from git://github.com/sitaramc/gitolite
|
||||
|
||||
cd gitolite-source
|
||||
GHH=$GITOLITE_HTTP_HOME # just for convenience in next 2 commands
|
||||
mkdir -p $GHH/bin $GHH/share/gitolite/conf $GHH/share/gitolite/hooks
|
||||
src/gl-system-install $GHH/bin $GHH/share/gitolite/conf $GHH/share/gitolite/hooks
|
||||
|
||||
* after the gl-system-install step, add these to the **top** of
|
||||
/var/www/gitolite-home/share/gitolite/conf/example.gitolite.rc
|
||||
|
||||
$ENV{GIT_HTTP_BACKEND} = "/usr/libexec/git-core/git-http-backend";
|
||||
# or wherever you have that file; note: NO trailing slash
|
||||
$ENV{PATH} .= ":$ENV{GITOLITE_HTTP_HOME}/bin";
|
||||
# note the ".=" here, not "="
|
||||
|
||||
* run gl-setup with the name of your admin user
|
||||
|
||||
gl-setup sitaram
|
||||
|
||||
* IMPORTANT: fix up ownerships
|
||||
|
||||
chown -R apache.apache $GITOLITE_HTTP_HOME
|
||||
|
||||
<a name="_setup_apache"></a>
|
||||
|
||||
#### setup apache
|
||||
|
||||
You will need to setup certain values in the httpd conf, as given in `man
|
||||
git-http-backend`. You can put all them into, for instance,
|
||||
`/etc/httpd/conf.d/gitolite.conf` and apache [at least on Fedora 14] will pick
|
||||
it up. These are the values to use; note that these are somewhat different
|
||||
from those in the manpage cited above, plus we have one extra variable:
|
||||
|
||||
SetEnv GIT_PROJECT_ROOT /var/www/gitolite-home/repositories
|
||||
SetEnv GIT_HTTP_EXPORT_ALL
|
||||
# please see notes below on ssh+http access
|
||||
ScriptAlias /git/ /var/www/gitolite-home/bin/gl-auth-command/
|
||||
# note trailing slash
|
||||
|
||||
SetEnv GITOLITE_HTTP_HOME /var/www/gitolite-home
|
||||
|
||||
<Location /git>
|
||||
AuthType Basic
|
||||
AuthName "Private Git Access"
|
||||
Require valid-user
|
||||
AuthUserFile /path/to/some/passwdfile
|
||||
</Location>
|
||||
|
||||
Now create/update the password file in `/path/to/some/passwdfile` using the
|
||||
`htpasswd` command, and you're all done for the setup!
|
||||
|
||||
<a name="_usage"></a>
|
||||
|
||||
### usage
|
||||
|
||||
Git URLs look like `http://user:password@server/git/reponame.git`.
|
||||
|
||||
The custom commands, like "info", "expand" should be handled as follows. The
|
||||
command name will come just after the `/git/`, followed by a `?`, followed by
|
||||
the arguments, with `+` representing a space. Here are some examples:
|
||||
|
||||
# ssh git@server info
|
||||
curl http://user:password@server/git/info
|
||||
# ssh git@server info repopatt
|
||||
curl http://user:password@server/git/info?repopatt
|
||||
# ssh git@server info repopatt user1 user2
|
||||
curl http://user:password@server/git/info?repopatt+user1+user2
|
||||
|
||||
It gets even more interesting for the `setperms` command, which expects STDIN.
|
||||
I didn't want to get too much into the code here, so I found that the
|
||||
following works and I'm leaving it at that:
|
||||
|
||||
(echo R user1 user2; echo RW user3 user4) |
|
||||
curl --data-binary @- http://user:password@server/git/setperms?reponame.git
|
||||
|
||||
With a few nice shell aliases, you won't even notice the horrible convolutions
|
||||
here ;-)
|
||||
|
||||
<a name="_allowing_anonymous_access"></a>
|
||||
|
||||
### allowing anonymous access
|
||||
|
||||
Like [mob branches][mob] with ssh, you can allow completely
|
||||
**un**-authenticated users to still have some rights specified in gitolite.
|
||||
Briefly, here's how:
|
||||
|
||||
* specify a ScriptAlias in apache config for unauthenticated access also. I
|
||||
prefer something like
|
||||
|
||||
ScriptAlias /gitmob/ /var/www/gitolite-home/bin/gl-auth-command/
|
||||
|
||||
* set `$GL_HTTP_ANON_USER` to some name, like 'mob' or 'anon' in the rc file
|
||||
|
||||
* give rights to this user ('mob' or 'anon' or whatever you used) in the
|
||||
gitolite config file and push the change
|
||||
|
||||
URLs (in this example) will then look like `http://server/gitmob/reponame.git`
|
||||
-- we lose the userid:passwd part and change 'git' to 'gitmob'.
|
||||
|
||||
<a name="_ssh_http_access_and_the_GIT_HTTP_EXPORT_ALL_variable"></a>
|
||||
|
||||
### ssh + http access and the `GIT_HTTP_EXPORT_ALL` variable
|
||||
|
||||
This document only talks about setting up access to a set of git repositories
|
||||
purely via smart http. The `GIT_HTTP_EXPORT_ALL` variable must be set for
|
||||
such environments.
|
||||
|
||||
However, it is possible to allow both ssh as well as http access, perhaps
|
||||
using suexec to make the CGI run under the 'git' user [detailed documentation
|
||||
patches welcome!] For those environments, this variable is not mandatory.
|
||||
|
||||
If you omit that variable, you can decide which repo is accessible via http by
|
||||
setting `R = daemon` just for those repos.
|
||||
|
||||
Please note that there is no way to use "deny" rules for *read* access. Do
|
||||
not try:
|
||||
|
||||
repo gitolite-admin
|
||||
- = daemon
|
||||
|
||||
repo @all
|
||||
R = daemon
|
||||
|
||||
to achieve the (possibly common) need for disallowing http access to the admin
|
||||
repo.
|
||||
|
||||
----
|
||||
|
||||
Enjoy!
|
||||
|
||||
[mob]: http://sitaramc.github.com/gitolite/doc/mob-branches.html
|
||||
|
|
@ -1,279 +0,0 @@
|
|||
# gitolite install transcript
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_about_this_document">about this document</a>
|
||||
* <a href="#_create_userids_on_server_and_client_optional_">create userids on server and client (optional)</a>
|
||||
* <a href="#_get_pubkey_access_from_client_to_server">get pubkey access from client to server</a>
|
||||
* <a href="#_get_gitolite_source">get gitolite source</a>
|
||||
* <a href="#_install_gitolite">install gitolite</a>
|
||||
* <a href="#_VERY_IMPORTANT_">VERY IMPORTANT...</a>
|
||||
* <a href="#_examine_what_you_have">examine what you have</a>
|
||||
* <a href="#_emergency_password_access">emergency password access</a>
|
||||
|
||||
----
|
||||
|
||||
<a name="_about_this_document"></a>
|
||||
|
||||
### about this document
|
||||
|
||||
This is a *complete* transcript of a full gitolite install, *from scratch*,
|
||||
using brand new userids ("sita" on the client, "git" on the server). Please
|
||||
note that you can use existing userids also, it is not necessary to use
|
||||
dedicated user IDs for this. In particular, people who have a single user
|
||||
hosting account can also use this method, as long as they have password access
|
||||
as a fallback if they screw up the keys somewhere. Also, you don't have to
|
||||
use some *other* server for all this, both server and client can be
|
||||
"localhost" if you like.
|
||||
|
||||
Please note that this entire transcript can be summarised as:
|
||||
|
||||
* create users on client and server (optional)
|
||||
* get pubkey access to server from client (`ssh-copy-id` or manual eqvt)
|
||||
* run one command ***on client*** (`gl-easy-install`)
|
||||
|
||||
...and only that last step is actually gitolite. In fact, the bulk of the
|
||||
transcript is **non**-gitolite stuff :)
|
||||
|
||||
**Please also note that this method will setup everything on the server, but
|
||||
you have to run it on your workstation, NOT on the server!**
|
||||
|
||||
----
|
||||
|
||||
<a name="_create_userids_on_server_and_client_optional_"></a>
|
||||
|
||||
### create userids on server and client (optional)
|
||||
|
||||
Client side: add user, give him a password
|
||||
|
||||
sita-lt:~ # useradd sita
|
||||
|
||||
sita-lt:~ # passwd sita
|
||||
Changing password for user sita.
|
||||
New UNIX password:
|
||||
Retype new UNIX password:
|
||||
passwd: all authentication tokens updated successfully.
|
||||
|
||||
Server side: (log on to server, then) add user, give it a password
|
||||
|
||||
sita-lt:~ # ssh sitaram@server
|
||||
sitaram@server's password:
|
||||
Last login: Fri Dec 18 20:25:06 2009
|
||||
-bash-3.2$ su -
|
||||
Password:
|
||||
|
||||
sita-sv:~ # useradd git
|
||||
|
||||
sita-sv:~ # passwd git
|
||||
Changing password for user git.
|
||||
New UNIX password:
|
||||
Retype new UNIX password:
|
||||
passwd: all authentication tokens updated successfully.
|
||||
|
||||
Server side: allow ssh access to "git" user
|
||||
|
||||
This is done by editing the sshd config file and adding "git" to the
|
||||
"AllowUsers" list (the grep command is just confirming the change we made,
|
||||
because I'm not showing the actual "vi" session):
|
||||
|
||||
sita-sv:~ # vim /etc/ssh/sshd_config
|
||||
|
||||
sita-sv:~ # grep -i allowusers /etc/ssh/sshd_config
|
||||
AllowUsers sitaram git
|
||||
|
||||
sita-sv:~ # service sshd restart
|
||||
Stopping sshd: [ OK ]
|
||||
Starting sshd: [ OK ]
|
||||
|
||||
**NOTE**: if the `AllowUsers` setting is completely missing from the sshd
|
||||
config file, all users are allowed (see `man sshd_config`). You may prefer to
|
||||
leave it that way -- your choice. I prefer to make the usernames explicit
|
||||
because I'm paranoid ;-)
|
||||
|
||||
----
|
||||
|
||||
<a name="_get_pubkey_access_from_client_to_server"></a>
|
||||
|
||||
### get pubkey access from client to server
|
||||
|
||||
This involves creating a keypair for yourself (using `ssh-keygen`), and
|
||||
copying the public part of that keypair to the `~/.ssh/authorized_keys` file
|
||||
on the server (using `ssh-copy-id`, if you're on Linux, or the manual method
|
||||
described in the `ssh-copy-id` section in `doc/3-faq-tips-etc.mkd`).
|
||||
|
||||
sita-lt:~ $ su - sita
|
||||
Password:
|
||||
|
||||
sita@sita-lt:~ $ ssh-keygen
|
||||
Generating public/private rsa key pair.
|
||||
Enter file in which to save the key (/home/sita/.ssh/id_rsa):
|
||||
Created directory '/home/sita/.ssh'.
|
||||
Enter passphrase (empty for no passphrase):
|
||||
Enter same passphrase again:
|
||||
Your identification has been saved in /home/sita/.ssh/id_rsa.
|
||||
Your public key has been saved in /home/sita/.ssh/id_rsa.pub.
|
||||
The key fingerprint is:
|
||||
8a:e0:60:1b:04:58:68:50:a4:d7:d0:3a:a5:2d:bf:0a sita@sita-lt.atc.tcs.com
|
||||
The key's randomart image is:
|
||||
+--[ RSA 2048]----+
|
||||
|===. |
|
||||
|+o oo |
|
||||
|o..=. |
|
||||
|..= . |
|
||||
|.o.+ S |
|
||||
|.oo... . |
|
||||
|E.. ... |
|
||||
| . . |
|
||||
| .. |
|
||||
+-----------------+
|
||||
|
||||
sita@sita-lt:~ $ ssh-copy-id -i ~/.ssh/id_rsa.pub git@server
|
||||
git@server's password:
|
||||
/usr/bin/xauth: creating new authority file /home/git/.Xauthority
|
||||
Now try logging into the machine, with "ssh 'git@server'", and check in:
|
||||
|
||||
.ssh/authorized_keys
|
||||
|
||||
to make sure we haven't added extra keys that you weren't expecting.
|
||||
|
||||
Double check to make sure you can log on to `git@server` without a password:
|
||||
|
||||
sita@sita-lt:~ $ ssh git@server pwd
|
||||
/home/git
|
||||
|
||||
**DO NOT PROCEED UNTIL THIS WORKS OK!**
|
||||
|
||||
----
|
||||
|
||||
<a name="_get_gitolite_source"></a>
|
||||
|
||||
### get gitolite source
|
||||
|
||||
sita@sita-lt:~ $ git clone git://github.com/sitaramc/gitolite gitolite-source
|
||||
Initialized empty Git repository in /home/sita/gitolite-source/.git/
|
||||
remote: Counting objects: 1157, done.
|
||||
remote: Compressing objects: 100% (584/584), done.
|
||||
remote: Total 1157 (delta 756), reused 912 (delta 562)
|
||||
Receiving objects: 100% (1157/1157), 270.08 KiB | 61 KiB/s, done.
|
||||
Resolving deltas: 100% (756/756), done.
|
||||
|
||||
<a name="_install_gitolite"></a>
|
||||
|
||||
### install gitolite
|
||||
|
||||
Note that gitolite is installed from the *client*. The `easy-install` script
|
||||
runs on the client but installs gitolite on the server!
|
||||
|
||||
sita@sita-lt:~ $ cd gitolite-source/src
|
||||
|
||||
<font color="red"> **This is the only gitolite specific command in a typical
|
||||
install sequence**. </font> Run it without any arguments to see a usage
|
||||
message. Run it without the `-q` to get a more verbose, pause-at-every-step,
|
||||
install mode that allows you to change the defaults (for example, if you want
|
||||
a different UMASK setting, or you want the repos to be in a different place,
|
||||
etc.)
|
||||
|
||||
sita@sita-lt:src $ ./gl-easy-install -q git server sitaram
|
||||
you are upgrading (or installing first-time) to v0.95-38-gb0ce84d
|
||||
setting up keypair...
|
||||
Generating public/private rsa key pair.
|
||||
Enter passphrase (empty for no passphrase):
|
||||
Enter same passphrase again:
|
||||
Your identification has been saved in /home/sita/.ssh/sitaram.
|
||||
Your public key has been saved in /home/sita/.ssh/sitaram.pub.
|
||||
The key fingerprint is:
|
||||
2a:8e:88:42:36:7e:71:e8:cc:ff:4c:54:64:8e:cf:19 sita@sita-lt.atc.tcs.com
|
||||
The key's randomart image is:
|
||||
+--[ RSA 2048]----+
|
||||
| o |
|
||||
| = |
|
||||
| . E |
|
||||
| + o |
|
||||
| . .S+ |
|
||||
| + o ... |
|
||||
|+ = + .. |
|
||||
|oo B .o |
|
||||
|+ o o..o |
|
||||
+-----------------+
|
||||
creating gitolite para in ~/.ssh/config...
|
||||
finding/creating gitolite rc...
|
||||
installing/upgrading...
|
||||
Initialized empty Git repository in /home/git/repositories/gitolite-admin.git/
|
||||
Initialized empty Git repository in /home/git/repositories/testing.git/
|
||||
Pseudo-terminal will not be allocated because stdin is not a terminal.
|
||||
fatal: No HEAD commit to compare with (yet)
|
||||
[master (root-commit) 2f40d4b] start
|
||||
2 files changed, 13 insertions(+), 0 deletions(-)
|
||||
create mode 100644 conf/gitolite.conf
|
||||
create mode 100644 keydir/sitaram.pub
|
||||
cloning gitolite-admin repo...
|
||||
Initialized empty Git repository in /home/sita/gitolite-admin/.git/
|
||||
remote: Counting objects: 6, done.
|
||||
remote: Compressing objects: 100% (4/4), done.
|
||||
remote: Total 6 (delta 0), reused 0 (delta 0)
|
||||
Receiving objects: 100% (6/6), done.
|
||||
|
||||
|
||||
---------------------------------------------------------------
|
||||
|
||||
done!
|
||||
|
||||
Reminder:
|
||||
*Your* URL for cloning any repo on this server will be
|
||||
gitolite:reponame.git
|
||||
*Other* users you set up will have to use
|
||||
git@server:reponame.git
|
||||
|
||||
If this is your first time installing gitolite, please also:
|
||||
tail -31 ./gl-easy-install
|
||||
for next steps.
|
||||
|
||||
----
|
||||
|
||||
<a name="_VERY_IMPORTANT_"></a>
|
||||
|
||||
### VERY IMPORTANT...
|
||||
|
||||
Please read the text that the easy-install command produces as output when you
|
||||
run it. People who fail to read this get into trouble later. And I didn't
|
||||
write all that because I wanted to practice typing.
|
||||
|
||||
The text just above this section is an approximation; your version will
|
||||
contain the correct URLs for your install, including port numbers if
|
||||
non-standard ports were used).
|
||||
|
||||
Try out that `tail -31 ./gl-easy-install` too :)
|
||||
|
||||
<a name="_examine_what_you_have"></a>
|
||||
|
||||
### examine what you have
|
||||
|
||||
The last step of the previous command creates a local clone of your
|
||||
gitolite-admin repo in `~/gitolite-admin`.
|
||||
|
||||
sita@sita-lt:src $ cd ~/gitolite-admin/
|
||||
|
||||
sita@sita-lt:gitolite-admin $ git --no-pager log --stat
|
||||
commit 2f40d4bb80d424dc39aae5d0973f8c1b2e395666
|
||||
Author: git <git@sita-lt.atc.tcs.com>
|
||||
Date: Thu Dec 24 21:39:15 2009 +0530
|
||||
|
||||
start
|
||||
|
||||
conf/gitolite.conf | 12 ++++++++++++
|
||||
keydir/sitaram.pub | 1 +
|
||||
2 files changed, 13 insertions(+), 0 deletions(-)
|
||||
|
||||
And that's really all. Add keys to keydir here, edit conf/gitolite.conf as
|
||||
needed, then add, commit, and push the changes to the server.
|
||||
|
||||
<a name="_emergency_password_access"></a>
|
||||
|
||||
### emergency password access
|
||||
|
||||
If you lose your keys or the worst happens and you use the wrong key for the
|
||||
wrong thing and apparently lose all access, but you still know the password,
|
||||
this is what you do:
|
||||
|
||||
sita@sita-lt:~ $ ssh -o preferredauthentications=password git@server
|
||||
git@server's password:
|
109
doc/migrate.mkd
109
doc/migrate.mkd
|
@ -1,109 +0,0 @@
|
|||
# migrating from gitosis to gitolite
|
||||
|
||||
[TODO: make the migration tool fix up gitweb and daemon control also...]
|
||||
|
||||
Migrating from gitosis to gitolite is pretty easy, because the basic design is
|
||||
the same.
|
||||
|
||||
Here's how we migrated my work repos:
|
||||
|
||||
1. login as the `git` user on the server, and get a bash shell prompt
|
||||
|
||||
2. **disable gitosis** by renaming `/usr/bin/gitosis-serve` to something
|
||||
else. This will prevent users from pushing anything while you do the
|
||||
backup, migration, etc.
|
||||
|
||||
3. **edit** `~/.ssh/authorized_keys` and **carefully** remove all the lines
|
||||
containing "gitosis-serve", as well as the marker line that says
|
||||
"auto-generated by gitosis, DO NOT REMOVE", then save the file. If the
|
||||
file did not have any other keys and is now empty, don't worry -- save it
|
||||
anyway because gitolite expects the file to be present (even if it is
|
||||
empty).
|
||||
|
||||
4. 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`.
|
||||
|
||||
If you do not do this, an accidental push to the gitosis-admin repo will
|
||||
mess up your `~/.ssh/authorized_keys` file
|
||||
|
||||
5. If you already use the `update` hook for some reason, **rename** it (on
|
||||
each individual repository) to `update.secondary`. This is because
|
||||
gitolite uses the update hook for checking write access.
|
||||
|
||||
6. take a **backup** of the `~/repositories` directory
|
||||
|
||||
Now, log off the server and get back to the client:
|
||||
|
||||
1. follow instructions to install gitolite; see the [install document][inst].
|
||||
Make sure that you **don't** change the default path for `$REPO_BASE` if
|
||||
you edit the config file!
|
||||
|
||||
This will give you a gitolite config that has the required entries for the
|
||||
"gitolite-admin" repo.
|
||||
|
||||
2. **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`
|
||||
|
||||
src/gl-conf-convert < $GSAC/gitosis.conf >> $GLAC/gitolite.conf
|
||||
|
||||
Be sure to check the file to make sure it converted correctly
|
||||
|
||||
3. **copy** the keys from gitosis's keydir (same meanings for GSAC and GLAC)
|
||||
|
||||
cp $GSAC/keydir/* $GLAC/keydir
|
||||
|
||||
4. **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.
|
||||
|
||||
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.
|
||||
|
||||
[This][mk] will tell you more about these nuances.
|
||||
|
||||
5. **IMPORTANT: expand any multi-key files you may have**. [Here][mk]'s an
|
||||
explanation of what multi-keys are, how gitosis does them and how gitolite
|
||||
does it differently.
|
||||
|
||||
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*
|
||||
|
||||
6. Check all your changes to your gitolite-admin clone, commit, and push
|
||||
|
||||
[mk]: http://sitaramc.github.com/gitolite/doc/3-faq-tips-etc.html#multikeys
|
||||
[inst]: http://sitaramc.github.com/gitolite/doc/1-INSTALL.html
|
|
@ -1,346 +0,0 @@
|
|||
## mirroring a gitolite setup
|
||||
|
||||
Mirroring git repos is essentially a one-liner. For each mirror you want to
|
||||
update, you just add a post-receive hook that says
|
||||
|
||||
#!/bin/bash
|
||||
git push --mirror slave_user@mirror.host:/path/to/repo.git
|
||||
|
||||
But life is never that simple...
|
||||
|
||||
**This document has been tested using a 3-server setup, all installed using
|
||||
the "non-root" method (see doc/1-INSTALL.mkd). However, the process is
|
||||
probably not going to be very forgiving of human error -- like anything that
|
||||
is this deep in "system admin" territory, errors are likely to be costly. If
|
||||
you're the kind who hits enter first and then thinks about what he typed,
|
||||
you're in for some fun times ;-)**
|
||||
|
||||
**On the plus side, everything we do is done using git commands, so things are
|
||||
never *really* lost until you do a `git gc`**.
|
||||
|
||||
----
|
||||
|
||||
**Update 2011-03-10**: I wrote this with a typical "corporate" setup in mind
|
||||
where all the servers involved are owned and administered by the same group of
|
||||
people. As a result, the scripts assume the servers trust each other
|
||||
completely. If that is not your situation, you will have to add code into
|
||||
`gl-mirror-shell` to limit the commands the remote may send. Patches welcome
|
||||
:-)
|
||||
|
||||
----
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_RULE_NUMBER_ONE_">RULE NUMBER ONE!</a>
|
||||
* <a href="#_things_that_will_NOT_be_mirrored_by_this_process">things that will NOT be mirrored by this process</a>
|
||||
* <a href="#_conventions_in_this_document">conventions in this document</a>
|
||||
* <a href="#_setting_up_mirroring">setting up mirroring</a>
|
||||
* <a href="#_install_gitolite_on_all_servers">install gitolite on all servers</a>
|
||||
* <a href="#_generate_keypairs">generate keypairs</a>
|
||||
* <a href="#_setup_the_mirror_shell_on_each_server">setup the mirror-shell on each server</a>
|
||||
* <a href="#_set_slaves_to_slave_mode">set slaves to slave mode</a>
|
||||
* <a href="#_set_slave_server_lists">set slave server lists</a>
|
||||
* <a href="#_efficiency_versus_paranoia">efficiency versus paranoia</a>
|
||||
* <a href="#_syncing_the_mirrors_the_first_time">syncing the mirrors the first time</a>
|
||||
* <a href="#_switching_over">switching over</a>
|
||||
* <a href="#_the_return_of_foo">the return of foo</a>
|
||||
* <a href="#_switching_back">switching back</a>
|
||||
* <a href="#_making_foo_a_slave">making foo a slave</a>
|
||||
* <a href="#_URLs_that_your_users_will_use">URLs that your users will use</a>
|
||||
|
||||
<a name="_RULE_NUMBER_ONE_"></a>
|
||||
|
||||
### RULE NUMBER ONE!
|
||||
|
||||
**RULE OF GIT MIRRORING: users should push directly to only one server**! All
|
||||
the other machines (the slaves) should be updated by the master server.
|
||||
|
||||
If a user pushes directly to one of the slaves, those changes will get wiped
|
||||
out on the next mirror push from the real master server.
|
||||
|
||||
Corollary: if the primary went down and you effected a changeover, you must
|
||||
make sure that the primary does not come up in a push-enabled mode when it
|
||||
recovers.
|
||||
|
||||
<a name="_things_that_will_NOT_be_mirrored_by_this_process"></a>
|
||||
|
||||
### things that will NOT be mirrored by this process
|
||||
|
||||
Let's get this out of the way. This procedure will only mirror your git
|
||||
repositories, using `git push --mirror`. Therefore, certain files will not be
|
||||
mirrored:
|
||||
|
||||
* gitolite log files
|
||||
* "gl-creator" and "gl-perms" files
|
||||
* "projects.list", "description", and entries in the "config" files within
|
||||
each repo
|
||||
|
||||
None of these affect actual repo contents of course, but they could be
|
||||
important, (especially the gl-creator, although if your wildcard pattern had
|
||||
"CREATOR" in it you can recreate those files easily enough anyway).
|
||||
|
||||
Your best bet is to use rsync for the log files, and tar for the others, at
|
||||
regular intervals.
|
||||
|
||||
<a name="_conventions_in_this_document"></a>
|
||||
|
||||
### conventions in this document
|
||||
|
||||
The userid hosting gitolite is `gitolite` on all machines. The servers are
|
||||
foo, bar, and baz. At the beginning, foo is the master, the other 2 are
|
||||
slaves.
|
||||
|
||||
<a name="_setting_up_mirroring"></a>
|
||||
|
||||
### setting up mirroring
|
||||
|
||||
<a name="_install_gitolite_on_all_servers"></a>
|
||||
|
||||
#### install gitolite on all servers
|
||||
|
||||
* before running the final step in the install sequence, make sure you go to
|
||||
the `hooks/common` directory and rename `post-receive.mirrorpush` to
|
||||
`post-receive`. See doc/hook-propagation.mkd if you're not sure where you
|
||||
should look for `hooks/common`.
|
||||
|
||||
* if the server already has gitolite installed, use the normal methods to
|
||||
make sure this hook gets in.
|
||||
|
||||
* Use the same "admin key" on all the machines, so that the same person has
|
||||
gitolite-admin access to all of them.
|
||||
|
||||
<a name="_generate_keypairs"></a>
|
||||
|
||||
#### generate keypairs
|
||||
|
||||
Each server will be potentially logging on to one or more of the other
|
||||
servers, so first generate keypairs for all of them (`ssh-keygen`) and copy
|
||||
the `.pub` files to all other servers, named appropriately. So foo will have
|
||||
bar.pub and baz.pub, etc.
|
||||
|
||||
<a name="_setup_the_mirror_shell_on_each_server"></a>
|
||||
|
||||
#### setup the mirror-shell on each server
|
||||
|
||||
XXX review this document after testing mirroring...
|
||||
|
||||
If you installed gitolite using the from client method, run the following:
|
||||
|
||||
# on foo
|
||||
export GL_BINDIR=$HOME/.gitolite/src
|
||||
cat bar.pub baz.pub |
|
||||
sed -e 's,^,command="'$GL_BINDIR'/gl-mirror-shell" ,' >> ~/.ssh/authorized_keys
|
||||
|
||||
If you installed using any of the other 3 methods do this:
|
||||
|
||||
# on foo
|
||||
export GL_BINDIR=`gl-query-rc GL_BINDIR`
|
||||
cat bar.pub baz.pub |
|
||||
sed -e 's,^,command="'$GL_BINDIR'/gl-mirror-shell" ,' >> ~/.ssh/authorized_keys
|
||||
|
||||
Also do the same thing on the other machines.
|
||||
|
||||
Now test this access:
|
||||
|
||||
# on foo
|
||||
ssh gitolite@bar pwd
|
||||
# should print /home/gitolite/repositories
|
||||
ssh gitolite@bar uname -a
|
||||
# should print the appropriate info for that server
|
||||
|
||||
Similarly test the other combinations.
|
||||
|
||||
<a name="_set_slaves_to_slave_mode"></a>
|
||||
|
||||
#### set slaves to slave mode
|
||||
|
||||
Set slave mode on all the *slave* servers by setting `$GL_SLAVE_MODE = 1`
|
||||
(uncommenting the line if necessary).
|
||||
|
||||
Leave the master server's file as is.
|
||||
|
||||
<a name="_set_slave_server_lists"></a>
|
||||
|
||||
#### set slave server lists
|
||||
|
||||
On the master (foo), set the names of the slaves by editing the
|
||||
`~/.gitolite.rc` to contain:
|
||||
|
||||
$ENV{GL_SLAVES} = 'gitolite@bar gitolite@baz';
|
||||
|
||||
**Note the syntax well; this is critical**:
|
||||
|
||||
* **this must be in single quotes** (or you must remember to escape the `@`)
|
||||
* the variable is an ENV var, not a plain perl var
|
||||
* the values are *space separated*
|
||||
* each value represents the userid and hostname for one server
|
||||
|
||||
The basic idea is that this string, should be usable in both the following
|
||||
syntaxes:
|
||||
|
||||
git clone gitolite@bar:repo
|
||||
ssh gitolite@bar pwd
|
||||
|
||||
You can also use ssh host aliases. Let's say server "bar" has a non-standard
|
||||
port number:
|
||||
|
||||
# in ~/.ssh/config on foo
|
||||
host mybar
|
||||
hostname bar
|
||||
user gitolite
|
||||
port 2222
|
||||
|
||||
# in ~/.gitolite.rc on foo
|
||||
$ENV{GL_SLAVES} = 'bar gitolite@baz';
|
||||
|
||||
And that's really all there is, unless...
|
||||
|
||||
<a name="_efficiency_versus_paranoia"></a>
|
||||
|
||||
### efficiency versus paranoia
|
||||
|
||||
If you're paranoid enough to use mirrors, you should be paranoid enough to
|
||||
like the `receive.fsckObjects` setting we now default to :-) However, informal
|
||||
tests indicate a 40-50% CPU overhead from this. If you don't like that,
|
||||
remove that line from the post-receive code.
|
||||
|
||||
Please also note that we only set it on mirrors, and that too at the time the
|
||||
mirrored repo is *created*. This means, when you start using your old "main"
|
||||
server as a mirror (see later sections on switching over to a mirror, etc.),
|
||||
it's repos do not have this setting. Repos created by previous versions of
|
||||
gitolite also will not have this setting.
|
||||
|
||||
Personally, I just set `git config --global receive.fsckObjects true`, since
|
||||
those servers aren't doing anything else anyway, and are idle for long
|
||||
stretches of time. It's upto you what you want to do here.
|
||||
|
||||
<a name="_syncing_the_mirrors_the_first_time"></a>
|
||||
|
||||
### syncing the mirrors the first time
|
||||
|
||||
This is fine if you're setting up everything from scratch. But if your master
|
||||
server already had some repos with commits on them, you have to manually sync
|
||||
them up once.
|
||||
|
||||
# on foo
|
||||
gl-mirror-sync gitolite@bar
|
||||
# path to "sync" program is ~/.gitolite/src if "from-client" install
|
||||
|
||||
<a name="_switching_over"></a>
|
||||
|
||||
### switching over
|
||||
|
||||
Let's say foo goes down. You want to make bar the main server, and continue
|
||||
to have "baz" be a slave.
|
||||
|
||||
* on bar, edit `~/.gitolite.rc` and set
|
||||
|
||||
$GL_SLAVE_MODE = 0;
|
||||
$ENV{GL_SLAVES} = 'gitolite@baz';
|
||||
|
||||
* **sanity check**: go to your gitolite-admin clone, add a remote for "bar",
|
||||
fetch it, and make sure they are the same:
|
||||
|
||||
git remote add bar gitolite@bar:gitolite-admin
|
||||
git fetch bar
|
||||
git branch -a -v
|
||||
# check that all SHAs are the same
|
||||
|
||||
* inform everyone of the new URL for their repos (see next section for more
|
||||
on this)
|
||||
|
||||
* make sure that if "foo" does come up, it will not immediately start
|
||||
serving requests. You'll be in trouble if (a) foo comes up as it was
|
||||
before, and (b) some developer still had the old URL lying around and
|
||||
started pushing changes to it.
|
||||
|
||||
You could jump in quickly and set `$GL_SLAVE_MODE = 1` as soon as the
|
||||
system comes up. Better still, use extraneous means to block incoming
|
||||
connections from normal users (out of scope for this document).
|
||||
|
||||
<a name="_the_return_of_foo"></a>
|
||||
|
||||
### the return of foo
|
||||
|
||||
<a name="_switching_back"></a>
|
||||
|
||||
#### switching back
|
||||
|
||||
Switching back is fairly easy.
|
||||
|
||||
* synchronise all repos from bar to foo. This may take some time, depending
|
||||
on how long foo was down.
|
||||
|
||||
# on bar
|
||||
gl-mirror-sync gitolite@foo
|
||||
# path to "sync" program is ~/.gitolite/src if "from-client" install
|
||||
|
||||
* turn off pushes on "bar" by setting slave mode to 1
|
||||
* run the sync once again; this should complete quickly
|
||||
|
||||
* **double check by comparing some the repos on both sides if needed**. You
|
||||
could run the following snippet on all servers for a quick check:
|
||||
|
||||
cd ~/repositories # or wherever $REPO_BASE is
|
||||
find . -type d -name "*.git" | sort |
|
||||
while read r
|
||||
do
|
||||
echo $r
|
||||
git ls-remote $r | sort
|
||||
done | md5sum
|
||||
|
||||
* on foo, set the slave list (or check that it is correct)
|
||||
* on foo, set slave mode off
|
||||
* tell everyone to switch back
|
||||
|
||||
<a name="_making_foo_a_slave"></a>
|
||||
|
||||
#### making foo a slave
|
||||
|
||||
If "foo" does come up in a controlled manner, you might not want to switch
|
||||
back right away. Unless you're doing DNS tricks, users may be peeved at
|
||||
having to do 2 switches.
|
||||
|
||||
If you want to make foo a slave, you know the drill by now:
|
||||
|
||||
* set slave mode to 1 on foo
|
||||
* on bar, add foo as a slave
|
||||
|
||||
# in ~/.gitolite.rc on bar
|
||||
$ENV{GL_SLAVES} = 'gitolite@foo gitolite@baz';
|
||||
|
||||
I think that should cover pretty much everything. I *have* tested most of
|
||||
this, but YMMV.
|
||||
|
||||
----
|
||||
|
||||
<a name="_URLs_that_your_users_will_use"></a>
|
||||
|
||||
### URLs that your users will use
|
||||
|
||||
Unless you play DNS tricks, it is more than likely that your users would have
|
||||
to change the URLs they use to access their repos if you change the server
|
||||
they push to.
|
||||
|
||||
I cannot speak for the plethora of git client software out there but for
|
||||
normal git, this problem can be mitigated somewhat by doing this:
|
||||
|
||||
* in `~/.ssh/config` on my workstation, I have
|
||||
|
||||
host gl
|
||||
hostname=primary.server.ip
|
||||
user=gitolite
|
||||
|
||||
* all my `git clone` commands use `gl:reponame` as the URL
|
||||
|
||||
* if the primary goes down, and I have to access the secondary, I just
|
||||
change the `hostname` line in `~/.ssh/config`.
|
||||
|
||||
That's it. Every clone of every repo used anywhere in this userid is now
|
||||
changed.
|
||||
|
||||
To repeat, this may or may not work with all the git clients that exist (like
|
||||
jgit, or any of the GUI tools, and especially if you're on Windows).
|
||||
|
||||
If anyone has a better idea, something that works more universally, I'd love
|
||||
to hear it.
|
|
@ -1,76 +0,0 @@
|
|||
## mob branches in gitolite
|
||||
|
||||
WARNING: This is hairy stuff. But what's life without a little danger?
|
||||
|
||||
WARNING 2: girocco does mob branches quite differently; the controls on what a
|
||||
mob branch can do are much more fundamental. Here we just trick gitolite into
|
||||
accepting anonymous ssh connections and pretending they're from a mythical
|
||||
user called "mob". **This means all the access control is -- as you might
|
||||
expect -- in the gitolite.conf file, so make sure you don't give the `mob`
|
||||
user too many rights!**
|
||||
|
||||
(tested on Fedora 13; assumes your gitolite server userid is "gitolite" and
|
||||
install was "from-client" method; adjust according to your environment. If
|
||||
you need more than this, you should not be enabling mob branches anyway ;-)
|
||||
|
||||
[hah! Easy way out of being badgered with questions!]
|
||||
|
||||
* create a file called `/tmp/mobshell` (put it somewhere more permanent if
|
||||
you wish). This file should be `chmod +x` and contain
|
||||
|
||||
#!/bin/sh
|
||||
shift
|
||||
export SSH_ORIGINAL_COMMAND
|
||||
SSH_ORIGINAL_COMMAND="$*"
|
||||
|
||||
/home/gitolite/.gitolite/src/gl-auth-command mob
|
||||
# see one of the lines in ~gitolite/.ssh/authorized_keys for the
|
||||
# precise location of the gl-auth-command script
|
||||
|
||||
* create a user called mob. Give it the same UID number and `$HOME` as your
|
||||
gitolite server userid, and set the login shell to be the script you just
|
||||
created. Also delete the password.
|
||||
|
||||
id -u gitolite
|
||||
# returns 503 or something...
|
||||
useradd -d /home/gitolite -s /tmp/mobshell -u 503 -o mob
|
||||
passwd -d mob
|
||||
|
||||
* make sure you have a recent enough sshd and put these lines at the bottom,
|
||||
then restart sshd
|
||||
|
||||
Match user mob
|
||||
PermitEmptyPasswords yes
|
||||
|
||||
That's it. Now you can add stuff to your gitolite.conf file. Here's some
|
||||
examples:
|
||||
|
||||
* This allows the mob user to do anything to the "mob" branch:
|
||||
|
||||
repo foo
|
||||
RW+ = alice bob
|
||||
R = eve
|
||||
RW+ mob$ = mob
|
||||
# only the mob branch, nothing more
|
||||
|
||||
* This is the same, except it can be any branch under "mob/" so you get some
|
||||
flexibility:
|
||||
|
||||
RW+ mob/ = mob
|
||||
|
||||
* Girocco allows pushing to the mob branch only if it already exists (that
|
||||
is, the mob user cannot *create* the mob branch, but if it already exists
|
||||
he can push to it). Here's how you'd do that in gitolite:
|
||||
|
||||
repo foo
|
||||
RW+C = alice bob
|
||||
R = eve
|
||||
RW+ mob$ = mob
|
||||
|
||||
* This gives *every* repo a mob branch (be careful!)
|
||||
|
||||
repo @all
|
||||
RW+ mob$ = mob
|
||||
|
||||
How do mob users access it? The URLs just look like: `mob@server:repo`
|
||||
instead of `gitolite@server:repo` That's it!
|
|
@ -1,67 +0,0 @@
|
|||
## (contributed doc: integrating gitolite with monkeysphere)
|
||||
|
||||
This document attempts to describe one way to integrate
|
||||
[Monkeysphere](http://web.monkeysphere.info/) authentication
|
||||
with [gitolite](http://github.com/sitaramc/gitolite).
|
||||
|
||||
We presuppose that you have a system with a new enough
|
||||
version of Monkeysphere to support ssh `authorized_keys`
|
||||
options, and that you are not making use of
|
||||
monkeysphere-authentication on this system.
|
||||
|
||||
As a first step, import the key or keys you wish to
|
||||
act as Monkeysphere certifiers into the GnuPG public
|
||||
keyring of the gitolite user (for example,
|
||||
`gpg --keyserver pool.sks-keyservers.net --recv-keys B0AE9A02`)
|
||||
Then edit such keys (`gpg --edit B0AE9A02`) and assign them
|
||||
*ultimate* ownertrust.
|
||||
|
||||
Next install a script of this nature as `post-update.secondary`
|
||||
in the `hooks/` directory of the `gitolite-admin` repository. You can also
|
||||
follow the "using hooks" section in gitolite's "admin" document to let
|
||||
gitolite put your new hook in the correct place.
|
||||
|
||||
#!/bin/zsh
|
||||
|
||||
# this should use locking
|
||||
|
||||
pushd ${GL_ADMINDIR}
|
||||
|
||||
if [[ -d monkeydir ]]
|
||||
then
|
||||
cp ~/.monkeysphere/authorized_user_ids ~/.monkeysphere/old-authorized_user_ids
|
||||
rm -f ~/.monkeysphere/new-authorized_user_ids
|
||||
for i in monkeydir/*.pub
|
||||
do
|
||||
username=$i:t:r
|
||||
for j in ${(f)"$(<$i)"}
|
||||
do
|
||||
cat >> ~/.monkeysphere/new-authorized_user_ids <<EOF
|
||||
$j
|
||||
command="/usr/share/gitolite/gl-auth-command $username"
|
||||
no-port-forwarding
|
||||
no-X11-forwarding
|
||||
no-agent-forwarding
|
||||
no-pty
|
||||
EOF
|
||||
|
||||
done
|
||||
done
|
||||
|
||||
mv ~/.monkeysphere/new-authorized_user_ids ~/.monkeysphere/authorized_user_ids
|
||||
monkeysphere update-authorized_keys
|
||||
fi
|
||||
|
||||
popd
|
||||
|
||||
ADMIN_POST_UPDATE_CHAINS_TO=hooks/post-update.tertiary
|
||||
|
||||
if [[ -f $ADMIN_POST_UPDATE_CHAINS_TO || -L $ADMIN_POST_UPDATE_CHAINS_TO ]]; then
|
||||
exec $ADMIN_POST_UPDATE_CHAINS_TO "$@"
|
||||
fi
|
||||
|
||||
Finally, place *username*.pub files containing OpenPGP IDs into
|
||||
a directory called `monkeydir/` in the root of the gitolite-admin
|
||||
repository. If everything has been set up correctly, adding
|
||||
and pushing these files should then result in the appropriate
|
||||
generation of `~/.ssh/authorized_keys`.
|
|
@ -1,57 +0,0 @@
|
|||
## when gitolite is overkill
|
||||
|
||||
Note: I wrote this to help people for whom gitolite is genuinely overkill. I
|
||||
believe it will all work, but YMMV.
|
||||
|
||||
----
|
||||
|
||||
You don't always need something like gitolite. If you have a fixed (or very
|
||||
rarely changing) number of users, and all of them have full access to all your
|
||||
repos, you can use plain Unix permissions to get a lot of this done:
|
||||
|
||||
* dedicate a userid (say "git") to host all your repos. This user will also
|
||||
have a group (normally called "git" on most distros I think)
|
||||
|
||||
* create a directory that is accessible (at least "r" and "x" permissions)
|
||||
to the group "git", all the way upto the root. (That is, if the directory
|
||||
you chose is /home/git/repos, then /, /home, /home/git, and
|
||||
/home/git/repos must all be "g+rx").
|
||||
|
||||
* create all repos in this directory, as the "git" user, using the following
|
||||
command:
|
||||
|
||||
git init --bare --shared reponame.git
|
||||
|
||||
* For each user who needs access to the repos, add them as members to the
|
||||
"git" group also. On Fedora this is:
|
||||
|
||||
usermod -a -G git username
|
||||
|
||||
And that's basically it. The "init --shared" will create the repos with
|
||||
"chmod -R g+s". If you have existing repos where you forgot (or didn't know)
|
||||
the "--shared" argument, do this on each of them:
|
||||
|
||||
cd reponame.git
|
||||
git init --shared --bare
|
||||
chmod -R g+w .
|
||||
chmod g+s `find . -type d`
|
||||
|
||||
I think that should do it.
|
||||
|
||||
Once you've setup the Unix level permissions, you may consider setting the
|
||||
shell of some of the less experienced users to "git-shell" (using its full
|
||||
path) if they don't really need a shell on the server. This will let them
|
||||
access git remotely but not do anything else.
|
||||
|
||||
Combining this with settings like `receive.denyDeletes` and
|
||||
`receive.denyNonFastForwards`, or at least `core.logAllRefUpdates`, can go a
|
||||
long way toward preventing accidents or at least making it feasible to recover
|
||||
from them.
|
||||
|
||||
----
|
||||
|
||||
You can do more complex things using Unix acls. If you do, and feel like
|
||||
writing it up, send it to me and I will add it here (with credit given of
|
||||
course). Personally, I can't be bothered -- once you have differing needs for
|
||||
different people, you really need gitolite anyway, because you probably need
|
||||
different rights for branches as well and Unix ACLs can't do that.
|
|
@ -1,56 +0,0 @@
|
|||
## packaging gitolite
|
||||
|
||||
Here's how you'd package gitolite. In the following description, location "X"
|
||||
can be, say, `/usr/share/gitolite/conf` or some such, and similarly location
|
||||
"Y" can be perhaps `/usr/share/gitolite/hooks`. It's upto your distro
|
||||
policies where they are.
|
||||
|
||||
**Step 1**: Clone the gitolite repo and run the make command inside the clone
|
||||
|
||||
git clone git://github.com/sitaramc/gitolite.git
|
||||
cd gitolite
|
||||
make pu.tar # or "make master.tar" or "make v1.2.tar" etc
|
||||
|
||||
Then you explode the tar file in some temporary location.
|
||||
|
||||
*Alternatively, you can `git checkout` the tag or branch you want, and run
|
||||
this command in the clone directly*:
|
||||
|
||||
git describe --tags --long > conf/VERSION
|
||||
|
||||
**Step 2**: Now make the following changes (no trailing slashes in the
|
||||
location values please):
|
||||
|
||||
* `src/gl-setup` should have the following line:
|
||||
|
||||
GL_PACKAGE_CONF="X"
|
||||
|
||||
* `conf/example.gitolite.rc` should have the following lines:
|
||||
|
||||
$GL_PACKAGE_CONF="X";
|
||||
$GL_PACKAGE_HOOKS="Y";
|
||||
|
||||
* delete `src/gl-easy-install`; that script is meant for a totally different
|
||||
mode of installation and does *not* play well in this mode :-)
|
||||
|
||||
**Step 3**: Move (or arrange to move) the files to their proper locations as
|
||||
given below:
|
||||
|
||||
* everything in "src" goes somewhere on the PATH
|
||||
* everything in "conf" goes to location "X"
|
||||
* everything in "hooks" goes to location "Y"
|
||||
|
||||
**Step 4**: There is no step 4. Unless you count telling your users to run
|
||||
`gl-setup` as a step :)
|
||||
|
||||
On the initial install (urpmi, yum install, or apt-get install), you could
|
||||
also choose to setup a userid called "gitolite", and run "gl-setup" as that
|
||||
user; however I do not know how you would come up with the initial pubkey that
|
||||
is needed. Anyway, the point is that the "gitolite" user is no more special
|
||||
than any other in terms of hosting gitolite. Any user can host gitolite on
|
||||
his userid by just running "gl-setup".
|
||||
|
||||
When you upgrade, just overwrite all the files; it'll all just work. In fact,
|
||||
other than the initial "gl-setup" run, the only time a gitolite hosting user
|
||||
has to actually do anything is to edit their own `~/.gitolite.rc` file if they
|
||||
want to enable or disable specific features.
|
|
@ -1,190 +0,0 @@
|
|||
# (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][gldpg]. 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.
|
||||
|
||||
[gldpg]: http://sitaramc.github.com/gitolite/doc/progit-article.html
|
||||
|
||||
Git has started to 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.
|
||||
|
||||
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.
|
||||
|
||||
<a name="_Installing_"></a>
|
||||
|
||||
### 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; various Linux flavours, and Solaris 10, have been tested. 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 `gitolite` 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". As a result, there is a notion of "installing" the software itself, and then "setting up" a user as a "gitolite host".
|
||||
|
||||
Gitolite has 4 methods of installation. People using Fedora or Debian systems can obtain an RPM or a DEB and install that. People with root access can install it manually. In these two methods, any user on the system can then become a "gitolite host".
|
||||
|
||||
People without root access can install it within their own userids. And finally, gitolite can be installed by running a script *on the workstation*, from a bash shell. (Even the bash that comes with msysgit will do, in case you're wondering.)
|
||||
|
||||
We will describe this last method in this article; for the other methods please see the documentation.
|
||||
|
||||
You start by obtaining public key based access to your server, so that you can log in from your workstation to the server without getting a password prompt. The following method works on Linux; for other workstation OSs you may have to do this manually. We assume you already had a key pair generated using `ssh-keygen`.
|
||||
|
||||
$ ssh-copy-id -i ~/.ssh/id_rsa.pub gitolite@gitserver
|
||||
|
||||
This will ask you for the password to the gitolite account, and then set up public key access. This is **essential** for the install script, so check to make sure you can run a command without getting a password prompt:
|
||||
|
||||
$ ssh gitolite@gitserver pwd
|
||||
/home/gitolite
|
||||
|
||||
Next, you clone Gitolite from the project's main site and run the "easy install" script (the third argument is your name as you would like it to appear in the resulting gitolite-admin repository):
|
||||
|
||||
$ git clone git://github.com/sitaramc/gitolite
|
||||
$ cd gitolite/src
|
||||
$ ./gl-easy-install -q gitolite gitserver sitaram
|
||||
|
||||
And you're done! Gitolite has now been installed on the server, and you now have a brand new repository called `gitolite-admin` in the home directory of your workstation. You administer your gitolite setup by making changes to this repository and pushing.
|
||||
|
||||
That last command does produce a fair amount of output, which might be interesting to read. Also, the first time you run this, a new keypair is created; you will have to choose a passphrase or hit enter for none. Why a second keypair is needed, and how it is used, is explained in the "ssh troubleshooting" document that comes with Gitolite. (Hey the documentation has to be good for *something*!)
|
||||
|
||||
<a name="_Customising_the_Install_"></a>
|
||||
|
||||
### Customising the Install ###
|
||||
|
||||
While the default, quick, install works for most people, there are some ways to customise the install if you need to. If you omit the `-q` argument, you get a "verbose" mode install -- detailed information on what the install is doing at each step. The verbose mode also allows you to change certain server-side parameters, such as the location of the actual repositories, by editing an "rc" file that the server uses. This "rc" file is documented in [doc/gitolite.rc.mkd][rcdoc] so you should be able to make any changes you need quite easily, save it, and continue. This file also contains various settings that you can change to enable or disable some of gitolite's advanced features.
|
||||
|
||||
<a name="_Config_File_and_Access_Control_Rules_"></a>
|
||||
|
||||
### 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
|
||||
#gitolite conf
|
||||
# please see doc/gitolite.conf.mkd for details on syntax and features
|
||||
|
||||
|
||||
repo gitolite-admin
|
||||
RW+ = sitaram
|
||||
|
||||
repo testing
|
||||
RW+ = @all
|
||||
|
||||
Notice that "sitaram" (the last argument in the `gl-easy-install` command you gave 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 documented in [doc/gitolite.conf.mkd][confdoc] 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.
|
||||
|
||||
<a name="_Advanced_Access_Control_with_deny_rules_"></a>
|
||||
|
||||
### 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.
|
||||
|
||||
<a name="_Restricting_pushes_by_files_changed_"></a>
|
||||
|
||||
### 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
|
||||
|
||||
RW NAME/ = @senior_devs
|
||||
- NAME/Makefile = @junior_devs
|
||||
RW NAME/ = @junior_devs
|
||||
|
||||
This powerful feature is documented in `conf/example.conf`.
|
||||
|
||||
<a name="_Personal_Branches_"></a>
|
||||
|
||||
### 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/<devname>/*`); see the "personal branches" section in `doc/3-faq-tips-etc.mkd` for details.
|
||||
|
||||
<a name="_Wildcard_repositories_"></a>
|
||||
|
||||
### "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. This is a *very* powerful feature, which has to be enabled by setting `$GL_WILDREPOS = 1;` in the rc file. 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 in `doc/wildcard-repositories.mkd`.
|
||||
|
||||
<a name="_Other_Features_"></a>
|
||||
|
||||
### 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 "faqs, tips, etc" and other documents.
|
||||
|
||||
**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.
|
||||
|
||||
**Git outside normal PATH**: One extremely useful convenience feature in gitolite is support for git installed outside the normal `$PATH` (this is more common than you think; some corporate environments or even some hosting providers refuse to install things system-wide and you end up putting them in your own directories). Normally, you are forced to make the *client-side* git aware of this non-standard location of the git binaries in some way. With gitolite, just choose a verbose install and set `$GIT_PATH` in the "rc" files. No client-side changes are required after that :-)
|
||||
|
||||
**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, the gitolite version here is v1.5.4-19-ga3397d4
|
||||
the gitolite config gives you the following access:
|
||||
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. This feature has its own documentation file in the `doc/` directory.
|
||||
|
||||
**Gitweb support**: Gitolite supports gitweb in several ways. You can specify which repos are visible via gitweb. You can set the "owner" and "description" for gitweb from the gitolite config file. Gitweb has a mechanism for you to implement access control based on HTTP authentication, so you can make it use the "compiled" config file that gitolite produces, which means the same access control rules (for read access) apply for gitweb and gitolite.
|
||||
|
||||
**Mirroring**: Gitolite can help you maintain multiple mirrors, and switch between them easily if the primary server goes down.
|
||||
|
||||
[rcdoc]:http://sitaramc.github.com/gitolite/doc/gitolite.rc.html
|
||||
[confdoc]:http://sitaramc.github.com/gitolite/doc/gitolite.conf.html
|
|
@ -1,149 +0,0 @@
|
|||
# output of the "info" and "expand" commands
|
||||
|
||||
Running "ssh git@server info" or "ssh git@server expand" gives you certain
|
||||
output. This doclet describes the output; you're welcome to help me make it
|
||||
clearer :)
|
||||
|
||||
(Side note: if you installed using the "from-client" method, and you're the
|
||||
administrator, please replace `ssh git@server` with `ssh gitolite`, all
|
||||
through this document).
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_the_info_command">the "info" command</a>
|
||||
* <a href="#_interpreting_the_output">interpreting the output</a>
|
||||
* <a href="#_using_patterns_to_limit_output">using patterns to limit output</a>
|
||||
* <a href="#_side_note_openssh_5_6">side note: openssh 5.6</a>
|
||||
* <a href="#_the_expand_command">the "expand" command</a>
|
||||
|
||||
----
|
||||
|
||||
<a name="_the_info_command"></a>
|
||||
|
||||
### the "info" command
|
||||
|
||||
Usage:
|
||||
|
||||
ssh git@server info [optional_pattern [list of users]]
|
||||
|
||||
The "info" command shows you all the repos (and repo patterns) in the config
|
||||
file that you have been given any kind of access to. If you supply an
|
||||
optional pattern the output will be limited to repos matching that pattern.
|
||||
If you're an admin you can append a list of users to see their permissions
|
||||
instead of your own; in this mode the pattern is mandatory, even if you just
|
||||
use `.` to cheat.
|
||||
|
||||
Here is a sample output of the info command. There are 3 columns of
|
||||
permissions (create, read, and write) in the output, although the first column
|
||||
is often blank.
|
||||
|
||||
$ ssh git@server info
|
||||
hello sitaram, the gitolite version here is v1.5.5-24-g2b066fc
|
||||
the gitolite config gives you the following access:
|
||||
R W SecureBrowse
|
||||
R W anu-wsd
|
||||
R W entrans
|
||||
@R W git-notes
|
||||
@R W gitolite
|
||||
R W gitolite-admin
|
||||
R W indic_web_input
|
||||
@C R W private/sitaram/[\w.-]+
|
||||
R W proxy
|
||||
@C @R W public/sitaram/[\w.-]+
|
||||
@R_ @W_ testing
|
||||
R W vkc
|
||||
|
||||
<a name="_interpreting_the_output"></a>
|
||||
|
||||
#### interpreting the output
|
||||
|
||||
The meaning of C, R, and W are self-explanatory, but they may be prefixed or
|
||||
suffixed by a symbol:
|
||||
|
||||
* an `@` prefix means "@all" users have been given this permission
|
||||
|
||||
repo foo
|
||||
R = @all
|
||||
|
||||
* a `#` prefix means this user is a "superuser" (think root's shell prompt)
|
||||
and so has access to `@all` repos. Which means you'll see this prefix
|
||||
(or, in some cases, an `&`; see next bullet) for *all* the repos, or none
|
||||
of them
|
||||
|
||||
repo @all
|
||||
R = sitaram
|
||||
|
||||
* an `&` prefix means both of the above are true
|
||||
|
||||
The `_` suffix is special. This says the user has only implicit access (due
|
||||
to one of the `@all` uses), but no explicit access.
|
||||
|
||||
<a name="_using_patterns_to_limit_output"></a>
|
||||
|
||||
#### using patterns to limit output
|
||||
|
||||
Here are a couple of samples with optional patterns:
|
||||
|
||||
$ ssh git@server info git
|
||||
hello sitaram, the gitolite version here is v1.5.5-24-g2b066fc
|
||||
the gitolite config gives you the following access:
|
||||
@R W git-notes
|
||||
@R W gitolite
|
||||
R W gitolite-admin
|
||||
|
||||
$ ssh git@server info admin
|
||||
hello sitaram, the gitolite version here is v1.5.5-24-g2b066fc
|
||||
the gitolite config gives you the following access:
|
||||
R W gitolite-admin
|
||||
|
||||
In "big-config" mode (i.e., when `GL_BIG_CONFIG` is set) the pattern is
|
||||
**mandatory**. You can try and cheat the system by passing in a "." but
|
||||
gitolite truncates the output after 20 results to prevent a DOS. (This limit
|
||||
can be changed; see `$BIG_INFO_CAP` in [doc/gitolite.rc.mkd][rcdoc]).
|
||||
|
||||
[rcdoc]: http://sitaramc.github.com/gitolite/doc/gitolite.rc.html
|
||||
|
||||
The pattern is also mandatory when an admin wants to find out what access some
|
||||
*other* user has, which you may have guessed from the syntax in the "usage"
|
||||
line above.
|
||||
|
||||
<a name="_side_note_openssh_5_6"></a>
|
||||
|
||||
#### side note: openssh 5.6
|
||||
|
||||
It used to be that the gitolite documentation would say "just use `ssh
|
||||
git@server`" in the past, because gitolite defaults to the "info" command if
|
||||
no command is passed.
|
||||
|
||||
However, starting with [openssh 5.6][openssh56], this won't work. Openssh
|
||||
will now "Kill channel when pty allocation requests fail". This means that
|
||||
gitolite is not even invoked; you only get a message about pty allocation
|
||||
failure, followed by "connection closed".
|
||||
|
||||
So now you have to use an explicit "info" command, (`ssh git@server info`) or
|
||||
add the `-T` option to ssh (`ssh -T git@server`).
|
||||
|
||||
[openssh56]: http://www.openssh.org/txt/release-5.6
|
||||
|
||||
<a name="_the_expand_command"></a>
|
||||
|
||||
### the "expand" command
|
||||
|
||||
Usage:
|
||||
|
||||
ssh git@server expand [optional_pattern]
|
||||
|
||||
The "expand" command trawls through all the repositories on the server,
|
||||
limiting to repos matching the pattern you provide (default is all repos
|
||||
found).
|
||||
|
||||
For each repo found, it searches for it in the config -- either the actual
|
||||
repo entry (when the repo is not a wildcard repo), or an entry for the
|
||||
wildcard that matches it -- and reports permissions. It also takes into
|
||||
account extra permissions enabled by the `setperms` command (see
|
||||
doc/wildcard-repositories.mkd). It shows you the "creator" of the repo as
|
||||
an additional column, defaulting to `<gitolite>` if it was not a wildcard
|
||||
repo.
|
||||
|
||||
The limit of number of repos shown in big-config mode (20, by default)
|
||||
described earlier applies to the "expand" command also.
|
|
@ -1,88 +0,0 @@
|
|||
## avoiding the shell on the server
|
||||
|
||||
Gitolite now tries to prevent gitolite-admin push privileges from being used
|
||||
to obtain a shell on the server. This was not always the case (older gitolite
|
||||
did not make this distinction), but I've been moving towards this for a while
|
||||
now, and, while there could still be holes in that separation, they will be
|
||||
fixed as and when found.
|
||||
|
||||
Thus, settings that have security implications can be set only from the rc
|
||||
file, which needs to be edited directly on the server. And adding a new hook
|
||||
requires adding it to the *gitolite* clone and running easy install again, or
|
||||
gl-setup, if you used the server-side install method, both of which require
|
||||
shell access.
|
||||
|
||||
While this is great for my main target (corporate environments), some people
|
||||
don't like it. They want to do all of this from the *gitolite-admin* repo,
|
||||
because the security concern mentioned above does not bother them. They don't
|
||||
want to log on to the server to make a change in the rc file or don't want to
|
||||
run easy install to propagate a new set of hooks. In addition, they may want
|
||||
all of these animals versioned in the "gitolite-admin" repo itself, which
|
||||
certainly makes sense.
|
||||
|
||||
So here's how you might do that.
|
||||
|
||||
First, arrange to have all your special files added to the gitolite-admin
|
||||
repo. The best option is to keep all of this in a single subdirectory (let's
|
||||
call it "local" in our example). So your `~/.gitolite.rc` might go into
|
||||
`local/gitolite.rc`, and all your local hooks into `local/hooks` etc. Add
|
||||
them, commit, and push.
|
||||
|
||||
Note: do not create any top level directory called "conf", "contrib", "doc",
|
||||
"hooks", or "src" -- those names are used by gitolite itself.
|
||||
|
||||
Second, create a `post-update.secondary` hook and place it in the *gitolite*
|
||||
clone's `hooks/common` directory, containing the following code:
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
[ "$GL_REPO" = "gitolite-admin" ] || exit 0
|
||||
|
||||
[ -z "$GL_RC" ] && { echo "ENV GL_RC not set"; exit 1; }
|
||||
|
||||
GL_ADMINDIR=`$GL_BINDIR/gl-query-rc GL_ADMINDIR`
|
||||
|
||||
cp $GL_ADMINDIR/local/gitolite.rc $HOME/.gitolite.rc
|
||||
cp -a $GL_ADMINDIR/local/hooks/* $GL_ADMINDIR/hooks/common
|
||||
|
||||
/Full/Path/To/gl-install -q
|
||||
# the path should be the same as that for gl-auth-command in the
|
||||
# "command=" parameter of ~/.ssh/authorized_keys on the server
|
||||
|
||||
Don't forget to make it executable!
|
||||
|
||||
After this, run the upgrade instructions for the install method you used (just
|
||||
as if the `post-update.secondary` file you just created came from a gitolite
|
||||
software update).
|
||||
|
||||
All future changes to the rc file can be done via local/gitolite.rc in the
|
||||
admin repo, and hooks can be added to local/hooks.
|
||||
|
||||
**Note**: One quirk of how gitolite [propagates hooks][hpd] is that now this
|
||||
`post-update.secondary` exists in all normal repos also. Just ignore it; it's
|
||||
not doing any harm.
|
||||
|
||||
[hpd]: http://sitaramc.github.com/gitolite/doc/hook-propagation.html
|
||||
|
||||
**Warning**: Nothing in gitolite *removes* hooks, so if you delete (or even
|
||||
rename) a script, it still stays on the server -- you'll have to delete them
|
||||
manually from the server.
|
||||
|
||||
----
|
||||
|
||||
So what's this actually doing?
|
||||
|
||||
Well, first, note that `$GL_ADMINDIR` contains files from both gitolite
|
||||
itself, as well as from the gitolite-admin repo. "conf/VERSION", "src",
|
||||
"doc", and "hooks" come from gitolite itself, while the other 2 files in
|
||||
"conf", and all of "keydir" come from the gitolite-admin repo. ("logs"
|
||||
doesn't come from anywhere).
|
||||
|
||||
In addition, any other files in the "master" branch of the gitolite-admin repo
|
||||
get checked out here, which in this case would mean the entire "local/"
|
||||
hierarchy you created above.
|
||||
|
||||
Now, since the "hooks/common" directory is coming from gitolite itself,
|
||||
clearly this is where the internal "install" routine expects to find new or
|
||||
updated hooks to propagate. So you just copy your local hooks (in the
|
||||
"local/hooks" directory) to "hooks/common" and run the installer again. Done!
|
|
@ -1,497 +0,0 @@
|
|||
# ssh troubleshooting
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_common_ssh_asks_for_a_password">(common) ssh asks for a password</a>
|
||||
* <a href="#_problems_when_using_package_root_or_non_root_install_methods">problems when using package, root, or non-root install methods</a>
|
||||
* <a href="#_problems_when_using_the_from_client_install_method">problems when using the "from-client" install method</a>
|
||||
* <a href="#_sidebar_why_two_keys_on_client_for_the_admin">(sidebar) why two keys on client for the admin</a>
|
||||
* <a href="#_bypassing_gitolite_without_intending_to">bypassing gitolite without intending to</a>
|
||||
* <a href="#_basic_ssh_troubleshooting_for_the_admin">basic ssh troubleshooting for the admin</a>
|
||||
* <a href="#_problems_with_using_non_openssh_public_keys">problems with using non-openssh public keys</a>
|
||||
* <a href="#_windows_issues">windows issues</a>
|
||||
* <a href="#_details">details</a>
|
||||
* <a href="#_files_on_the_server">files on the server</a>
|
||||
* <a href="#_files_on_client">files on client</a>
|
||||
* <a href="#_some_other_tips_and_tricks">some other tips and tricks</a>
|
||||
* <a href="#_giving_shell_access_to_gitolite_users">giving shell access to gitolite users</a>
|
||||
* <a href="#_losing_your_admin_key">losing your admin key</a>
|
||||
* <a href="#_simulating_ssh_copy_id">simulating ssh-copy-id</a>
|
||||
|
||||
----
|
||||
|
||||
----
|
||||
|
||||
This document should help you troubleshoot ssh-related problems in installing
|
||||
and accessing gitolite.
|
||||
|
||||
**This is about all the help I can give you in terms of the ssh aspect of
|
||||
using gitolite. If you're installing gitolite, you're a "system admin", like
|
||||
it or not. Ssh is therefore a necessary skill. Please take the time to learn
|
||||
at least enough to get passwordless access working.**
|
||||
|
||||
**I have spent more than my share of time helping people debug their
|
||||
misconfigured servers, simply because they tried to blame gitolite for their
|
||||
troubles. This stops now. I'd rather spend time on actual gitolite features,
|
||||
code, and documentation.**
|
||||
|
||||
Other resources:
|
||||
|
||||
* people who think this is too hard should take a look at this
|
||||
[transcript][] to **see how simple it *actually* is**. This transcript
|
||||
uses the 'from-client' method of install.
|
||||
|
||||
* someone also wrote a tutorial, see [here][tut]. This uses the 'non-root'
|
||||
method of install, to provide a different perspective.
|
||||
|
||||
* I **strongly** recommend reading [doc/gitolite-and-ssh.mkd][doc9gas],
|
||||
which is a very detailed look at how gitolite uses ssh's features on the
|
||||
server side. Most people don't know ssh as well as they *think* they do;
|
||||
even if you don't have any problems right now, it's worth skimming over.
|
||||
|
||||
* there's a program called `sshkeys-lint` that you can run on your client to
|
||||
figure out which key is doing what. Run it without arguments to get help
|
||||
on how to run it and what inputs it needs.
|
||||
|
||||
----
|
||||
|
||||
<a name="_common_ssh_asks_for_a_password"></a>
|
||||
|
||||
### (common) ssh asks for a password
|
||||
|
||||
**NOTE**: This section should be useful to anyone trying to get password-less
|
||||
access working. It is **not** specific to gitolite.
|
||||
|
||||
You have generated a keypair on your workstation (`ssh-keygen`) and copied the
|
||||
public part of it (`~/.ssh/id_rsa.pub`, by default) to the server.
|
||||
|
||||
On the server you have appended this file to `~/.ssh/authorized_keys`. Or you
|
||||
ran something, like the `gl-setup` or `gl-easy-install` steps during a
|
||||
gitolite install, which should have done that for you.
|
||||
|
||||
You now expect to log in without having to type in a password, but when you
|
||||
try, you are being asked for a password.
|
||||
|
||||
This is a quick checklist:
|
||||
|
||||
* make sure you're being asked for a password and not a pass*phrase*. Do
|
||||
not confuse or mistake a prompt saying `Enter passphrase for key
|
||||
'/home/sitaram/.ssh/id_rsa':` for a password prompt from the remote
|
||||
server!
|
||||
|
||||
When you create an ssh keypair using `ssh-keygen`, you have the option of
|
||||
protecting it with a passphrase. When you subsequently use that keypair
|
||||
to access a remote host, your *local* ssh client needs to unlock the
|
||||
corresponding private key, and ssh will probably ask for the passphrase
|
||||
you set when you created the keypair.
|
||||
|
||||
You have two choices to avoid this prompt every time you try to use the
|
||||
private key. The first is to create keypairs *without* a passphrase (just
|
||||
hit enter when prompted for one). **Be sure to add a passphrase later,
|
||||
once everything is working, using `ssh-keygen -p`**.
|
||||
|
||||
The second is to use `ssh-agent` (or `keychain`, which in turn uses
|
||||
`ssh-agent`) or something like that to manage your keys. Other than
|
||||
discussing one more potential trouble-spot with ssh-agent (see below),
|
||||
further discussion of ssh-agent/keychain is out of scope of this document.
|
||||
|
||||
* make sure the right private key is being offered. Run ssh in very
|
||||
verbose mode and look for the word "Offering", like so:
|
||||
|
||||
ssh -vvvv user@host pwd 2> >(grep -i offer)
|
||||
|
||||
If some keys *are* being offered, but not the key that was supposed to be
|
||||
used, you may be using ssh-agent; see next bullet.
|
||||
|
||||
If you don't see any offers being made at all, then you probably don't
|
||||
have any protocol 2 keys in your `~/.ssh` (names are `id_rsa` or `id_dsa`,
|
||||
with corresponding `.pub` files).
|
||||
|
||||
* If `ssh-add -l` responds with either "The agent has no identities." or
|
||||
"Could not open a connection to your authentication agent.", then you can
|
||||
skip this bullet.
|
||||
|
||||
However, if `ssh-add -l` lists *any* keys at all, then something weird
|
||||
happens. Due to a quirk in ssh-agent, ssh will now *only* use one of
|
||||
those keys, *even if you explicitly ask* for some other key to be used.
|
||||
|
||||
In that case, add the key you want using `ssh-add ~/.ssh/mykey` and try
|
||||
the access again.
|
||||
|
||||
* ssh is very sensitive to permissions. An extremely conservative setup is
|
||||
given below, but be sure to do this on **both the client and the server**:
|
||||
|
||||
cd $HOME
|
||||
chmod go-rwx .
|
||||
chmod -R go-rwx .ssh
|
||||
|
||||
* actually, every component of the path to `~/.ssh/authorized_keys` all the
|
||||
way upto the root directory must be at least `chmod go-w`. So be sure to
|
||||
check `/` and `/home` also.
|
||||
|
||||
* while you're doing this, make sure the owner and group info for each of
|
||||
these components are correct. `ls -ald ~ ~/.ssh ~/.ssh/authorized_keys`
|
||||
will tell you what they are.
|
||||
|
||||
* if all that fails, log onto the server as root, `cd /var/log`, and look
|
||||
for a file called `auth.log` or `secure` or some such name. Look inside
|
||||
this file for messages matching the approximate time of your last attempt
|
||||
to login, to see if they tell you what is the problem.
|
||||
|
||||
----
|
||||
|
||||
<a name="_problems_when_using_package_root_or_non_root_install_methods"></a>
|
||||
|
||||
### problems when using package, root, or non-root install methods
|
||||
|
||||
This section applies if you installed using any of the [first 3 methods][o3]
|
||||
of install.
|
||||
|
||||
In these 3 modes, installation is done on the server, by logging in as some
|
||||
other user and doing and `su - git`. The admin's workstation has only one key
|
||||
that is known to the server's authkeys file, and this key invokes gitolite.
|
||||
**Note** that this key is not supposed to get you a shell; it is supposed to
|
||||
invoke gitolite.
|
||||
|
||||
As a result, it's a lot easier to debug. Just run `ssh git@server info`. If
|
||||
this get you the [gitolite version and access info][repout], everything is
|
||||
fine. If it asks you for a password, see the very first section of this
|
||||
document for help.
|
||||
|
||||
If it gets you the GNU info command output, you have shell access. This
|
||||
probably means you had passwordless shell access to the server *before* you
|
||||
were added as a gitolite user, and you sent that same key to your gitolite
|
||||
admin to include in the admin repo. This won't work -- the same key appears
|
||||
twice in the authkeys file now, and since the ssh server will always use the
|
||||
first match, the second occurrence (which invokes gitolite) is ignored.
|
||||
|
||||
You'll have to (create and) use a different keypair for gitolite access.
|
||||
|
||||
<a name="_problems_when_using_the_from_client_install_method"></a>
|
||||
|
||||
### problems when using the "from-client" install method
|
||||
|
||||
This section applies if you installed using the [from-client method][fc].
|
||||
|
||||
This method of install is unique in that the admin will have 2 distinct keys
|
||||
to access the server. The default key (`~/.ssh/id_rsa`) is used to get a
|
||||
shell prompt and to run commands; for example, `gl-easy-install` uses this key
|
||||
to do all its server-side work.
|
||||
|
||||
In addition, there is a named key created just to invoke gitolite instead of
|
||||
starting a shell. The name is whatever you gave as the third argument to the
|
||||
`gl-easy-install` command (for example, `~/.ssh/sitaram.pub` in my case).
|
||||
|
||||
Finally, a `host gitolite` para is added to `~/.ssh/config`:
|
||||
|
||||
host gitolite
|
||||
user git
|
||||
hostname server
|
||||
identityfile ~/.ssh/sitaram
|
||||
|
||||
so that you can use `gitolite:reponame` as the URL to make ssh use the named
|
||||
key.
|
||||
|
||||
All this applies *only* to the admin. Normal users will only have one key and
|
||||
do not need any of this.
|
||||
|
||||
<a name="twokeys"></a>
|
||||
|
||||
<a name="_sidebar_why_two_keys_on_client_for_the_admin"></a>
|
||||
|
||||
#### (sidebar) why two keys on client for the admin
|
||||
|
||||
> There are two types of access the admin will make to the server: a normal
|
||||
> login, to get a shell prompt, and gitolite access (clone/fetch/push etc).
|
||||
> The first access needs an authkeys line *without* any "command="
|
||||
> restrictions, while the second requires a line *with* such a restriction.
|
||||
|
||||
> And we can't use the same key for both because there is no way to
|
||||
> disambiguate them; the ssh server will always (*always*) pick the first
|
||||
> one in sequence when the key is offered by the ssh client.
|
||||
|
||||
> So the next question is usually "I have other ways to get a shell on that
|
||||
> account (like `su - git` from some other account), so why do I need a key
|
||||
> for shell access at all?"
|
||||
|
||||
> The answer to this is that the "easy install" script, being written for
|
||||
> the most general case, needs shell access via ssh to do its stuff. If you
|
||||
> have access otherwise, you really should use one of the other 3 install
|
||||
> methods to install gitolite. Please see the [install doc][install] for
|
||||
> details.
|
||||
|
||||
<a name="_bypassing_gitolite_without_intending_to"></a>
|
||||
|
||||
#### bypassing gitolite without intending to
|
||||
|
||||
These problems happen to the person who has **utterly failed** to read/heed
|
||||
the message that shows up at the end of running the `gl-easy-install` command.
|
||||
Both these problems are caused by using the wrong key, thus **bypassing
|
||||
gitolite completely**:
|
||||
|
||||
* you get `fatal: 'reponame' does not appear to be a git repository`, and
|
||||
yet you are sure 'reponame' exists, you haven't mis-spelled it, etc.
|
||||
|
||||
* you are able to clone repositories but are unable to push changes back
|
||||
(the error complains about the `GL_RC` environment variable not being set,
|
||||
and the `hooks/update` failing in some way).
|
||||
|
||||
Let us recap the message that appears on a successful run of the "easy-install"
|
||||
program; it looks something like this (with suitable values substituted for
|
||||
`<user>`, `<server>`, and `<port>`):
|
||||
|
||||
IMPORTANT NOTE -- PLEASE READ!!!
|
||||
*Your* URL for cloning any repo on this server will be
|
||||
gitolite:reponame.git
|
||||
|
||||
*Other* users you set up will have to use
|
||||
<user>@<server>:reponame.git
|
||||
However, if your server uses a non-standard ssh port, they should use
|
||||
ssh://<user>@<server>:<port>/reponame.git
|
||||
|
||||
If this is your first time installing gitolite, please also:
|
||||
tail -31 src/gl-easy-install
|
||||
for next steps.
|
||||
|
||||
The first error above happens if you use `git@server:reponame` instead of
|
||||
`gitolite:reponame`. All your repos are actually in a subdirectory pointed to
|
||||
by `$REPO_BASE` in the rc file (default: `repositories`). Gitolite internally
|
||||
prefixes this before calling the actual git command you invoked, but since
|
||||
you're bypassing gitolite completely, this prefixing does not happen, and so
|
||||
the repo is not found.
|
||||
|
||||
The second error happens if you use `git@server:repositories/reponame.git`
|
||||
(assuming default `$REPO_BASE` setting) -- that is, you used the full unix
|
||||
path. Since the "prefixing" mentioned above is not required, the shell finds
|
||||
the repo and clones ok. But when you push, gitolite's **update hook** kicks
|
||||
in, and fails to run because some of the environment variables it is
|
||||
expecting are not present.
|
||||
|
||||
<a name="_basic_ssh_troubleshooting_for_the_admin"></a>
|
||||
|
||||
#### basic ssh troubleshooting for the admin
|
||||
|
||||
Otherwise, run these checks:
|
||||
|
||||
1. `ssh git@server` should get you a command line *without* asking for a
|
||||
password.
|
||||
|
||||
If it asks you for a password, then your `id_rsa` keypair changed after
|
||||
you ran the easy install, or someone fiddled with the
|
||||
`~/.ssh/authorized_keys` file on the server.
|
||||
|
||||
If it prints the gitolite version and access info (see
|
||||
[doc/report-output.mkd][repout]), you managed to overwrite the `id_rsa`
|
||||
keypair with the `sitaram` keypair, or something equally weird. This is
|
||||
because a gitolite key, when used without any actual command, defaults to
|
||||
running gitolite's internal "info" command.
|
||||
|
||||
**NOTE** starting with [version 5.6][openssh56], openssh will "Kill
|
||||
channel when pty allocation requests fail". This means that, instead of
|
||||
seeing the version and access info as described above, you may only get a
|
||||
message about pty allocation failure, followed by "connection closed".
|
||||
|
||||
2. `ssh gitolite info` should print some gitolite version and access info.
|
||||
If you get the output of the GNU info command instead, you probably reused
|
||||
your `id_rsa` keypair as your `sitaram` keypair, or overwrote the
|
||||
`sitaram` keypair with the `id_rsa` keypair.
|
||||
|
||||
There are many ways to fix this, depending on where and what the damage is.
|
||||
The most generic way (and therefore time-taking) is to re-install gitolite
|
||||
from scratch:
|
||||
|
||||
* make a backup of your gitolite-admin repo clone somewhere (basically your
|
||||
`keydir/*.pub` and your `conf/gitolite.conf`). If necessary get these
|
||||
files from the server's `~/.gitolite` directory.
|
||||
* log on to the server somehow (using some other account, using a password,
|
||||
su-ing in, etc) and delete `~/.ssh/authorized_keys`. Rename or move aside
|
||||
`~/.gitolite` so that also looks like it is missing.
|
||||
* back on your workstation, make sure you have 2 keypairs (`id_rsa` and
|
||||
`sitaram`, along with corresponding `.pub` files). Create them if needed.
|
||||
Also make sure they are *different* and not a copy of each other :-)
|
||||
* install gitolite normally:
|
||||
* run `ssh-copy-id -i ~/.ssh/id_rsa.pub git@server` to get passwordless
|
||||
access to the server. (Mac users may have to do this step manually)
|
||||
* make sure `ssh git@server pwd` prints the `$HOME` of `git@server`
|
||||
**without** asking for a password. Do not proceed till this works.
|
||||
* run easy install again, (in my case: `cd gitolite-source;
|
||||
src/gl-easy-install -q git server sitaram`)
|
||||
* go to your gitolite-admin repo clone, and copy `conf/gitolite.conf` and
|
||||
`keydir/*.pub` from your backup to this directory
|
||||
* copy (be sure to overwrite!) `~/.ssh/sitaram.pub` also to keydir
|
||||
* now `git add keydir; git commit; git push -f`
|
||||
|
||||
That's a long sequence but it should work.
|
||||
|
||||
<a name="_problems_with_using_non_openssh_public_keys"></a>
|
||||
|
||||
### problems with using non-openssh public keys
|
||||
|
||||
Gitolite accepts public keys only in openssh format. Trying to use an "ssh2"
|
||||
key (used by proprietary SSH software) results in:
|
||||
|
||||
WARNING: a pubkey file can only have one line (key); ignoring YourName.pub
|
||||
|
||||
To convert ssh2-compatible keys to openssh run:
|
||||
|
||||
ssh-keygen -i -f /tmp/ssh2/YourName.pub > /tmp/openssh/YourName.pub
|
||||
|
||||
then use the resulting pubkey as you normally would in gitolite.
|
||||
|
||||
<a name="_windows_issues"></a>
|
||||
|
||||
### windows issues
|
||||
|
||||
On windows, I have only used msysgit, and the openssh that comes with it.
|
||||
Over time, I have grown to distrust putty/plink due to the number of people
|
||||
who seem to have trouble when those beasts are involved (I myself have never
|
||||
used them for any kind of git access). If you have unusual ssh problems that
|
||||
just don't seem to have any explanation, try removing all traces of
|
||||
putty/plink, including environment variables, etc., and then try again.
|
||||
|
||||
If you can offer an *authoritative* account of the complications involved, and
|
||||
how to resolve them and get things working, I'd be happy to credit you and
|
||||
include it, either directly here if it is short enough or just an external
|
||||
link, or in contrib/ if it's a longer piece of text.
|
||||
|
||||
<a name="_details"></a>
|
||||
|
||||
### details
|
||||
|
||||
Here's how it all hangs together.
|
||||
|
||||
<a name="_files_on_the_server"></a>
|
||||
|
||||
#### files on the server
|
||||
|
||||
* the authkeys file; this contains one line containing the pubkey of each
|
||||
user who is permitted to login without a password.
|
||||
|
||||
Pubkey lines that give shell access look like this:
|
||||
|
||||
ssh-rsa AAAAB3NzaC[snip]uPjrUiAUew== /home/sitaram/.ssh/id_rsa
|
||||
|
||||
On a typical server there will be only one or two of these lines.
|
||||
|
||||
Note that the last bit (`/home/sitaram/.ssh/id_rsa`) is purely a *comment*
|
||||
field and can be anything. Also, the actual lines are much longer, about
|
||||
400 characters; I snipped 'em in the middle, as you can see.
|
||||
|
||||
In contrast, pubkey lines that give access to git repos hosted by gitolite
|
||||
look like this:
|
||||
|
||||
command="[some path]src/gl-auth-command sitaram",[some restrictions] ssh-rsa AAAAB3NzaC[snip]s18OnB42oQ== sitaram@sita-lt
|
||||
|
||||
You will have many more of these lines -- one for every pubkey file in
|
||||
`keydir/` of your gitolite-admin repo, with the corresponding username in
|
||||
place of "sitaram" in the example above.
|
||||
|
||||
The "command=" at the beginning ensures that when someone with the
|
||||
corresponding private key logs in, they don't get a shell. Instead, the
|
||||
`gl-auth-command` program is run, and (in this example) is given the
|
||||
argument `sitaram`. This is how gitolite is invoked, (and is told the
|
||||
user logging in is "sitaram").
|
||||
|
||||
<a name="_files_on_client"></a>
|
||||
|
||||
#### files on client
|
||||
|
||||
* default keypair; used to get shell access to servers. You would have
|
||||
copied this pubkey to the gitolite server in order to log in without a
|
||||
password. (On Linux systems you may have used `ssh-copy-id` to do that).
|
||||
You would have done this *before* you ran the easy install script, because
|
||||
otherwise easy install won't run!
|
||||
|
||||
~/.ssh/id_rsa
|
||||
~/.ssh/id_rsa.pub
|
||||
|
||||
* gitolite keypair; the "sitaram" in this is the 3rd argument to the
|
||||
`src/gl-easy-install` command you ran; the easy install script does the
|
||||
rest
|
||||
|
||||
~/.ssh/sitaram
|
||||
~/.ssh/sitaram.pub
|
||||
|
||||
* config file; this file has an entry for gitolite access if you install
|
||||
usine the "from-client" method. (See above for example "host gitolite"
|
||||
para in the ssh config file).
|
||||
|
||||
This is needed because this is the only way to force git to use a
|
||||
non-default keypair (unlike command line ssh, which can be given the `-i
|
||||
~/.ssh/sitaram` flag to do so).
|
||||
|
||||
<a name="_some_other_tips_and_tricks"></a>
|
||||
|
||||
### some other tips and tricks
|
||||
|
||||
<a name="_giving_shell_access_to_gitolite_users"></a>
|
||||
|
||||
#### giving shell access to gitolite users
|
||||
|
||||
We've managed (thanks to an idea from Jesse Keating) to make it possible for a
|
||||
single key to allow both gitolite access *and* shell access.
|
||||
|
||||
This is done by copying the pubkey (to which you want to give shell access) to
|
||||
the server and running either
|
||||
|
||||
cd $HOME/.gitolite # assuming default $GL_ADMINDIR in ~/.gitolite.rc
|
||||
src/gl-tool shell-add ~/foo.pub
|
||||
|
||||
or
|
||||
|
||||
gl-tool shell-add ~/foo.pub
|
||||
|
||||
The first method is applicable if you installed using the **from-client**
|
||||
method, while the second method is for any of the other three (see
|
||||
doc/1-INSTALL.mkd, section on "install methods", for more on this)
|
||||
|
||||
**IMPORTANT UPGRADE NOTE**: previous implementations of this feature were
|
||||
crap. There was no easy/elegant way to ensure that someone who had repo admin
|
||||
access would not manage to get himself shell access.
|
||||
|
||||
Giving someone shell access requires that you should have shell access in the
|
||||
first place, so the simplest way is to enable it from the server side only.
|
||||
|
||||
<a name="_losing_your_admin_key"></a>
|
||||
|
||||
#### losing your admin key
|
||||
|
||||
If you lost the admin key, and need to re-establish ownership of the
|
||||
gitolite-admin repository with a fresh key, take a look at the
|
||||
`src/gl-dont-panic` program. You will need shell access to the server of
|
||||
course. Run it without arguments to get instructions.
|
||||
|
||||
<a name="_simulating_ssh_copy_id"></a>
|
||||
|
||||
#### simulating ssh-copy-id
|
||||
|
||||
don't have `ssh-copy-id`? This is broadly what that command does, if you want
|
||||
to replicate it manually. The input is your pubkey, typically
|
||||
`~/.ssh/id_rsa.pub` from your client/workstation.
|
||||
|
||||
* it copies it to the server as some file
|
||||
|
||||
* it appends that file to `~/.ssh/authorized_keys` on the server
|
||||
(creating it if it doesn't already exist)
|
||||
|
||||
* it then makes sure that all these files/directories have go-w perms
|
||||
set (assuming user is "git"):
|
||||
|
||||
/home/git/.ssh/authorized_keys
|
||||
/home/git/.ssh
|
||||
/home/git
|
||||
|
||||
[Actually, `sshd` requires that even directories *above* `~` (`/`, `/home`,
|
||||
typically) also must be `go-w`, but that needs root. And typically
|
||||
they're already set that way anyway. (Or if they're not, you've got
|
||||
bigger problems than gitolite install not working!)]
|
||||
|
||||
[doc9gas]: http://sitaramc.github.com/gitolite/doc/gitolite-and-ssh.html
|
||||
[install]: http://sitaramc.github.com/gitolite/doc/1-INSTALL.html
|
||||
[o3]: http://sitaramc.github.com/gitolite/doc/1-INSTALL.html#methods
|
||||
[fc]: http://sitaramc.github.com/gitolite/doc/1-INSTALL.html#fc
|
||||
[urls]: http://sitaramc.github.com/gitolite/doc/1-INSTALL.html#URLs_for_gitolite_managed_repos
|
||||
[repout]: http://sitaramc.github.com/gitolite/doc/report-output.html
|
||||
[transcript]: http://sitaramc.github.com/gitolite/doc/install-transcript.html
|
||||
[openssh56]: http://www.openssh.org/txt/release-5.6
|
||||
[tut]: http://sites.google.com/site/senawario/home/gitolite-tutorial
|
|
@ -1,67 +0,0 @@
|
|||
## uninstalling gitolite
|
||||
|
||||
Sometimes you might find gitolite is overkill -- you have only one user
|
||||
(yourself) pushing maybe. Or maybe gitolite is just not enough -- you want a
|
||||
web-based front end that users can use to manage their keys themselves, etc.,
|
||||
in which case you'd probably switch to [github][g1], [girocco][g2],
|
||||
[indefero][g3] or [gitorious][g4]. [Gerrit][g5] is quite nice too, if you
|
||||
want collaborative code review there's nothing like it. Either way, you'd
|
||||
like to uninstall gitolite.
|
||||
|
||||
[g1]: http://github.com
|
||||
[g2]: http://repo.or.cz/w/girocco.git
|
||||
[g3]: http://www.indefero.net/
|
||||
[g4]: http://gitorious.com/
|
||||
[g5]: http://code.google.com/p/gerrit/
|
||||
|
||||
Uninstalling gitolite is fairly easy, although it is manual. (We'll assume
|
||||
`$REPO_BASE` in the rc file was left at its default of `~/repositories`; if
|
||||
not, adjust accordingly):
|
||||
|
||||
**server side tasks**
|
||||
|
||||
* edit `~/.ssh/authorized_keys` and delete the `# gitolite start` and `#
|
||||
gitolite end` markers and all the lines between them. This will prevent
|
||||
any of your users from attempting a push while you are doing this.
|
||||
|
||||
If you are the only user, and/or *need* one or more of those keys to
|
||||
continue to access this account (like if one of them is your laptop or
|
||||
your home desktop etc.) then instead of deleting the line you can just
|
||||
delete everything upto but not including the words "ssh-rsa" or "ssh-dss".
|
||||
|
||||
* Now remove (or move aside or rename to something else if you're paranoid)
|
||||
the following files and directories.
|
||||
|
||||
~/.gitolite
|
||||
~/.gitolite.rc
|
||||
~/repositories/gitolite-admin.git
|
||||
|
||||
* You can remove all of `~/repositories` if you have not really started
|
||||
using gitolite properly yet; that's your choice.
|
||||
|
||||
If you *do* need to preserve the other repos and continue to use them,
|
||||
remove all the `update` hooks that git installs on each repository. The
|
||||
easiest way is:
|
||||
|
||||
find ~/repositories -wholename "*.git/hooks/update" | xargs rm -f
|
||||
|
||||
but you can do it manually if you want to be careful.
|
||||
|
||||
**client side tasks**
|
||||
|
||||
* Any remote users that still have access must update their clone's remote
|
||||
URLs (edit `.git/config` in the repo) to prefix `repositories/` before the
|
||||
actual path used, in order for the remote to still work. This is because
|
||||
you'll now be accessing it through plain ssh, which means you have to give
|
||||
it the full path.
|
||||
|
||||
* Finally, you as the gitolite admin will probably have a host stanza for
|
||||
"gitolite" in your *client*'s `~/.ssh/config`. Find and delete lines that
|
||||
look like this:
|
||||
|
||||
host gitolite
|
||||
user git
|
||||
hostname your.server
|
||||
port 22
|
||||
identityfile ~/.ssh/your-gitolite-admin-username
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
# who uses gitolite
|
||||
|
||||
> > If you're using gitolite and find it very useful in some way, I would
|
||||
> > love to describe your use of it or add a link to your own description
|
||||
> > of it here. Of course, you can anonymise it as much as you need to.
|
||||
|
||||
The **Fedora Project** controls access to over 10,000 package management
|
||||
repositories accessed by over 1,000 package maintainers [using
|
||||
gitolite][fedora]. This is probably the largest *confirmed* gitolite
|
||||
installation anywhere. The whole [big-config][bc] thing was initially done
|
||||
for them (their config file was so big that without the big-config changes
|
||||
gitolite would just run out of memory and die!).
|
||||
|
||||
[fedora]: http://lists.fedoraproject.org/pipermail/devel-announce/2010-July/000647.html
|
||||
[bc]: http://sitaramc.github.com/gitolite/doc/big-config.html
|
||||
|
||||
The **KDE project** [uses][kde] gitolite (in combination with redmine for
|
||||
issue tracking and reviewboard for code review). Apart from the usual access
|
||||
control, the KDE folks are heavy users of the "ad hoc repo creation" features
|
||||
enabled by wildrepos and the accompanying commands. Several of the changes to
|
||||
the "admin defined commands" were also inspired by KDE's needs. See [section
|
||||
5][s5] and [section 6][s6] of the above linked page for details.
|
||||
|
||||
[kde]: http://community.kde.org/Sysadmin/GitKdeOrgManual
|
||||
[s5]: http://community.kde.org/Sysadmin/GitKdeOrgManual#Server-side_commands
|
||||
[s6]: http://community.kde.org/Sysadmin/GitKdeOrgManual#Personal_repositories
|
||||
[kdera]: http://permalink.gmane.org/gmane.comp.kde.scm-interest/1437
|
||||
|
||||
**Prof. Hiren Patel** of the University of Waterloo is responsible for the
|
||||
existence of the fairly popular "[wildrepos][wild]" feature. The
|
||||
documentation was pretty much written with his use case in mind, but of course
|
||||
it turns out to be useful for a lot of people, as you can see from the
|
||||
previous para on KDE's use of gitolite.
|
||||
|
||||
In fact, he surprised the heck out of me recently by saying that if it hadn't
|
||||
been for this feature, he might not have used git itself -- which is a pretty
|
||||
serious compliment if you think about the magnitude of the git project and my
|
||||
little one-man show!
|
||||
|
||||
He explains his use of it [here][hiren].
|
||||
|
||||
[wild]: http://sitaramc.github.com/gitolite/doc/wildcard-repositories.html
|
||||
[hiren]: http://ece.uwaterloo.ca/~hdpatel/uwhtml/?p=470
|
||||
|
||||
**Gentoo Linux** has [just moved][gentoo1] their git repositories from gitosis
|
||||
to gitolite. There are about 200 repositories, some of them are the so called
|
||||
[overlays][gentoo2], official and unofficial/user overlays, plus several
|
||||
developer and project repositories, used by more than 1000 people. That number
|
||||
will be increased in the near future, as they are going to migrate some of
|
||||
their CVS/SVN repositories there, plus they are offering overlays hosting for
|
||||
users as well.
|
||||
|
||||
[gentoo1]: http://archives.gentoo.org/gentoo-dev/msg_2812c9b9e768f64b46360ab17b9d0024.xml
|
||||
[gentoo2]: http://www.gentoo.org/proj/en/overlays/
|
||||
|
||||
**Nokia MeeGo** uses Gitolite internally, and has also contributed LDAP
|
||||
specific code (see [contrib/ldap][ldap] directory for details).
|
||||
|
||||
[ldap]: http://github.com/sitaramc/gitolite/blob/pu/contrib/ldap
|
|
@ -1,346 +0,0 @@
|
|||
## repositories named with wildcards
|
||||
|
||||
***IMPORTANT NOTE***:
|
||||
|
||||
This feature may be somewhat "brittle" in terms of security. Creating
|
||||
repositories based on wild cards, giving "ownership" to the specific user who
|
||||
created it, allowing him/her to hand out permissions to other users to
|
||||
collaborate, all these are possible. And any of these could have a bug in it.
|
||||
I haven't found any yet, but that doesn't mean there aren't any.
|
||||
|
||||
----
|
||||
|
||||
In this document:
|
||||
|
||||
* <a href="#_quick_introduction">quick introduction</a>
|
||||
* <a href="#_rc_file_setting_required">rc file setting required</a>
|
||||
* <a href="#_examples_of_wildcard_repos">examples of wildcard repos</a>
|
||||
* <a href="#_wildcard_repos_with_creator_name_in_them">wildcard repos with creator name in them</a>
|
||||
* <a href="#_wildcard_repos_without_creator_name_in_them">wildcard repos without creator name in them</a>
|
||||
* <a href="#_side_note_valid_regexes">side-note: valid regexes</a>
|
||||
* <a href="#_side_note_line_anchored_regexes">side-note: line-anchored regexes</a>
|
||||
* <a href="#_contrast_with_refexes">contrast with refexes</a>
|
||||
* <a href="#_handing_out_rights_to_wildcard_matched_repos">handing out rights to wildcard-matched repos</a>
|
||||
* <a href="#_admin_adding_other_categories_than_READERS_and_WRITERS">(admin) adding other categories than READERS and WRITERS</a>
|
||||
* <a href="#_IMPORTANT_WARNING_ABOUT_THIS_FEATURE_">**IMPORTANT WARNING ABOUT THIS FEATURE**</a>
|
||||
* <a href="#_setting_a_gitweb_description_for_a_wildcard_matched_repo">setting a gitweb description for a wildcard-matched repo</a>
|
||||
* <a href="#_reporting">reporting</a>
|
||||
* <a href="#_how_it_actually_works">how it actually works</a>
|
||||
|
||||
----
|
||||
|
||||
This document is mostly "by example".
|
||||
|
||||
----
|
||||
|
||||
<a name="_quick_introduction"></a>
|
||||
|
||||
### quick introduction
|
||||
|
||||
The wildrepos feature allows you to specify access control rules using regular
|
||||
expression patterns, so you can have many actual repos being served by a
|
||||
single set of rules in the config file. The regex pattern can also include
|
||||
the word `CREATOR` in it, allowing you to parametrise the name of the user
|
||||
creating the repo. The examples below will make this clearer.
|
||||
|
||||
<a name="_rc_file_setting_required"></a>
|
||||
|
||||
### rc file setting required
|
||||
|
||||
This feature requires that you set `$GL_WILDREPOS` to "1" in `~/.gitolite.rc`
|
||||
on the server. Please search for that variable in `doc/gitolite.rc.mkd`
|
||||
for more information on this.
|
||||
|
||||
<a name="_examples_of_wildcard_repos"></a>
|
||||
|
||||
### examples of wildcard repos
|
||||
|
||||
As the introduction said, you can include the word `CREATOR` in the regex
|
||||
pattern, though it is not mandatory. We'll look at examples of both types of
|
||||
usage.
|
||||
|
||||
Which of these alternatives you choose depends on your needs, and the social
|
||||
aspects of your environment. Including the creator name in the pattern keeps
|
||||
users rigidly separated from each others repos, and is good for a largely
|
||||
autonomous collection of users with a high probability of repo name clashes.
|
||||
|
||||
Omitting the creator name from the pattern puts the repos in a common
|
||||
namespace, and is suitable for environments where it is not very important to
|
||||
keep track of who actually created the repo (except for granting access), but
|
||||
needs more communication / co-operation among the users to avoid repo name
|
||||
clashes.
|
||||
|
||||
<a name="_wildcard_repos_with_creator_name_in_them"></a>
|
||||
|
||||
#### wildcard repos with creator name in them
|
||||
|
||||
Here's an example snippet:
|
||||
|
||||
@prof = u1
|
||||
@TAs = u2 u3
|
||||
@students = u4 u5 u6
|
||||
|
||||
repo assignments/CREATOR/a[0-9][0-9]
|
||||
C = @students
|
||||
RW+ = CREATOR
|
||||
RW = WRITERS @TAs
|
||||
R = READERS @prof
|
||||
|
||||
For now, ignore the special usernames READERS and WRITERS, and just create a
|
||||
new repo, as user "u4" (a student):
|
||||
|
||||
$ git clone git@server:assignments/u4/a12
|
||||
Initialized empty Git repository in /home/sitaram/t/a12/.git/
|
||||
Initialized empty Git repository in /home/gitolite/repositories/assignments/u4/a12.git/
|
||||
warning: You appear to have cloned an empty repository.
|
||||
|
||||
Notice the *two* empty repo inits, and the order in which they occur ;-)
|
||||
|
||||
<a name="_wildcard_repos_without_creator_name_in_them"></a>
|
||||
|
||||
#### wildcard repos without creator name in them
|
||||
|
||||
Here's how the same example would look if you did not want the CREATOR's name
|
||||
to be part of the actual repo name.
|
||||
|
||||
repo assignments/a[0-9][0-9]
|
||||
C = @students
|
||||
RW+ = CREATOR
|
||||
RW = WRITERS @TAs
|
||||
R = READERS @prof
|
||||
|
||||
We haven't changed anything except the repo name pattern. This means that the
|
||||
first student that creates, say, `assignments/a12` becomes the owner.
|
||||
Mistakes (such as claiming a12 instead of a13) need to be rectified by an
|
||||
admin logging on to the back end, though it's not too difficult.
|
||||
|
||||
You could also repace the C line like this:
|
||||
|
||||
C = @TAs
|
||||
|
||||
and have a TA create the repos in advance.
|
||||
|
||||
In either case, they could then use the `setperms` feature to specify which
|
||||
users are "READERS" and which are "WRITERS". See later for details.
|
||||
|
||||
<a name="_side_note_valid_regexes"></a>
|
||||
|
||||
### side-note: valid regexes
|
||||
|
||||
Due to projects like `gtk+`, the `+` character is now considered a valid
|
||||
character for an *ordinary* repo. Therefore, a pattern like `foo/.+` does not
|
||||
look like a regex to gitolite. Use `foo/..*` if you want that.
|
||||
|
||||
Also, `..*` by itself is not considered a valid repo pattern. Try
|
||||
`[a-zA-Z0-9].*`.
|
||||
|
||||
<a name="_side_note_line_anchored_regexes"></a>
|
||||
|
||||
### side-note: line-anchored regexes
|
||||
|
||||
A regex like
|
||||
|
||||
repo assignments/S[0-9]+/A[0-9]+
|
||||
|
||||
would match `assignments/S02/A37`. It will not match `assignments/S02/ABC`,
|
||||
or `assignments/S02/a37`, obviously.
|
||||
|
||||
But you may be surprised to find that it does not match even
|
||||
`assignments/S02/A37/B99`. This is because internally, gitolite
|
||||
*line-anchors* the given regex; so that regex actually becomes
|
||||
`^assignments/S[0-9]+/A[0-9]+$` -- notice the line beginning and ending
|
||||
metacharacters.
|
||||
|
||||
<a name="_contrast_with_refexes"></a>
|
||||
|
||||
#### contrast with refexes
|
||||
|
||||
Just for interest, note that this is in contrast to the refexes for the normal
|
||||
"branch" permissions, as described in `doc/gitolite.conf.mkd` and elsewhere.
|
||||
These "refexes" are only anchored at the start; a pattern like
|
||||
`refs/heads/master` actually can match `refs/heads/master01/bar` as well, even
|
||||
if no one will actually push such a branch! You can anchor both sides if you
|
||||
really care, by using `master$` instead of `master`, but that is *not* the
|
||||
default for refexes.
|
||||
|
||||
<a name="_handing_out_rights_to_wildcard_matched_repos"></a>
|
||||
|
||||
### handing out rights to wildcard-matched repos
|
||||
|
||||
In the examples above, we saw two special "user" names: READERS and WRITERS.
|
||||
The permissions they have are controlled by the config file, but ***who is
|
||||
part of this list*** is controlled by the person who created the repository.
|
||||
|
||||
The use case is that, although our toy example has only 3 students, in reality
|
||||
there will be a few dozen, but each assignment will be worked on only by a
|
||||
handful from among those. This allows the creator to take ad hoc sets of
|
||||
users from among the actual users in the system, and place them into one of
|
||||
two categories (in this example, READERS and WRITERS respectively). In theory
|
||||
you could do the same thing by creating lots of little "assignment-NN" groups
|
||||
in the config file but that may be a little too cumbersome for non-secret
|
||||
environments.
|
||||
|
||||
Create a small text file that contains the permissions you desire:
|
||||
|
||||
$ cat > myperms
|
||||
READERS u5
|
||||
WRITERS u6
|
||||
(hit ctrl-d here)
|
||||
|
||||
...and use the new "setperms" command to set permissions for your repo:
|
||||
|
||||
$ ssh git@server setperms assignments/u4/a12 < myperms
|
||||
New perms are:
|
||||
READERS u5
|
||||
WRITERS u6
|
||||
|
||||
'setperms' will helpfully print what the new permissions are but you can also
|
||||
use 'getperms' to check:
|
||||
|
||||
$ ssh git@server getperms assignments/u4/a12
|
||||
READERS u5
|
||||
WRITERS u6
|
||||
|
||||
The following points are important:
|
||||
|
||||
* note the syntax of the commands; it's not a "git" command, and there's no
|
||||
`:` like in a repo URL. The first space-separated word is READERS or
|
||||
WRITERS, and the rest are simple usernames.
|
||||
|
||||
<a name="_admin_adding_other_categories_than_READERS_and_WRITERS"></a>
|
||||
|
||||
### (admin) adding other categories than READERS and WRITERS
|
||||
|
||||
Let's say your needs are more complex and you need more categories of users.
|
||||
For example, you might like to have a setup where only a tester can update
|
||||
tags, and only a manager can delete branches:
|
||||
|
||||
repo foo/..*
|
||||
C = u1
|
||||
RW refs/tags/ = TESTERS
|
||||
- refs/tags/ = @all
|
||||
RW+ = WRITERS
|
||||
RW = INTERNS
|
||||
R = READERS
|
||||
RW+D = MANAGERS
|
||||
|
||||
As you can see, someone pre-creates the repo and assigns rights to various
|
||||
people, say by sending something like this to `setperms`:
|
||||
|
||||
READERS wally
|
||||
WRITERS dilbert alice
|
||||
MANAGERS phb
|
||||
INTERNS ashok
|
||||
TESTERS ashok
|
||||
|
||||
You can enable this by setting the `GL_WILDREPOS_PERM_CATS` variable in the rc
|
||||
file. The rc file documentation (`doc/gitolite.rc.mkd`) explains how.
|
||||
|
||||
<a name="_IMPORTANT_WARNING_ABOUT_THIS_FEATURE_"></a>
|
||||
|
||||
#### **IMPORTANT WARNING ABOUT THIS FEATURE**
|
||||
|
||||
Please make sure that none of the category names conflict with any of the
|
||||
**usernames** in the system. For example, if you have a user called "foo",
|
||||
make sure you do not include "foo" as a valid category in
|
||||
`$GL_WILDREPOS_PERM_CATS`.
|
||||
|
||||
You can keep things sane by using UPPERCASE names for categories, while
|
||||
keeping all your usernames lowercase; then you don't have to worry about this
|
||||
problem.
|
||||
|
||||
<a name="_setting_a_gitweb_description_for_a_wildcard_matched_repo"></a>
|
||||
|
||||
### setting a gitweb description for a wildcard-matched repo
|
||||
|
||||
Similar to the getperms/setperms commands, there are the getdesc/setdesc
|
||||
commands, thanks to Teemu.
|
||||
|
||||
<a name="_reporting"></a>
|
||||
|
||||
### reporting
|
||||
|
||||
In order to see what repositories were created from a wildcard, use the
|
||||
"expand" command, described briefly in [doc/report-output.mkd][repout].
|
||||
|
||||
### deleting a wild repo
|
||||
|
||||
See [repo deletion][rmr] for more on this. Note that this requires you to
|
||||
install/setup "adc"s (admin defined commands). See
|
||||
[doc/admin-defined-commands.mkd][adc] for how to do that.
|
||||
|
||||
[adc]: http://sitaramc.github.com/gitolite/doc/admin-defined-commands.html
|
||||
[rmr]: http://github.com/sitaramc/gitolite/blob/pu/contrib/adc/repo-deletion.README
|
||||
|
||||
<a name="_how_it_actually_works"></a>
|
||||
|
||||
### how it actually works
|
||||
|
||||
This section tells you what is happening inside gitolite so you can understand
|
||||
this feature better. Let's use the config example at the beginning of this
|
||||
document:
|
||||
|
||||
repo assignments/CREATOR/a[0-9][0-9]
|
||||
C = @students
|
||||
RW+ = CREATOR
|
||||
RW = WRITERS @TAs
|
||||
R = READERS @prof
|
||||
|
||||
First we find the set of rules to apply. This involves replacing the special
|
||||
words CREATOR, WRITERS, and READERS with appropriate usernames to derive an
|
||||
"effective" ruleset for the repo in question.
|
||||
|
||||
For a **new** repo, replace the word CREATOR in all repo patterns and rules
|
||||
with the name of the invoking user.
|
||||
|
||||
> (Note: this is why you should never use `C = CREATOR`; it becomes `C =
|
||||
> invoking_user`! Unless you really want to allow *all* users to create
|
||||
> repos, you should restrict "C" perms to an actual user or set of users,
|
||||
> like in the examples in this document).
|
||||
|
||||
For an **existing** repo, do the same but replace with the name of the user
|
||||
who actually *created* the repo (this name is recorded in a special file in
|
||||
the repo directory when the repo is first created, so it is available).
|
||||
|
||||
Now find a repo pattern that matches the actual reponame being pushed -- this
|
||||
tells you which set of rules to apply. There can be multiple matches; if so,
|
||||
they will all be applied in the sequence they appear in the config file.
|
||||
|
||||
If the invoking user has been put in the "WRITERS" category using `setperms`, all
|
||||
permissions for the the user WRITERS are given to the invoking username (and
|
||||
similarly for READERS).
|
||||
|
||||
At this point we have an effective ruleset, and the normal access rules (R,
|
||||
RW, etc) apply, with the addition that the invoking user needs "C" access to
|
||||
be able to create a repo.
|
||||
|
||||
> (Note: "C" rights do not automatically give the CREATOR any other rights;
|
||||
> they must be specifically given. `RW+ = CREATOR` is recommended in most
|
||||
> situations, as you can see in our example).
|
||||
|
||||
Assuming user "u4" trying to push-create a new repo called
|
||||
`assignments/u4/a23`, this is what the effective ruleset looks like:
|
||||
|
||||
repo assignments/u4/a23
|
||||
C = @students
|
||||
RW+ = u4
|
||||
RW = @TAs
|
||||
R = @prof
|
||||
|
||||
If u4 puts u5 in the "WRITERS" category using `setperms`, and u5 tries to
|
||||
access that repo, the ruleset looks like:
|
||||
|
||||
repo assignments/u4/a23
|
||||
C = @students
|
||||
RW+ = u4
|
||||
RW = u5 @TAs
|
||||
R = @prof
|
||||
|
||||
I hope that helps.
|
||||
|
||||
----
|
||||
|
||||
Enjoy, and please use with care. This is pretty powerful stuff. As they say:
|
||||
if you break it, you get to keep both pieces :)
|
||||
|
||||
[repout]: http://sitaramc.github.com/gitolite/doc/report-output.html
|
|
@ -1,10 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# sample pre-git hook to print pending hub requests
|
||||
|
||||
[ "$1" = "R" ] && exit 0 # we only want to print them on pushes
|
||||
|
||||
# print 'fetched' and 'pending' requests only
|
||||
SSH_ORIGINAL_COMMAND="hub list-requests $GL_REPO fetched pending" $GL_BINDIR/gl-auth-command $GL_USER
|
||||
|
||||
exit 0
|
|
@ -1,26 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# gitolite mirroring
|
||||
|
||||
# please see doc/mirroring.mkd for instructions on how to use this
|
||||
|
||||
# flush STDIN coming from git; we have no use for that info in this hook but
|
||||
# if you don't do this, git-shell sometimes dies of a signal 13 (SIGPIPE)
|
||||
[ -t 0 ] || cat >/dev/null
|
||||
|
||||
if [ -n "$GL_SLAVES" ]
|
||||
then
|
||||
for mirror in $GL_SLAVES
|
||||
do
|
||||
if git push --mirror $mirror:$GL_REPO.git
|
||||
then
|
||||
:
|
||||
else
|
||||
ssh $mirror mkdir -p $GL_REPO.git
|
||||
ssh $mirror git init --bare $GL_REPO.git
|
||||
ssh $mirror "cd $GL_REPO.git; git config receive.fsckObjects true"
|
||||
git push --mirror $mirror:$GL_REPO.git ||
|
||||
echo "WARNING: mirror push to $mirror failed"
|
||||
fi
|
||||
done
|
||||
fi >&2
|
|
@ -1,99 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# === update ===
|
||||
# this is gitolite's update hook
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# find the rc file, then pull the libraries
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
BEGIN {
|
||||
# people with shell access should be allowed to bypass the update hook,
|
||||
# simply by setting an env var that the ssh "front door" will never set
|
||||
exit 0 if exists $ENV{GL_BYPASS_UPDATE_HOOK};
|
||||
|
||||
die "ENV GL_RC not set\n" unless $ENV{GL_RC};
|
||||
die "ENV GL_BINDIR not set\n" unless $ENV{GL_BINDIR};
|
||||
}
|
||||
|
||||
use lib $ENV{GL_BINDIR};
|
||||
use gitolite_rc;
|
||||
use gitolite qw(:DEFAULT %repos);
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# start...
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
my ($perm, $creator, $wild) = repo_rights($ENV{GL_REPO});
|
||||
my $reported_repo = $ENV{GL_REPO} . ( $wild ? " ($wild)" : "" );
|
||||
|
||||
# arguments are as supplied to an update hook by git; man githooks
|
||||
my ($ref, $oldsha, $newsha) = @ARGV;
|
||||
my $merge_base = '0' x 40;
|
||||
# compute a merge-base if both SHAs are non-0, else leave it as '0'x40
|
||||
# (i.e., for branch create or delete, merge_base == '0'x40)
|
||||
chomp($merge_base = `git merge-base $oldsha $newsha`)
|
||||
unless $oldsha eq '0' x 40
|
||||
or $newsha eq '0' x 40;
|
||||
|
||||
# att_acc == attempted access -- what are you trying to do? (is it 'W' or '+'?)
|
||||
my $att_acc = 'W';
|
||||
# rewriting a tag is considered a rewind, in terms of permissions
|
||||
$att_acc = '+' if $ref =~ m(refs/tags/) and $oldsha ne ('0' x 40);
|
||||
# non-ff push to ref
|
||||
# notice that ref delete looks like a rewind, as it should
|
||||
$att_acc = '+' if $oldsha ne $merge_base;
|
||||
|
||||
# were any 'D' perms specified? If they were, it means we have to separate
|
||||
# deletes from rewinds, so if the new sha is all 0's, change the '+' to a 'D'
|
||||
$att_acc = 'D' if ( $repos{$ENV{GL_REPO}}{DELETE_IS_D} or $repos{'@all'}{DELETE_IS_D} ) and $newsha eq '0' x 40;
|
||||
# similarly C for create a branch
|
||||
$att_acc = 'C' if ( $repos{$ENV{GL_REPO}}{CREATE_IS_C} or $repos{'@all'}{CREATE_IS_C} ) and $oldsha eq '0' x 40;
|
||||
|
||||
my @allowed_refs;
|
||||
# @all repos: see comments in similar code in check_access
|
||||
push @allowed_refs, @ { $repos{$ENV{GL_REPO}}{$ENV{GL_USER}} || [] };
|
||||
push @allowed_refs, @ { $repos{'@all'} {$ENV{GL_USER}} || [] };
|
||||
push @allowed_refs, @ { $repos{$ENV{GL_REPO}}{'@all'} || [] };
|
||||
|
||||
# prepare the list of refs to be checked
|
||||
|
||||
# previously, we just checked $ref -- the ref being updated, which is passed
|
||||
# to us by git (see man githooks). Now we also have to treat each NAME being
|
||||
# updated as a potential "ref" and check that, if NAME-based restrictions have
|
||||
# been specified
|
||||
|
||||
my @refs = ($ref); # the first ref to check is the real one
|
||||
# because making it work screws up efficiency like no tomorrow...
|
||||
if (exists $repos{$ENV{GL_REPO}}{NAME_LIMITS}) {
|
||||
# this is special to git -- the hash of an empty tree
|
||||
my $empty='4b825dc642cb6eb9a060e54bf8d69288fbee4904';
|
||||
# well they're not really "trees" but $empty is indeed the empty tree so
|
||||
# we can just pretend $oldsha/$newsha are also trees, and anyway 'git
|
||||
# diff' only wants trees
|
||||
my $oldtree = $oldsha eq '0' x 40 ? $empty : $oldsha;
|
||||
my $newtree = $newsha eq '0' x 40 ? $empty : $newsha;
|
||||
push @refs, map { chomp; s/^/NAME\//; $_; } `git diff --name-only $oldtree $newtree`;
|
||||
}
|
||||
|
||||
# we potentially have many "refs" to check. The one we print in the log is
|
||||
# the *first* one (which is a *real* ref, like refs/heads/master), while all
|
||||
# the rest (if they exist) are like NAME/something. So we do the first one
|
||||
# separately to capture it, then run the rest (if any)
|
||||
my $log_refex = check_ref(\@allowed_refs, $ENV{GL_REPO}, (shift @refs), $att_acc);
|
||||
check_ref (\@allowed_refs, $ENV{GL_REPO}, $_ , $att_acc) for @refs;
|
||||
|
||||
# if we returned at all, all the checks succeeded. Check secondary hooks now
|
||||
$UPDATE_CHAINS_TO ||= 'hooks/update.secondary';
|
||||
( -f $UPDATE_CHAINS_TO or -l $UPDATE_CHAINS_TO )
|
||||
and system ( $UPDATE_CHAINS_TO, @ARGV )
|
||||
and die "$UPDATE_CHAINS_TO died\n";
|
||||
|
||||
# now log it and exit 0 so git can get on with it
|
||||
log_it("", "$att_acc\t" . substr($oldsha, 0, 14) . "\t" . substr($newsha, 0, 14) .
|
||||
"\t$reported_repo\t$ref\t$log_refex");
|
||||
|
||||
exit 0;
|
|
@ -1,44 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# driver script to run multiple update "hooklets". Each "hooklet" performs a
|
||||
# specific (possibly site-local) check, and they *all* have to succeed for the
|
||||
# push to succeed.
|
||||
|
||||
# HOW TO USE:
|
||||
|
||||
# (1) clone gitolite as you would for an upgrade (or install)
|
||||
# (2) rename this file to remove the .sample extension
|
||||
# (3) make the renamed file executable (chmod +x)
|
||||
# (4) create a directory called update.secondary.d in hooks/common
|
||||
# (5) copy all the update "hooklets" you want (like update.detect-dup-pubkeys)
|
||||
# from contrib or wherever, to that directory
|
||||
# (6) make them also executable (chmod +x)
|
||||
# (7) install/upgrade gitolite as normal so all these files go to the server
|
||||
|
||||
# rules for writing a hooklet are in the sample hooklet called
|
||||
# "update.detect-dup-pubkeys" in contrib
|
||||
|
||||
# ----
|
||||
|
||||
# NOTE: a hooklet runs under the same assumptions as the 'update' hook, so the
|
||||
# starting directory must be maintained and arguments must be passed on.
|
||||
|
||||
[ -d hooks/update.secondary.d ] || exit 0
|
||||
|
||||
# all output from these "hooklets" must go to STDERR to avoid confusing the client
|
||||
exec >&2
|
||||
|
||||
for i in hooks/update.secondary.d/*
|
||||
do
|
||||
[ -x "$i" ] || continue
|
||||
# call the hooklet with the same arguments we got
|
||||
"$i" "$@" || {
|
||||
# hooklet failed; we need to log it...
|
||||
echo hooklet $i failed
|
||||
perl -I$GL_BINDIR -Mgitolite -e "log_it('hooklet $i failed')"
|
||||
# ...and send back some non-zero exit code ;-)
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
|
||||
exit 0
|
|
@ -1,32 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
[ -z "$GL_RC" ] && die "ENV GL_RC not set"
|
||||
[ -z "$GL_BINDIR" ] && die "ENV GL_BINDIR not set"
|
||||
[ -z "$GL_ADMINDIR" ] && die "ENV GL_ADMINDIR not set"
|
||||
|
||||
# ensure that the admin is not sneaking in src/ and hooks/ :)
|
||||
GIT_WORK_TREE=$GL_ADMINDIR git ls-tree --name-only master |
|
||||
perl -lne 'exit 1 if /^(src|hooks)$/' || {
|
||||
echo "*** ERROR ***" >&2
|
||||
echo "no files/dirs called 'src' or 'hooks' are allowed, sorry" >&2
|
||||
echo "until those files are deleted, the post-update hook will not run" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# checkout the master branch to $GL_ADMINDIR
|
||||
# (the GL_ADMINDIR env var would have been set by gl-auth-command)
|
||||
GIT_WORK_TREE=$GL_ADMINDIR git checkout -f --quiet master
|
||||
|
||||
od=$PWD
|
||||
cd $GL_ADMINDIR
|
||||
$GL_BINDIR/gl-compile-conf
|
||||
|
||||
cd $od
|
||||
|
||||
ADMIN_POST_UPDATE_CHAINS_TO=`$GL_BINDIR/gl-query-rc ADMIN_POST_UPDATE_CHAINS_TO`
|
||||
[ -n "$ADMIN_POST_UPDATE_CHAINS_TO" ] || ADMIN_POST_UPDATE_CHAINS_TO=hooks/post-update.secondary
|
||||
|
||||
if [ -f $ADMIN_POST_UPDATE_CHAINS_TO ] || [ -L $ADMIN_POST_UPDATE_CHAINS_TO ]
|
||||
then
|
||||
exec $ADMIN_POST_UPDATE_CHAINS_TO "$@"
|
||||
fi
|
77
install
Executable file
77
install
Executable file
|
@ -0,0 +1,77 @@
|
|||
#!/usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# Clearly you don't need a program to make one measly symlink, but the git
|
||||
# describe command involved in generating the VERSION string is a bit fiddly.
|
||||
|
||||
use Getopt::Long;
|
||||
use FindBin;
|
||||
|
||||
# meant to be run from the root of the gitolite tree, one level above 'src'
|
||||
BEGIN { $ENV{GL_BINDIR} = $FindBin::RealBin . "/src"; }
|
||||
BEGIN { $ENV{GL_LIBDIR} = "$ENV{GL_BINDIR}/lib"; }
|
||||
use lib $ENV{GL_LIBDIR};
|
||||
use Gitolite::Common;
|
||||
|
||||
=for usage
|
||||
Usage (from gitolite clone directory):
|
||||
|
||||
./install
|
||||
to run gitolite using an absolute or relative path, for example
|
||||
'src/gitolite' or '/full/path/to/this/dir/src/gitolite'
|
||||
|
||||
./install -ln [<dir>]
|
||||
to symlink just the gitolite executable to some <dir> that is in
|
||||
$PATH. <dir> defaults to $HOME/bin if <dir> not specified. <dir> is
|
||||
assumed to exist; gitolite will not create it.
|
||||
|
||||
Please provide a full path, not a relative path.
|
||||
|
||||
./install -to <dir>
|
||||
to copy the entire 'src' directory to <dir>. If <dir> is not in
|
||||
$PATH, use the full path to run gitolite commands.
|
||||
|
||||
Please provide a full path, not a relative path.
|
||||
|
||||
Simplest use, if $HOME/bin exists and is in $PATH, is:
|
||||
|
||||
git clone git://github.com/sitaramc/gitolite
|
||||
gitolite/install -ln
|
||||
|
||||
# now run setup
|
||||
gitolite setup -pk /path/to/YourName.pub
|
||||
=cut
|
||||
|
||||
my ( $to, $ln, $help, $quiet );
|
||||
|
||||
GetOptions(
|
||||
'to=s' => \$to,
|
||||
'ln:s' => \$ln,
|
||||
'help|h' => \$help,
|
||||
'quiet|q' => \$quiet,
|
||||
);
|
||||
usage() if $to and $ln or $help;
|
||||
$ln = "$ENV{HOME}/bin" if defined($ln) and not $ln;
|
||||
for my $d ($ln, $to) {
|
||||
if ($d and not -d $d) {
|
||||
print STDERR "FATAL: '$d' does not exist.\n";
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
chdir($ENV{GL_BINDIR});
|
||||
my $version = `git describe --tags --long --dirty=-dt`;
|
||||
|
||||
if ($to) {
|
||||
_mkdir($to);
|
||||
system("cp -a * $to");
|
||||
_print( "$to/VERSION", $version );
|
||||
} elsif ($ln) {
|
||||
ln_sf( $ENV{GL_BINDIR}, "gitolite", $ln );
|
||||
_print( "VERSION", $version );
|
||||
} else {
|
||||
say "use the following full path for gitolite:";
|
||||
say "\t$ENV{GL_BINDIR}/gitolite";
|
||||
_print( "VERSION", $version );
|
||||
}
|
51
src/VREF/COUNT
Executable file
51
src/VREF/COUNT
Executable file
|
@ -0,0 +1,51 @@
|
|||
#!/bin/sh
|
||||
|
||||
# gitolite VREF to count number of changed/new files in a push
|
||||
|
||||
# see gitolite docs for what the first 7 arguments mean
|
||||
|
||||
# inputs:
|
||||
# arg-8 is a number
|
||||
# arg-9 is optional, and can be "NEWFILES"
|
||||
# outputs (STDOUT)
|
||||
# arg-7 if the number of changed (or new, if arg-9 supplied) files is > arg-8
|
||||
# otherwise nothing
|
||||
# exit status:
|
||||
# always 0
|
||||
|
||||
die() { echo "$@" >&2; exit 1; }
|
||||
[ -z "$8" ] && die "not meant to be run manually"
|
||||
|
||||
newsha=$3
|
||||
oldtree=$4
|
||||
newtree=$5
|
||||
refex=$7
|
||||
|
||||
max=$8
|
||||
|
||||
nf=
|
||||
[ "$9" = "NEWFILES" ] && nf='--diff-filter=A'
|
||||
# NO_SIGNOFF implies NEWFILES
|
||||
[ "$9" = "NO_SIGNOFF" ] && nf='--diff-filter=A'
|
||||
|
||||
# count files against all the other commits in the system not just $oldsha
|
||||
# (why? consider what is $oldtree when you create a new branch, or what is
|
||||
# $oldsha when you update an old feature branch from master and then push it
|
||||
count=`git log --name-only $nf --format=%n $newtree --not --all | grep . | sort -u | perl -ne '}{print "$."'`
|
||||
|
||||
[ $count -gt $max ] && {
|
||||
# count has been exceeded. If $9 was NO_SIGNOFF there's still a chance
|
||||
# for redemption -- if the top commit has a proper signed-off by line
|
||||
[ "$9" = "NO_SIGNOFF" ] && {
|
||||
author_email=$(git log --format=%ae -1 $newsha)
|
||||
git cat-file -p $newsha |
|
||||
egrep -i >/dev/null "^ *$count +new +files +signed-off by: *$author_email *$" && exit 0
|
||||
echo $refex top commit message should include the text \'$count new files signed-off by: $author_email\'
|
||||
exit 0
|
||||
}
|
||||
echo -n $refex "(too many "
|
||||
[ -n "$nf" ] && echo -n "new " || echo -n "changed "
|
||||
echo "files in this push)"
|
||||
}
|
||||
|
||||
exit 0
|
66
src/VREF/EMAIL-CHECK
Executable file
66
src/VREF/EMAIL-CHECK
Executable file
|
@ -0,0 +1,66 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# gitolite VREF to check if all *new* commits have author == pusher
|
||||
|
||||
# THIS IS NOT READY TO USE AS IS
|
||||
# ------------------------------
|
||||
# you MUST change the 'email_ok()' sub to suit *YOUR* site's
|
||||
# gitolite username -> author email mapping!
|
||||
|
||||
# See bottom of the program for important philosophical notes.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# mapping between gitolite userid and correct email address is encapsulated in
|
||||
# this subroutine; change as you like
|
||||
sub email_ok {
|
||||
my ($author_email) = shift;
|
||||
my $expected_email = "$ENV{GL_USER}\@atc.tcs.com";
|
||||
return $author_email eq $expected_email;
|
||||
}
|
||||
|
||||
my ( $ref, $old, $new ) = @ARGV;
|
||||
for my $rev (`git log --format="%ae\t%h\t%s" $new --not --all`) {
|
||||
chomp($rev);
|
||||
my ( $author_email, $hash, $subject ) = split /\t/, $rev;
|
||||
|
||||
# again, we use the trick that a vref can just choose to die instead of
|
||||
# passing back a vref, having it checked, etc., if it's more convenient
|
||||
die "$ENV{GL_USER}, you can't push $hash authored by $author_email\n" . "\t(subject of commit was $subject)\n"
|
||||
unless email_ok($author_email);
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
__END__
|
||||
|
||||
The following discussion is for people who want to enforce this check on ALL
|
||||
their developers (i.e., not just the newbies).
|
||||
|
||||
Doing this breaks the "D" in "DVCS", forcing all your developers to work to a
|
||||
centralised model as far as pushes are concerned. It prevents amending
|
||||
someone else's commit and pushing (this includes rebasing, cherry-picking, and
|
||||
so on, which are all impossible now). It also makes *any* off-line
|
||||
collabaration between two developers useless, because neither of them can push
|
||||
the result to the server.
|
||||
|
||||
PHBs should note that validating the committer ID is NOT the same as reviewing
|
||||
the code and running QA/tests on it. If you're not reviewing/QA-ing the code,
|
||||
it's probably worthless anyway. Conversely, if you *are* going to review the
|
||||
code and run QA/tests anyway, then you don't really need to validate the
|
||||
author email!
|
||||
|
||||
In a DVCS, if you *pushed* a series of commits, you have -- in some sense --
|
||||
signed off on them. The most formal way to "sign" a series is to tack on and
|
||||
push a gpg-signed tag, although most people don't go that far. Gitolite's log
|
||||
files are designed to preserve that accountability to *some* extent, though;
|
||||
see contrib/adc/who-pushed for an admin defined command that quickly and
|
||||
easily tells you who *pushed* a particular commit.
|
||||
|
||||
Anyway, the point is that the only purpose of this script is to
|
||||
|
||||
* pander to someone who still has not grokked *D*VCS
|
||||
OR
|
||||
* tick off an item in some stupid PHB's checklist
|
||||
|
45
src/VREF/FILETYPE
Executable file
45
src/VREF/FILETYPE
Executable file
|
@ -0,0 +1,45 @@
|
|||
#!/bin/sh
|
||||
|
||||
# gitolite VREF to find autogenerated files
|
||||
|
||||
# *completely* site specific; use it as an illustration of what can be done
|
||||
# with gitolite VREFs if you wish
|
||||
|
||||
# see gitolite docs for what the first 7 arguments mean
|
||||
|
||||
# inputs:
|
||||
# arg-8 is currently only one possible value: AUTOGENERATED
|
||||
# outputs (STDOUT)
|
||||
# arg-7 if any files changed in the push look like they were autogenerated
|
||||
# otherwise nothing
|
||||
# exit status:
|
||||
# always 0
|
||||
|
||||
die() { echo "$@" >&2; exit 1; }
|
||||
[ -z "$8" ] && die "not meant to be run manually"
|
||||
|
||||
newsha=$3
|
||||
oldtree=$4
|
||||
newtree=$5
|
||||
refex=$7
|
||||
|
||||
option=$8
|
||||
|
||||
[ "$option" = "AUTOGENERATED" ] && {
|
||||
# currently we only look for ".java" programs with the string "Generated
|
||||
# by the protocol buffer compiler. DO NOT EDIT" in them.
|
||||
|
||||
git log --name-only $nf --format=%n $newtree --not --all |
|
||||
grep . |
|
||||
sort -u |
|
||||
grep '\.java$' |
|
||||
while read fn
|
||||
do
|
||||
git show "$newtree:$fn" | egrep >/dev/null \
|
||||
'Generated by the protocol buffer compiler. +DO NOT EDIT' ||
|
||||
continue
|
||||
|
||||
echo $refex
|
||||
exit 0
|
||||
done
|
||||
}
|
40
src/VREF/MAX_NEWBIN_SIZE
Executable file
40
src/VREF/MAX_NEWBIN_SIZE
Executable file
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# gitolite VREF to check max size of new binary files
|
||||
|
||||
# see gitolite docs for what the first 7 arguments mean
|
||||
|
||||
# inputs:
|
||||
# arg-8 is a number
|
||||
# outputs (STDOUT)
|
||||
# arg-7 if any new binary files exist that are greater in size than arg-8
|
||||
# *and* there is no "signed-off by" line for such a file in the top commit
|
||||
# message.
|
||||
#
|
||||
# Otherwise nothing
|
||||
# exit status:
|
||||
# always 0
|
||||
|
||||
die "not meant to be run manually" unless $ARGV[7];
|
||||
|
||||
my ( $newsha, $oldtree, $newtree, $refex, $max ) = @ARGV[ 2, 3, 4, 6, 7 ];
|
||||
|
||||
# / (.*) +\| Bin 0 -> (\d+) bytes/
|
||||
|
||||
chomp( my $author_email = `git log --format=%ae -1 $newsha` );
|
||||
my $msg = `git cat-file -p $newsha`;
|
||||
$msg =~ s/\t/ /g; # makes our regexes simpler
|
||||
|
||||
for my $newbin (`git diff --stat=999,999 $oldtree $newtree | grep Bin.0.-`) {
|
||||
next unless $newbin =~ /^ (.*) +\| +Bin 0 -> (\d+) bytes/;
|
||||
my ( $f, $s ) = ( $1, $2 );
|
||||
next if $s <= $max;
|
||||
|
||||
next if $msg =~ /^ *$f +signed-off by: *$author_email *$/mi;
|
||||
|
||||
print "$refex $f is larger than $max";
|
||||
}
|
||||
|
||||
exit 0
|
49
src/VREF/MERGE-CHECK
Normal file
49
src/VREF/MERGE-CHECK
Normal file
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# gitolite VREF to check if there are any merge commits in the current push.
|
||||
|
||||
# THIS IS DEMO CODE; please read all comments below as well as
|
||||
# doc/vref.mkd before trying to use this.
|
||||
|
||||
# usage in conf/gitolite.conf goes like this:
|
||||
|
||||
# - VREF/MERGE_CHECK/master = @all
|
||||
# # reject only if the merge commit is being pushed to the master branch
|
||||
# - VREF/MERGE_CHECK = @all
|
||||
# # reject merge commits to any branch
|
||||
|
||||
my $ref = $ARGV[0];
|
||||
my $oldsha = $ARGV[1];
|
||||
my $newsha = $ARGV[2];
|
||||
my $refex = $ARGV[6];
|
||||
|
||||
# The following code duplicates some code from parse_conf_line() and some from
|
||||
# check_ref(). This duplication is the only thing that is preventing me from
|
||||
# removing the "M" permission code from 'core' gitolite and using this
|
||||
# instead. However, it does demonstrate how you would do this if you had to
|
||||
# create any other similar features, for example someone wanted "no non-merge
|
||||
# first-parent", which is far too specific for me to add to 'core'.
|
||||
|
||||
# -- begin duplication --
|
||||
my $branch_refex = $ARGV[7] || '';
|
||||
if ($branch_refex) {
|
||||
$branch_refex =~ m(^refs/) or $branch_refex =~ s(^)(refs/heads/);
|
||||
} else {
|
||||
$branch_refex = 'refs/.*';
|
||||
}
|
||||
exit 0 unless $ref =~ /^$branch_refex/;
|
||||
# -- end duplication --
|
||||
|
||||
# we can't run this check for tag creation or new branch creation, because
|
||||
# 'git log' does not deal well with $oldsha = '0' x 40.
|
||||
if ( $oldsha eq "0" x 40 or $newsha eq "0" x 40 ) {
|
||||
print STDERR "ref create/delete ignored for purposes of merge-check\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
my $ret = `git rev-list -n 1 --merges $oldsha..$newsha`;
|
||||
print "$refex FATAL: merge commits not allowed\n" if $ret =~ /./;
|
||||
|
||||
exit 0;
|
80
src/VREF/VOTES
Executable file
80
src/VREF/VOTES
Executable file
|
@ -0,0 +1,80 @@
|
|||
#!/bin/sh
|
||||
|
||||
# gitolite VREF to count votes before allowing pushes to certain branches.
|
||||
|
||||
# This approximates gerrit's voting (but it is SHA based; I believe Gerrit is
|
||||
# more "changeset" based). Here's how it works:
|
||||
|
||||
# - A normal developer "bob" proposes changes to master by pushing a commit to
|
||||
# "pers/bob/master", then informs the voting members by email.
|
||||
|
||||
# - Some or all of the voting members fetch and examine the commit. If they
|
||||
# approve, they "vote" for the commit like so. For example, say voting
|
||||
# member "alice" fetched bob's proposed commit into "bob-master" on her
|
||||
# clone, then tested or reviewed it. She would approve it by running:
|
||||
# git push origin bob-master:votes/alice/master
|
||||
|
||||
# - Once enough votes have been tallied (hopefully there is normal team
|
||||
# communication that says "hey I approved your commit", or it can be checked
|
||||
# by 'git ls-remote origin' anyway), Bob, or any developer, can push the
|
||||
# same commit (same SHA) to master and the push will succeed.
|
||||
|
||||
# - Finally, a "trusted" developer can push a commit to master without
|
||||
# worrying about the voting restriction at all.
|
||||
|
||||
# The config for this example would look like this:
|
||||
|
||||
# repo foo
|
||||
# # allow personal branches (to submit proposed changes)
|
||||
# RW+ pers/USER/ = @devs
|
||||
# - pers/ = @all
|
||||
#
|
||||
# # allow only voters to vote
|
||||
# RW+ votes/USER/ = @voters
|
||||
# - votes/ = @all
|
||||
#
|
||||
# # normal access rules go here; should allow *someone* to push master
|
||||
# RW+ = @devs
|
||||
#
|
||||
# # 2 votes required to push master, but trusted devs don't have this restriction
|
||||
# RW+ VREF/VOTES/2/master = @trusted-devs
|
||||
# - VREF/VOTES/2/master = @devs
|
||||
|
||||
# Note: "2 votes required to push master" means at least 2 refs matching
|
||||
# "votes/*/master" have the same SHA as the one currently being pushed.
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# see gitolite docs for what the first 7 arguments mean
|
||||
|
||||
# inputs:
|
||||
# arg-8 is a number; see below
|
||||
# arg-9 is a simple branch name (i.e., "master", etc). Currently this code
|
||||
# does NOT do vote counting for branch names with more than one component
|
||||
# (like foo/bar).
|
||||
# outputs (STDOUT)
|
||||
# nothing
|
||||
# exit status:
|
||||
# always 0
|
||||
|
||||
die() { echo "$@" >&2; exit 1; }
|
||||
[ -z "$8" ] && die "not meant to be run manually"
|
||||
|
||||
ref=$1
|
||||
newsha=$3
|
||||
refex=$7
|
||||
votes_needed=$8
|
||||
branch=$9
|
||||
|
||||
# nothing to do if the branch being pushed is not "master" (using our example)
|
||||
[ "$ref" = "refs/heads/$branch" ] || exit 0
|
||||
|
||||
# find how many votes have come in
|
||||
votes=`git for-each-ref refs/heads/votes/*/$branch | grep -c $newsha`
|
||||
|
||||
# send back a vref if we don't have the minimum votes needed. For trusted
|
||||
# developers this will invoke the RW+ rule and pass anyway, but for others it
|
||||
# will invoke the "-" rule and fail.
|
||||
[ $votes -ge $votes_needed ] || echo $refex "require at least $votes_needed votes to push $branch"
|
||||
|
||||
exit 0
|
36
src/VREF/lock
Executable file
36
src/VREF/lock
Executable file
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib $ENV{GL_LIBDIR};
|
||||
use Gitolite::Common;
|
||||
|
||||
# gitolite VREF to lock and unlock (binary) files. Requires companion command
|
||||
# 'lock' to be enabled; see doc/locking.mkd for details.
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# see gitolite docs for what the first 7 arguments mean
|
||||
|
||||
die "not meant to be run manually" unless $ARGV[6];
|
||||
|
||||
my $ff = "$ENV{GL_REPO_BASE}/$ENV{GL_REPO}.git/gl-locks";
|
||||
exit 0 unless -f $ff;
|
||||
|
||||
our %locks;
|
||||
my $t = slurp($ff);
|
||||
eval $t;
|
||||
_die "do '$ff' failed with '$@', contact your administrator" if $@;
|
||||
|
||||
my ( $oldtree, $newtree, $refex ) = @ARGV[ 3, 4, 6 ];
|
||||
|
||||
for my $file (`git diff --name-only $oldtree $newtree` ) {
|
||||
chomp($file);
|
||||
|
||||
if ($locks{$file} and $locks{$file}{USER} ne $ENV{GL_USER}) {
|
||||
print "$refex '$file' locked by '$locks{$file}{USER}'";
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
exit 0
|
41
src/VREF/partial-copy
Executable file
41
src/VREF/partial-copy
Executable file
|
@ -0,0 +1,41 @@
|
|||
#!/bin/sh
|
||||
|
||||
# push updated branches back to the "main" repo.
|
||||
|
||||
# This must be run as the *last* VREF, though it doesn't matter what
|
||||
# permission you give to it
|
||||
|
||||
die() { echo "$@" >&2; exit 1; }
|
||||
|
||||
repo=$GL_REPO
|
||||
user=$GL_USER
|
||||
ref=$1 # we're running like an update hook
|
||||
old=$2
|
||||
new=$3
|
||||
|
||||
# never send any STDOUT back, to avoid looking like a ref. If we fail, git
|
||||
# will catch it by our exit code
|
||||
exec >&2
|
||||
|
||||
main=`git config --file $GL_REPO_BASE/$repo.git/config --get gitolite.partialCopyOf`;
|
||||
[ -z "$main" ] && exit 0
|
||||
|
||||
rand=$$
|
||||
export GL_BYPASS_ACCESS_CHECKS=1
|
||||
|
||||
if [ "$new" = "0000000000000000000000000000000000000000" ]
|
||||
then
|
||||
# special case for deleting a ref (this is why it is important to put this
|
||||
# VREF as the last one; if we got this far he is allowed to delete it)
|
||||
git push -f $GL_REPO_BASE/$main.git :$ref || die "FATAL: failed to delete $ref"
|
||||
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git push -f $GL_REPO_BASE/$main.git $new:refs/partial/br-$rand || die "FATAL: failed to send $new"
|
||||
|
||||
cd $GL_REPO_BASE/$main.git
|
||||
git update-ref -d refs/partial/br-$rand
|
||||
git update-ref $ref $new $old || die "FATAL: update-ref for $ref failed"
|
||||
|
||||
exit 0
|
75
src/VREF/refex-expr
Executable file
75
src/VREF/refex-expr
Executable file
|
@ -0,0 +1,75 @@
|
|||
#!/usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $rule = $ARGV[7];
|
||||
die "\n\nFATAL: GL_REFEX_EXPR_ doesn't exist\n(your admin probably forgot the rc file change needed for this to work)\n\n"
|
||||
unless exists $ENV{"GL_REFEX_EXPR_" . $rule};
|
||||
my $res = $ENV{"GL_REFEX_EXPR_" . $rule} || 0;
|
||||
print "$ARGV[6] ($res)\n" if $res;
|
||||
|
||||
exit 0;
|
||||
|
||||
__END__
|
||||
|
||||
Documentation for the refex-expression evaluation feature
|
||||
|
||||
First, make sure you have both the VREF and the trigger scripts
|
||||
(src/VREF/refex-expr and src/lib/Gitolite/Triggers/RefexExpr.pm)
|
||||
|
||||
Next, add this to the ACCESS_2 list in the rc file:
|
||||
|
||||
'RefexExpr::access_2',
|
||||
|
||||
For the rest, we'll use this example:
|
||||
|
||||
* user u1 can push foo to some other branch, and anything else to the master
|
||||
branch, but not foo to the master branch
|
||||
|
||||
* user u2 is allowed to push either 'doc/' or 'src/' but not both
|
||||
|
||||
Here's the conf file extract:
|
||||
|
||||
repo testing
|
||||
RW+ master = u1 # line 1
|
||||
RW+ = @all # line 2
|
||||
|
||||
RW+ VREF/NAME/foo = u1
|
||||
RW+ VREF/NAME/doc/ = u2
|
||||
RW+ VREF/NAME/src/ = u2
|
||||
|
||||
# set up 2 refex expressions, named e1, e2
|
||||
option refex-expr.e1 = master and VREF/NAME/foo
|
||||
option refex-expr.e2 = VREF/NAME/doc/ and VREF/NAME/src/
|
||||
|
||||
# now deny users if the corresponding expression is true
|
||||
- VREF/refex-expr/e1 = u1
|
||||
- VREF/refex-expr/e2 = u2
|
||||
|
||||
Here are some IMPORTANT notes:
|
||||
|
||||
* You MUST place VREF/refex-expr rules at the end. (Only 'partial-copy', if
|
||||
you use it, must come later).
|
||||
|
||||
* You MUST explicitly permit the refexes used in your refex expressions. If
|
||||
you have more generic rules, the specific ones must come first.
|
||||
|
||||
For example, without line 1, the refex recorded for user u1 will come from
|
||||
line 2, (so it will be 'refs/.*'), and 'master' in the refex expressions
|
||||
will never have a true value.
|
||||
|
||||
* (corollary) make sure you use the exact same refex in the expression as
|
||||
you did on the original rule line. E.g., a missing slash at the end will
|
||||
mess things up.
|
||||
|
||||
* You can use any logical expression using refexes as operands and using
|
||||
these operators:
|
||||
|
||||
and not xor or
|
||||
|
||||
Parens are not allowed.
|
||||
|
||||
If a refex has passed, it will have a 'true' value, else it will be false.
|
||||
|
||||
The result of the evaluation, after these substitutions, will be the
|
||||
result of the refex-expr VREF.
|
131
src/commands/D
Executable file
131
src/commands/D
Executable file
|
@ -0,0 +1,131 @@
|
|||
#!/bin/sh
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# ADMINISTRATOR NOTES:
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# - set TRASH_CAN in the rc if you don't like the default. It should be
|
||||
# relative to GL_REPO_BASE or an absolute value. It should also be on the
|
||||
# same filesystem as GL_REPO_BASE, otherwise the 'mv' will take too long.
|
||||
|
||||
# - you could set TRASH_SUFFIX also but I recomend you leave it as it is
|
||||
|
||||
# - run a cron job to delete old repos based on age (the TRASH_SUFFIX has a
|
||||
# timestamp); your choice how/how often you do that
|
||||
|
||||
# - you can completely disable the 'rm' command by setting an rc variable
|
||||
# called D_DISABLE_RM to "1".
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Usage: ssh git@host D <subcommand> <argument>
|
||||
#
|
||||
# The whimsically named "D" command deletes repos ("D" is a counterpart to the
|
||||
# "C" permission which lets you create repos. Which also means that, just
|
||||
# like "C", it only works for wild repos).
|
||||
#
|
||||
# There are two kinds of deletions: 'rm' removes a repo completely, while
|
||||
# 'trash' moves it to a trashcan which can be recovered later (upto a time
|
||||
# limit that your admin will tell you).
|
||||
#
|
||||
# The 'rm', 'lock', and 'unlock' subcommands:
|
||||
# Initially, all repos are "locked" against 'rm'. The correct sequence is
|
||||
# ssh git@host D unlock repo
|
||||
# ssh git@host D rm repo
|
||||
# Since the initial condition is always locked, the "lock" command is
|
||||
# rarely used but it is there if you want it.
|
||||
#
|
||||
# The 'trash', 'list-trash', and 'restore' subcommands:
|
||||
# You can 'trash' a repo, which moves it to a special place:
|
||||
# ssh git@host D trash repo
|
||||
# You can then 'list-trash'
|
||||
# ssh git@host D list-trash
|
||||
# which prints something like
|
||||
# repo/2012-04-11_05:58:51
|
||||
# allowing you to restore by saying
|
||||
# ssh git@host D restore repo/2012-04-11_05:58:51
|
||||
|
||||
die() { echo "$@" >&2; exit 1; }
|
||||
usage() { perl -lne 'print substr($_, 2) if /^# Usage/../^$/' < $0; exit 1; }
|
||||
[ -z "$1" ] && usage
|
||||
[ "$1" = "-h" ] && usage
|
||||
[ "$1" != "list-trash" ] && [ -z "$2" ] && usage
|
||||
[ -z "$GL_USER" ] && die GL_USER not set
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
cmd=$1
|
||||
repo=$2
|
||||
# ----------------------------------------------------------------------
|
||||
RB=`gitolite query-rc GL_REPO_BASE`; cd $RB
|
||||
TRASH_CAN=`gitolite query-rc TRASH_CAN`; tcan=Trash; TRASH_CAN=${TRASH_CAN:-$tcan}
|
||||
TRASH_SUFFIX=`gitolite query-rc TRASH_SUFFIX`; tsuf=`date +%Y-%m-%d_%H:%M:%S`; TRASH_SUFFIX=${TRASH_SUFFIX:-$tsuf}
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
owner_or_die() {
|
||||
gitolite creator "$repo" $GL_USER || die You are not authorised
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
if [ "$cmd" = "rm" ]
|
||||
then
|
||||
|
||||
gitolite query-rc -q D_DISABLE_RM && die "sorry, 'unlock' and 'rm' are disabled"
|
||||
|
||||
owner_or_die
|
||||
[ -f $repo.git/gl-rm-ok ] || die "'$repo' is locked!"
|
||||
rm -rf $repo.git
|
||||
echo "'$repo' is now gone!"
|
||||
|
||||
elif [ "$cmd" = "lock" ]
|
||||
then
|
||||
|
||||
owner_or_die
|
||||
rm -f $repo.git/gl-rm-ok
|
||||
echo "'$repo' is now locked"
|
||||
|
||||
elif [ "$cmd" = "unlock" ]
|
||||
then
|
||||
|
||||
gitolite query-rc -q D_DISABLE_RM && die "sorry, 'unlock' and 'rm' are disabled"
|
||||
|
||||
owner_or_die
|
||||
touch $repo.git/gl-rm-ok
|
||||
echo "'$repo' is now unlocked"
|
||||
|
||||
elif [ "$cmd" = "trash" ]
|
||||
then
|
||||
|
||||
owner_or_die
|
||||
mkdir -p $TRASH_CAN/$repo 2>/dev/null || die "failed creating directory in trashcan"
|
||||
[ -d $TRASH_CAN/$repo/$TRASH_SUFFIX ] && die "try again in a few seconds..."
|
||||
mv $repo.git $TRASH_CAN/$repo/$TRASH_SUFFIX
|
||||
echo "'$repo' moved to trashcan"
|
||||
|
||||
elif [ "$cmd" = "list-trash" ]
|
||||
then
|
||||
|
||||
cd $TRASH_CAN 2>/dev/null || exit 0
|
||||
find . -name gl-creator | sort | while read t
|
||||
do
|
||||
owner=
|
||||
owner=`cat "$t"`
|
||||
[ "$owner" = "$GL_USER" ] && dirname $t
|
||||
done | cut -c3-
|
||||
|
||||
elif [ "$cmd" = "restore" ]
|
||||
then
|
||||
|
||||
owner=
|
||||
owner=`cat $TRASH_CAN/$repo/gl-creator 2>/dev/null`
|
||||
[ "$owner" = "$GL_USER" ] || die "'$repo' is not yours!"
|
||||
|
||||
cd $TRASH_CAN
|
||||
realrepo=`dirname $repo`
|
||||
[ -d $RB/$realrepo.git ] && die "'$realrepo' already exists"
|
||||
mv $repo $RB/$realrepo.git
|
||||
echo "'$repo' restored to '$realrepo'"
|
||||
|
||||
else
|
||||
die "unknown subcommand '$cmd'"
|
||||
fi
|
74
src/commands/access
Executable file
74
src/commands/access
Executable file
|
@ -0,0 +1,74 @@
|
|||
#!/usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib $ENV{GL_LIBDIR};
|
||||
use Gitolite::Rc;
|
||||
use Gitolite::Common;
|
||||
use Gitolite::Conf::Load;
|
||||
|
||||
=for usage
|
||||
Usage: gitolite access [-q] <repo> <user> <perm> <ref>
|
||||
|
||||
Print access rights for arguments given. The string printed has the word
|
||||
DENIED in it if access was denied. With '-q', returns only an exit code
|
||||
(shell truth, not perl truth -- 0 is success).
|
||||
|
||||
- repo: mandatory
|
||||
- user: mandatory
|
||||
- perm: defauts to '+'. Valid values: R, W, +, C, D, M
|
||||
- ref: defauts to 'any'. See notes below
|
||||
|
||||
Notes:
|
||||
- ref: Any fully qualified ref ('refs/heads/master', not 'master') is fine.
|
||||
The 'any' ref is special -- it ignores deny rules (see docs for what this
|
||||
means and exceptions).
|
||||
|
||||
For each case where access is not denied, one line is printed like this:
|
||||
|
||||
reponame<tab>username<tab>access rights
|
||||
|
||||
This is orders of magnitude faster than running the command multiple times;
|
||||
you'll notice if you have more than a hundred or so repos.
|
||||
|
||||
Advanced uses: see src/triggers/post-compile/update-git-daemon-access-list for
|
||||
a good example.
|
||||
=cut
|
||||
|
||||
usage() if not @ARGV or $ARGV[0] eq '-h';
|
||||
my $quiet = 0;
|
||||
if ( $ARGV[0] eq '-q' ) { $quiet = 1; shift @ARGV; }
|
||||
|
||||
my ( $repo, $user, $aa, $ref ) = @ARGV;
|
||||
$aa ||= '+';
|
||||
$ref ||= 'any';
|
||||
_die "invalid perm" if not( $aa and $aa =~ /^(R|W|\+|C|D|M|\^C)$/ );
|
||||
_die "invalid ref name" if not( $ref and $ref =~ $REPONAME_PATT );
|
||||
|
||||
my $ret = '';
|
||||
|
||||
if ( $repo ne '%' and $user ne '%' ) {
|
||||
# single repo, single user; no STDIN
|
||||
$ret = access( $repo, $user, $aa, $ref );
|
||||
|
||||
if ( $ret =~ /DENIED/ ) {
|
||||
print "$ret\n" unless $quiet;
|
||||
exit 1;
|
||||
}
|
||||
|
||||
print "$ret\n" unless $quiet;
|
||||
exit 0;
|
||||
}
|
||||
|
||||
$repo = '' if $repo eq '%';
|
||||
$user = '' if $user eq '%';
|
||||
|
||||
_die "'-q' doesn't go with using a pipe" if $quiet;
|
||||
@ARGV = ();
|
||||
while (<>) {
|
||||
my @in = split;
|
||||
my $r = $repo || shift @in;
|
||||
my $u = $user || shift @in;
|
||||
$ret = access( $r, $u, $aa, $ref );
|
||||
print "$r\t$u\t$ret\n";
|
||||
}
|
15
src/commands/create
Executable file
15
src/commands/create
Executable file
|
@ -0,0 +1,15 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Usage: ssh git@host create <repo>
|
||||
#
|
||||
# Create wild repo.
|
||||
|
||||
die() { echo "$@" >&2; exit 1; }
|
||||
usage() { perl -lne 'print substr($_, 2) if /^# Usage/../^$/' < $0; exit 1; }
|
||||
[ -z "$1" ] && usage
|
||||
[ -z "$2" ] || usage
|
||||
[ "$1" = "-h" ] && usage
|
||||
[ -z "$GL_USER" ] && die GL_USER not set
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
exec $GL_BINDIR/commands/perms -c "$@" < /dev/null
|
40
src/commands/creator
Executable file
40
src/commands/creator
Executable file
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib $ENV{GL_LIBDIR};
|
||||
use Gitolite::Rc;
|
||||
use Gitolite::Common;
|
||||
use Gitolite::Conf::Load;
|
||||
|
||||
=for usage
|
||||
Usage: gitolite creator [-n] <reponame> [<username>]
|
||||
|
||||
Print the creator name for the repo. A '-n' suppresses the newline.
|
||||
|
||||
When an optional username is supplied, it checks if the user is the creator of
|
||||
the repo and returns an exit code (shell truth, 0 for success) instead of
|
||||
printing anything, which makes it possible to do this in shell:
|
||||
|
||||
if gitolite creator someRepo someUser
|
||||
then
|
||||
...
|
||||
=cut
|
||||
|
||||
usage() if not @ARGV or $ARGV[0] eq '-h';
|
||||
my $nl = "\n";
|
||||
if ( $ARGV[0] eq '-n' ) {
|
||||
$nl = '';
|
||||
shift;
|
||||
}
|
||||
my $repo = shift;
|
||||
my $user = shift || '';
|
||||
|
||||
my $creator = '';
|
||||
$creator = creator($repo) if not repo_missing($repo);
|
||||
if ($user) {
|
||||
exit 0 if $creator eq $user;
|
||||
exit 1;
|
||||
}
|
||||
return ( $creator eq $user ) if $user;
|
||||
print "$creator$nl";
|
43
src/commands/desc
Executable file
43
src/commands/desc
Executable file
|
@ -0,0 +1,43 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Usage: ssh git@host desc <repo>
|
||||
# ssh git@host desc <repo> <description string>
|
||||
#
|
||||
# Show or set description for user-created ("wild") repo.
|
||||
|
||||
die() { echo "$@" >&2; exit 1; }
|
||||
usage() { perl -lne 'print substr($_, 2) if /^# Usage/../^$/' < $0; exit 1; }
|
||||
[ -z "$1" ] && usage
|
||||
[ "$1" = "-h" ] && usage
|
||||
[ -z "$GL_USER" ] && die GL_USER not set
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
repo=$1; shift
|
||||
|
||||
# this shell script takes arguments that are completely under the user's
|
||||
# control, so make sure you quote those suckers!
|
||||
|
||||
# kernel.org needs 'desc' to be available to people who have "RW" or above,
|
||||
# not just the "creator". In fact they need it for non-wild repos so there
|
||||
# *is* no creator.
|
||||
if gitolite query-rc -q WRITER_CAN_UPDATE_DESC
|
||||
then
|
||||
gitolite access -q "$repo" $GL_USER W any || die You are not authorised
|
||||
else
|
||||
gitolite creator "$repo" $GL_USER || die You are not authorised
|
||||
fi
|
||||
|
||||
# if it passes, $repo is a valid repo name so it is known to contain only sane
|
||||
# characters. This is because 'gitolite creator' return true only if there
|
||||
# *is* a repo of that name and it has a gl-creator file that contains the same
|
||||
# text as $GL_USER.
|
||||
|
||||
descfile=`gitolite query-rc GL_REPO_BASE`/"$repo".git/description
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
[ -r "$descfile" ] && cat "$descfile"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "$*" > "$descfile"
|
59
src/commands/fork
Executable file
59
src/commands/fork
Executable file
|
@ -0,0 +1,59 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Usage: ssh git@host fork <repo1> <repo2>
|
||||
#
|
||||
# Forks repo1 to repo2. You must have read permissions on repo1, and create
|
||||
# ("C") permissions for repo2, which of course must not exist.
|
||||
#
|
||||
# A fork is functionally the same as cloning repo1 to a client and pushing it
|
||||
# to a new repo2. It's just a little more efficient, not just in network
|
||||
# traffic but because it uses git clone's "-l" option to share the object
|
||||
# store also, so it is likely to be almost instantaneous, regardless of how
|
||||
# big the repo actually is.
|
||||
|
||||
die() { echo "$@" >&2; exit 1; }
|
||||
usage() { perl -lne 'print substr($_, 2) if /^# Usage/../^$/' < $0; exit 1; }
|
||||
[ -z "$1" ] && usage
|
||||
[ "$1" = "-h" ] && usage
|
||||
[ -z "$GL_USER" ] && die GL_USER not set
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
from=$1; shift
|
||||
to=$1; shift
|
||||
[ -z "$to" ] && usage
|
||||
|
||||
gitolite access -q "$from" $GL_USER R any || die "'$from' does not exist or you are not allowed to read it"
|
||||
gitolite access -q "$to" $GL_USER ^C any || die "'$to' already exists or you are not allowed to create it"
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# IMPORTANT NOTE: checking whether someone can create a repo is done as above.
|
||||
# However, make sure that the env var GL_USER is set, and that too to the same
|
||||
# value as arg-2 of the access command), otherwise it won't work.
|
||||
|
||||
# Ideally, you'll leave such code to me. There's a reason ^C is not listed in
|
||||
# the help message for 'gitolite access'.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# clone $from to $to
|
||||
git clone --bare -l $GL_REPO_BASE/$from.git $GL_REPO_BASE/$to.git
|
||||
[ $? -ne 0 ] && exit 1
|
||||
|
||||
echo "$from forked to $to" >&2
|
||||
|
||||
# fix up creator, default role permissions (gl-perms), and hooks
|
||||
cd $GL_REPO_BASE/$to.git
|
||||
echo $GL_USER > gl-creator
|
||||
|
||||
touch gl-perms
|
||||
if gitolite query-rc -q DEFAULT_ROLE_PERMS
|
||||
then
|
||||
gitolite query-rc DEFAULT_ROLE_PERMS > gl-perms
|
||||
fi
|
||||
|
||||
ln -sf `gitolite query-rc GL_ADMIN_BASE`/hooks/common/* hooks
|
||||
|
||||
# record where you came from
|
||||
echo "$from" > gl-forked-from
|
||||
|
||||
# trigger post_create
|
||||
gitolite trigger POST_CREATE $to $GL_USER fork
|
86
src/commands/git-config
Executable file
86
src/commands/git-config
Executable file
|
@ -0,0 +1,86 @@
|
|||
#!/usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Getopt::Long;
|
||||
use lib $ENV{GL_LIBDIR};
|
||||
use Gitolite::Rc;
|
||||
use Gitolite::Common;
|
||||
use Gitolite::Conf::Load;
|
||||
|
||||
=for usage
|
||||
Usage: gitolite git-config [-n] [-q] [-r] <repo> <key|pattern>
|
||||
|
||||
Print git config keys and values for the given repo. The key is either a full
|
||||
key, or, if '-r' is supplied, a regex that is applied to all available keys.
|
||||
|
||||
-q exit code only (shell truth; 0 is success)
|
||||
-n suppress trailing newline when used as key (not pattern)
|
||||
-r treat key as regex pattern (unanchored)
|
||||
|
||||
Examples:
|
||||
gitolite git-config repo gitweb.owner
|
||||
gitolite git-config -q repo gitweb.owner
|
||||
gitolite git-config -r repo gitweb
|
||||
|
||||
When the key is treated as a pattern, prints:
|
||||
|
||||
reponame<tab>key<tab>value<newline>
|
||||
|
||||
Otherwise the output is just the value.
|
||||
|
||||
Finally, see the advanced use section of 'gitolite access -h' -- you can do
|
||||
something similar here also:
|
||||
|
||||
gitolite list-phy-repos | gitolite git-config -r % gitweb\\. | cut -f1 > ~/projects.list
|
||||
=cut
|
||||
|
||||
usage() if not @ARGV;
|
||||
|
||||
my ( $help, $nonl, $quiet, $regex ) = (0) x 4;
|
||||
GetOptions(
|
||||
'n' => \$nonl,
|
||||
'q' => \$quiet,
|
||||
'r' => \$regex,
|
||||
'h' => \$help,
|
||||
) or usage();
|
||||
|
||||
my ( $repo, $key ) = @ARGV;
|
||||
usage() unless $key;
|
||||
|
||||
my $ret = '';
|
||||
|
||||
if ( $repo ne '%' and $key ne '%' ) {
|
||||
# single repo, single key; no STDIN
|
||||
$key = "^\Q$key\E\$" unless $regex;
|
||||
|
||||
$ret = git_config( $repo, $key );
|
||||
|
||||
# if the key is not a regex, it should match at most one item
|
||||
_die "found more than one entry for '$key'" if not $regex and scalar( keys %$ret ) > 1;
|
||||
|
||||
# unlike access, there's nothing to print if we don't find any matching keys
|
||||
exit 1 unless %$ret;
|
||||
|
||||
if ($regex) {
|
||||
map { print "$repo\t$_\t" . $ret->{$_} . "\n" } sort keys %$ret unless $quiet;
|
||||
} else {
|
||||
map { print $ret->{$_} . ( $nonl ? "" : "\n" ) } sort keys %$ret unless $quiet;
|
||||
}
|
||||
exit 0;
|
||||
}
|
||||
|
||||
$repo = '' if $repo eq '%';
|
||||
$key = '' if $key eq '%';
|
||||
|
||||
_die "'-q' doesn't go with using a pipe" if $quiet;
|
||||
@ARGV = ();
|
||||
while (<>) {
|
||||
my @in = split;
|
||||
my $r = $repo || shift @in;
|
||||
my $k = $key || shift @in;
|
||||
$k = "^\Q$k\E\$" unless $regex;
|
||||
$ret = git_config( $r, $k );
|
||||
next unless %$ret;
|
||||
map { print "$r\t$_\t" . $ret->{$_} . "\n" } sort keys %$ret;
|
||||
}
|
42
src/commands/help
Executable file
42
src/commands/help
Executable file
|
@ -0,0 +1,42 @@
|
|||
#!/usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use lib $ENV{GL_LIBDIR};
|
||||
use Gitolite::Rc;
|
||||
use Gitolite::Common;
|
||||
|
||||
=for usage
|
||||
Usage: ssh git@host help # via ssh
|
||||
gitolite help # directly on server command line
|
||||
|
||||
Prints a list of custom commands available at this gitolite installation.
|
||||
|
||||
Each command has its own help, accessed by passing it '-h' again.
|
||||
=cut
|
||||
|
||||
usage() if @ARGV;
|
||||
|
||||
my $user = $ENV{GL_USER} || '';
|
||||
print "hello" . ( $user ? " $user" : "" ) . ", this is gitolite3 " . version() . " on git " . substr( `git --version`, 12 ) . "\n";
|
||||
|
||||
print "list of " . ( $user ? "remote" : "gitolite" ) . " commands available:\n\n";
|
||||
|
||||
my %list = (list_x( $ENV{GL_BINDIR}), list_x($rc{LOCAL_CODE} || ''));
|
||||
for (sort keys %list) {
|
||||
print "\t$list{$_}" if $ENV{D};
|
||||
print "\t$_\n" if not $user or $rc{COMMANDS}{$_};
|
||||
}
|
||||
|
||||
print "\n";
|
||||
|
||||
exit 0;
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
sub list_x {
|
||||
my $d = shift;
|
||||
return unless $d;
|
||||
return unless -d "$d/commands";
|
||||
_chdir "$d/commands";
|
||||
return map { $_ => $d } grep { -x $_ } map { chomp; s(^./)(); $_ } `find . -type f -o -type l|sort`;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue