UP | HOME

soft-serve git serve 和静态 git 页面

我喜欢 soft-serve

它比 gitea/forgejo/gitlab 更轻量:没有 wiki、软件包之类一些可有可无的周边功能,没有复杂的用户和组织权限,甚至没有 Issue/PR。

它比 cgit/git-daemon 更完整:支持 http, git, ssh 三种协议克隆仓库。通过 ssh cli (ssh git.charm.sh help) 即可进行仓库管理。(cgit 不会处理 go-get 的请求,需要自己在中间件里注入,就很别扭)

Static web service

soft-serve 没有 web 前端展示仓库。

动态的 git 仓库前端渲染,是一个比较耗费性能的功能,加上我的 git 仓库的前端界面不是特别重要,只需要能看一下软件介绍,能简单翻阅一下代码。静态的网页显然已经足够了。

可选的 git 静态网页生成器有:

我选了 depp ,仅仅因为是我认识的人写的,加上 golang 改起来比较方便。

在服务端用 git post-receive hook 生成:

# file: $SOFT_SERV_DATA_PATH/hooks/post-receive
# $SOFT_SERV_DATA_PATH/hooks 为soft-serve 公用 git hooks 目录

if [ -f "$SOFT_SERVE_REPO_PATH/git-daemon-export-ok" ]; then
        depp -c 10 \
             -u "$SOFT_SERVE_GIT_PUBLIC_URL/$SOFT_SERVE_REPO_NAME.git" \
             -d "/srv/http/git/$SOFT_SERVE_REPO_NAME" \
             "$SOFT_SERVE_REPO_PATH"
else 
        [ -z "$SOFT_SERVE_REPO_NAME" ] || rm -rf "/srv/http/git/$SOFT_SERVE_REPO_NAME"
fi

# using my fork: https://git.lin.moe/fork/depp
depp-index -r -x -d /srv/http/git -t git.lin.moe $SOFT_SERVE_DATA_PATH/repos

全部的 server-side hooks 在 https://git.lin.moe/githooks/

nginx 需要能展示静态页面的同时,还要能将 git 请求传递到 soft-serve ,需要写一两条规则:

upstream soft-serve {
        server localhost:23232;
}

server{
        listen 443 ssl;
        listen [::]:443 ssl;

        server_name git.lin.moe;
        http2 on;

        ssl_certificate /path/to/certificate.pem;
        ssl_certificate_key /path/to/prikey.pem;
        root /srv/http/git/;

        location / {
                if ($arg_go-get != "") {
                        proxy_pass http://soft-serve;
                }
                try_files $uri $uri/ @softserve;
        }

        location @softserve {
                proxy_pass http://soft-serve;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $remote_addr;
                proxy_set_header X-Forwarded-Proto $scheme;
        }
}

SSH CLI wrapper

使用 ssh myserver.ltd 的方式有几个小缺点:

  • 命令太长了
  • 相比本地 cli 稍微会有一点慢,每次都要建立新的 ssh 连接
  • ssh 协议是将所有命令参数作为一个字符串传递到服务端,遇到带引号的参数就无法保持原意了,比如 ssh myserver.ltd repo demo desc "This is my repo" ,服务端实际看到的是 repo demo desc This is my repo

也为了以后方便支持 shell completion ,我写了一个小脚本:

: ${RGIT_CONTROL_PATH:="$HOME/.ssh/controlmaster/rgit"}
: ${RGIT_INSTANCE:="ssh://git.lin.moe"}

[ -d $(dirname $RGIT_CONTROL_PATH) ] || mkdir $(dirname $RGIT_CONTROL_PATH)
if [ ! -S $RGIT_CONTROL_PATH ]; then
        ssh -f -N \
            -o ExitOnForwardFailure=yes \
            -o ControlMaster=auto \
            -o ControlPath="$RGIT_CONTROL_PATH" \
            -o ControlPersist=1h \
            $RGIT_INSTANCE
fi

_quoted_args(){
        echo -n "'$1'"
        shift
        for arg in "$@"; do
                arg=$(echo $arg | sed "s/'/'\"'\"'/g")
                echo -n " '$arg'"
        done
}

ssh -o ControlMaster=auto \
    -o ControlPath="$RGIT_CONTROL_PATH" \
    -T $RGIT_INSTANCE "$(_quoted_args "$@")"

Issue/PR

用邮件列表