有没有办法可以从 git repo 中的分支提供文件,而无需将它们检出到不同的目录中?
我喜欢能够创建一个新分支、将其推送到测试服务器存储库,然后执行诸如浏览到 http://分店名称.test.com。我可以使用重写规则来处理分支名称子域以指向不同的根路径,但 Apache 当然无法读取裸存储库。
吉特夫斯可能会有用,但似乎已被废弃。
我也不特别需要 Apache。
答案1
最简单的方法是检查每个分支并在子目录中为每个分支创建克隆。使用 cron 运行的脚本(或在提交后挂钩中)可以很容易地做到这一点,例如:
#!/bin/sh
ROOT=/srv/repos/control
cd ${ROOT} # it's an internal repo
git fetch
for ref in .git/refs/remotes/origin/*; do
BRANCH=`basename ${ref}`
if ! [ -d ../${BRANCH} ]; then
git clone --local ${ROOT} ../${BRANCH}
cd ../${BRANCH}
git branch --track ${BRANCH} remotes/origin/${BRANCH}
git checkout ${BRANCH}
else
cd ../${BRANCH}
git pull
fi
done
它工作完成后,你会得到一堆带有分支的目录/srv/repos
。
git clone --local
即使在 Linux 内核等大型存储库上也非常快速且优化,因为它不会在存储库中创建所有对象,而是创建指向它们的硬链接,因此您不会在存储库副本上浪费任何空间。虽然您会在签出的副本上浪费空间,但 a) 它们可能不是很大,b) 这将使基于 Web 的访问更加轻松快捷。
答案2
您可以使用 git-show(或 git cat-file)和 Apache CGI 或类似程序的组合直接从存储库提供内容。我使用 .htaccess 和一个简单的 zsh 脚本设置了一个示例,如下所示:
.htaccess
Options +ExecCGI
AddHandler cgi-script .sh
RewriteEngine On
RewriteRule ^(?!index.sh)(.*)$ /index.sh [L]
索引文件
#!/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 中。如评论所述,可以对脚本进行大量改进。这更像是一个概念验证。
答案3
另请参阅分歧,一个将 git 分支映射到子域的 rack 应用程序。我自己还没有用过它,但它似乎很适合你的需求。