Вы можете обслуживать контент непосредственно из репозитория, используя комбинацию git-show (или git cat-file) и Apache CGI или аналогичного. Я настроил пример с использованием .htaccess и простого скрипта zsh:
.htaccess
Options +ExecCGI
AddHandler cgi-script .sh
RewriteEngine On
RewriteRule ^(?!index.sh)(.*)$ /index.sh [L]
index.sh
#!/bin/zsh
# Strips the initial slash, as git show ain't got time for that!
# REQUEST_URI is set by Apache when executing the script.
# You may also be interested in HTTP_HOST which is the request host.
# Don't get confused with HOST which is a default shell variable.
function get_request_uri {
if [ $REQUEST_URI[0,1] = '/' ]
then
REQUEST_URI=$REQUEST_URI:s#/##
fi
echo $REQUEST_URI
}
# You may not want to show the folders (represented by trees).
# Or you may want to manipulate the output to produce a proper directory index.
function is_file_folder {
[ $(git cat-file -t HEAD:$1) = 'tree' ]
}
# Just gets the content of the file.
# For trees will produce a directory listing, one line per file.
# To show different branches, pass them to git show in place of HEAD
function get_file_content {
local file=$1
git show HEAD:${file}
}
# Attempts to determine the file type without writing the data to a file.
# Has to resort to manually looking up the type in /usr/share/mime/globs
# to test by extension, you may have to adjust that code to your environment.
function get_file_type {
local file=$1
local content=$2
mime_type=$(echo ${content} | mimetype -b --stdin)
if [ -e /usr/share/mime/globs ]
then
file_mime_type=$(
grep "\*.${file:e}\$" /usr/share/mime/globs |
sed -ne 's/:.*$//' -e '1p'
)
# Conflict resolution is also something you should work on.
if [ $file_mime_type != '' ]
then
mime_type=$file_mime_type
fi
fi
echo $mime_type
}
function do_404 {
echo 'Status: 404 Not Found'
echo ''
}
# Just does the header because there can be problems
# getting binary data to the client by echoing it.
# A little something for you to explore a fix for :)
function do_200 {
mime_type=$1
echo "Content-Type: $mime_type"
echo ''
}
cd site.git
uri=$(get_request_uri)
file_content=$(get_file_content $uri)
# A non zero exit status from git show probably means the file does not exist.
# Even if the error was something else, you still have nothing to show for it.
if [ $? -ne 0 ]
then
do_404
fi
# You may not want to do the directory listing. Even if you do, you may
# not want to use the default directory listing (which is very primitive).
# If you wanted to redirect to index or similar, you would also handle that
# here.
if is_file_folder $uri
then
file_type='text/plain'
else
file_type=$(get_file_type $uri "$file_content")
fi
do_200 $file_type
# Doing this twice is not optimal, but it is very easy to
# mangle binary data accidentally when passing around the
# $file_content. Just reading the file directly to the client
# seems to sidestep this. Another thing for you to fix :)
get_file_content $uri
# You might want to uncomment the two lines below (commenting out
# any response code from above first), to show all of the variables
# available to you. This list will include the variables set by this
# script - to filter them out just run this earlier, with an exit after.
# do_200 'text/plain'
# set
# vim: set ai et sw=4 syntax=zsh :
Это предполагает, что ваш сайт находится в site.git в той же папке, что и два файла выше. Есть много улучшений, которые могут быть сделаны в сценарии - как прокомментировано. Это скорее подтверждение концепции.