------------------------------------------------------------------------------- Set up a personal GIT repository - with upload! OR GIT with a .htaccess and a CGI script OR using "Smart HTTP GIT" without root. ------------------------------------------------------------------------------- Normal /git/ setup As a contrast to below this is the normal way to setup git-http-backend access for GIT over HTTP Create a /etc/httpd/conf.d/git.conf. # Git over HTTP SetEnv GIT_PROJECT_ROOT /data/repos ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/ SSLRequire AuthType Basic AuthName "Git Access" AuthUserFile /var/www/passwd.git Require valid-user If you have SELinux chcon -R -t httpd_git_rw_content_t /data/repos chcon -t httpd_git_script_exec_t /usr/libexec/git-core/git-http-backend Now any repos in GIT_PROJECT_ROOT can be accessed using something like... http://server/git/repo.git The important notes about this is that there is no real per-repo access control, just a global access. And all access is via the http-backend CGI script. Personal Repos are similar but involve creating a specific CGI inside the web access area that maps those URL's to a personal GIT_PROJECT_ROOT. ------------------------------------------------------------------------------- Basic set up - via CGI execution, rather than command line Based on a document... http://www-verimag.imag.fr/~moy/?Host-a-Git-repository-over-HTTP-S But a good complete guide to what is actually going on is http://git-scm.com/2010/03/04/smart-http.html You can Google for "git http-backend .htaccess" BUT some of the docs assumes https://your.domain.com/ references the top level of your public html area. Which is not the case for general web servers like hobbit. The method below assumes... * you can create and upload web files and directories * you can set execute permission on ".cgi" files * The server allows you to use .htaccess files and ExecCGI (hobbit does) It does NOT require... * Command Line (you run uploaded scripts instead) Though command line would make it easier (you do on hobbit) * The server has the cgi module and GIT installed (hobbit does) NOTE: I used HTTPS for everything below, because it is the only way to protect web passwords in the communications. DO NOT USE HTTP with passwords. NOTE: the git repository does not actually need to be in the Web page document tree. Only the ".htaccess" and the git-html-backend CGI script needs to be accessable and password protected in the Web document tree (public_html). --- In your public_html directory, or some other web server exported directory the server administration has provided... Create a repository directory, call it anything you like. mkdir ~/public_html/git_repos chmod 755 ~/public_html/git_repos cd ~/public_html/git_repos Now lets get some information from the http server... First allow CGI programs -- REQUIRED vi .htaccess Options +ExecCGI AddHandler cgi-script cgi chmod 644 .htaccess Find out the directory of the repository, if you don't know. And insure you can run CGI scripts. vi config.cgi #! /bin/sh echo 'Content-type: text/plain' echo pwd git --version chmod 755 config.cgi Now use the appropriate URL to get the output of "config.cgi" You can use a browser, but for me it was the remote command... wget -q -O - https://www.example.com/user/git_repos/config.cgi for me it reported... /home/anthony/public_html/git_repos git version 1.7.1 A Version of 1.6.6 or later is needed to provide ' --- Set up authentation, using the above directory path (OPTIONAL) NOTE: the dwarf 'secure' area already has this setup by server Add to .htaccess file... vi .htaccess AuthUserFile /home/anthony/public_html/git_repos/.htpasswd AuthType Basic AuthName "Anthony's Private GIT Repository" Require valid-user Create the .htpasswd (using whatever method is appropriate) htpasswd -c .htpasswd anthony New password: my secret password Re-type password: my secret password Adding password for user anthony chmod 644 .htpasswd Test this again using a proper browser using the previous URL Or from command line using wget -q -O - https://www.example.com/anthony/git_repos/config.cgi \ --user=anthony --ask-password You could at this point set up ".htgroup" for group access to specific repos. EG: create a ".htaccess" in the repository sub-directory (we create next) with something like... "Require group ????" to control access to that repo. --- NOW create a test repo, (just valid user access) Again this will be done via uploaded script, but if you have commandline you can run the commands directly... NOTE: directory is world writable as we will be pushing to this. vi create_repo.cgi #!/bin/sh echo 'Content-type: text/plain' echo exec 2>&1 # echo "Disabled"; exit 0 REPO=myrepo.git DESC="Description of my Example Repo" mkdir $REPO ( cd $REPO git --bare init git --bare update-server-info echo "$DESC" > descriptionk cp hooks/post-update.sample hooks/post-update chmod a+x hooks/post-update # The following are to ensure the repo is exportable via HTTP(s) touch git-daemon-export-ok find . -type f -print | xargs chmod 666 find . -type d -print | xargs chmod 777 ) echo "---------------" ls -Fla $REPO chmod 755 create_repo.cgi And run it (browser or as follows) wget -q -O - --user=anthony --ask-password \ https://www.example.com/anthony/git_repos/create_repo.cgi When run, uncomment the 'Disabled' line to prevent it running again. --- At this point you have a read-only, old style repository, which you can 'clone' or 'pull' from. For example... git clone https://www.example.com/anthony/git_repos/myrepo.git But this always download the whole files, even if only one 'object' in a file changed. Also you will never be able to 'push' changes up to that repo. --- To now do Smart HTTP GIT to provide 'push' capability. We need a way to get at the repository via the 'http-backend' CGI program provided by GIT. vi git.cgi #!/bin/bash export GIT_PROJECT_ROOT=~anthony/public_html/git_repos export REMOTE_USER="${REMOTE_USER:-$REDIRECT_REMOTE_USER}" exec git http-backend "$@" chmod 755 git.cgi This script basically defines a CGI script that knows where your repositories are located and calls the backend, and sets what user is reading/writing the repository. The user was pre-defined by the webserver using $REMOTE_USER environment variable. For anonymous writes you can just set REMOTE_USER to anything. You can use it as follows. git clone https://www.example.com/anthony/git_repos/git.cgi/myrepo.git cd myrepo.git touch new_file git add new_file git commit -a git push --- Repository Ownership and File Permissions The above starts with a bare-bones repository, and all commits to it is via the WWW. This is important as the server will read-write to the repository, and as such save files with its own ownership and group. All new files will actually be located in the "objects" sub-directory of the GIT repo. --- Error Handling.. If you get a "error: unpack failed: unpack-objects abnormal exit" you have a write permission issue, on the "objects" for the web server. Try running a HEAD URL request directly https://www.example.com/anthony/git_repos/git.cgi/myrepo.git/HEAD This should return something like ref: refs/heads/master. Run the above clone with more error handling GIT_CURL_VERBOSE=1 GIT_TRACE=1 git clone https://.... For this a more complex git.cgi script is needed Note a writable log.txt is uploaded touch log.txt chmod 666 log.txt vi git.cgi #!/bin/sh export GIT_PROJECT_ROOT=/home/anthony/public_html/git_repos export REMOTE_USER="${REMOTE_USER:-$REDIRECT_REMOTE_USER}" exec 2>>log.txt echo >&2 "-----------------------" date >&2 "+%Y-%m-%d_%H:%M:%S" git http-backend "$@" || echo failed >&2 and after running look at the "log.txt" file created Error message meanings Service not enabled: 'receive-pack' This means you attempted to push a repository without authentication ------------------------------------------------------------------------------- Garbage Collection... Create a script called "gc.cgi" and run it every so often to 'clean up' the repositories vi gc.cgi #! /bin/sh echo 'Content-Type: text/plain' echo for repo in *.git; do printf "%s ... " "$repo" (cd "$repo" && git gc) && echo "OK" || echo "failed" done chmod 755 gc.cgi https://www.example.com/anthony/git_repos/gc.cgi =============================================================================== Remap the CGI script... This method uses some rewrite rules to remove the need to referance the CGI script, by having the server remap the repository path though the CGI script. A general guide https://github.com/tmacam/private-git-on-dreamhost and a updated version on http://www.burocrata.org/blog/archives/2010/11/08/345/ Which also sets up a 'gitweb' overview for the respoitory area NOTE: these last two are actually a better guide than this. But... CAVAT: The only difference from 'DreamHost' to 'Hobbit' is that 'Hobbit' needs the repositories to be writable by the apache webserver. The former 'DreamHost' uses "SUexec" to run CGI scripts as the script owner rather than as the apache web server. Set up directory (as before). mkdir ~/public_html/git_repos chmod 705 ~/public_html/git_repos cd ~/public_html/git_repos The ".htaccess" file is... NOTE: Replace paths containing "anthony" and "git_repos" as appropriate =======8<-------- # # Directory Options # Options +ExecCGI #Options +Indexes # # Authenticate everyone entering this directory # AuthType Basic AuthName "GIT Repository" AuthUserFile /home/anthony/public_html/git_repos/.htpasswd AuthGroupFile /dev/null Require valid-user Order allow,deny Allow from localhost # # Redirect GIT requests through the git-http-backend.cgi script # RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d #RewriteCond %{REQUEST_URI} ^/anthony/git_repos/.*\.git/(.*/(HEAD|info/refs|objects/(info/[^/]+|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))|git-(upload|receive)-pack))$ RewriteCond %{REQUEST_URI} ^/anthony/git_repos/.*\.git/ # Route requests through the backend CGI script in this directory RewriteRule (.*) /anthony/git_repos/git-http-backend.cgi/$1 =======8<-------- chmod 644 .htaccess The "git-http-backend.cgi" script (as above)... =======8<-------- #!/bin/bash export GIT_PROJECT_ROOT=~anthony/public_html/git_repos export REMOTE_USER="${REMOTE_USER:-$REDIRECT_REMOTE_USER}" exec git http-backend "$@" =======8<-------- chmod 705 .htaccess See notes about the script above. Create a ".htpasswd" htpasswd -c .htpasswd anthony New password: my secret password Re-type password: my secret password Adding password for user anthony chmod 644 .htpasswd Create a bare test repo "myrepo.git" -- as per "create_repo.cgi: script above REPO=myrepo.git DESC="Description of my Example Repo" mkdir $REPO ( cd $REPO git --bare init git --bare update-server-info echo "$DESC" > description cp hooks/post-update.sample hooks/post-update chmod a+x hooks/post-update # The following are to ensure the repo is exportable via HTTP(s) touch git-daemon-export-ok find . -type f -print | xargs chmod 666 find . -type d -print | xargs chmod 777 ) echo "---------------" ls -Fla $REPO Testing in another location, or machine... git clone https://www.example.com/anthony/git_repos/myrepo.git cd myrepo.git touch new_file git add new_file git commit -a git push For some strange reason the password is needed on "git push" as well! --- NOTE: a CGI script does NOT need to have a ".cgi" suffix if it is declared to be a CGI script in the ".htaccess" file. =======8<-------- # make "cgi-executable-file" executed as a CGI script. SetHandler cgi-script =======8<-------- =============================================================================== SERVER Config methods... From the git-http-backend manpage https://www.kernel.org/pub/software/scm/git/docs/git-http-backend.html You do not need to set the environment variables at all if you include the URI path after the CGI script part of the URL. That is if GIT_PROJECT_ROOT is not set, git http-backend reads PATH_TRANSLATED, whcih is part of the CGI interface protocol. For example if a "git-http-backend" is in the servers standard "cgi-bin", but does not set a GIT_PROJECT_ROOT environemnt vaiable then you should be able to do this. https://server.domain/cgi-bin/git-http-backend/~s123456/git_repos/myrepo.git THIS HAS NOT BEEN TESTED With a script alias such as ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/ The last URL becomes https://server.domain/git/~s123456/git_repos/myrepo.git If the server does set a *single* GIT_PROJECT_ROOT environment variable and "myrepo.git" is in that area, then the above becomes the more commonly known GIT repository URL. https://server.domain/git/myrepo.git Basically by using server configuration, you are only providing a scheme for 'URL beautification' The technique is nicely explained in http://git-scm.com/2010/03/04/smart-http.html ------------------------------------------------------------------------------- Alternative to CGI is to look at using a PHP solution "GitPHP" http://gitphp.org/projects/gitphp/wiki -------------------------------------------------------------------------------