summaryrefslogtreecommitdiffstats
path: root/code/linux/gitserver.md
diff options
context:
space:
mode:
Diffstat (limited to 'code/linux/gitserver.md')
-rw-r--r--code/linux/gitserver.md485
1 files changed, 470 insertions, 15 deletions
diff --git a/code/linux/gitserver.md b/code/linux/gitserver.md
index d0ed6d9..53add30 100644
--- a/code/linux/gitserver.md
+++ b/code/linux/gitserver.md
@@ -30,7 +30,7 @@
30 30
31当然,创建单独用户的理由不止这么简单,它在我们使用 http 来托管仓库的时候有专门的作用,下文会讨论到。 31当然,创建单独用户的理由不止这么简单,它在我们使用 http 来托管仓库的时候有专门的作用,下文会讨论到。
32 32
33我为其创建了一个名为`git`的用户,家目录`/home/git`,但不授予 sudo 权限。 33我为其创建了一个名为`git`的用户,家目录`/home/git`,但**不授予 sudo 权限**
34 34
35# ssh 服务 35# ssh 服务
36 36
@@ -70,8 +70,8 @@ bash push.sh
70read -p "Local repo name: " local_name 70read -p "Local repo name: " local_name
71read -p "Remote repo name: " remote_name 71read -p "Remote repo name: " remote_name
72 72
73# 远程仓库创建 73# 远程仓库创建,用的时候记得改服务器地址
74tmp="ssh aliyun-git git init --bare $remote_name.git" 74tmp="ssh your-server git init --bare $remote_name.git"
75eval "$tmp" 75eval "$tmp"
76 76
77# 本地仓库创建 77# 本地仓库创建
@@ -121,7 +121,7 @@ echo "Success!"
121 121
122于是,我发现了一篇[教程](https://www.aneasystone.com/archives/2018/12/build-your-own-git-server.html),照葫芦画瓢起来。 122于是,我发现了一篇[教程](https://www.aneasystone.com/archives/2018/12/build-your-own-git-server.html),照葫芦画瓢起来。
123 123
124需要注意的是,**上面的 ssh 服务不一定需要专门创建用户,但 http(s)服务这里我推荐新建用户**。 124需要注意的是,**仍然建议为 git 仓库专门建用户**。
125 125
126## 配套软件安装 126## 配套软件安装
127 127
@@ -224,16 +224,16 @@ admin [27/Nov/2018:22:19:33] "POST /test.git/git-receive-pack HTTP/1.1" 200 63 "
224server 224server
225{ 225{
226 listen 80; 226 listen 80;
227 server_name git.qin-juan-ge-zhu.top; 227 server_name git.player.com;
228 return 301 https://$host$request_uri; 228 return 301 https://$host$request_uri;
229} 229}
230server 230server
231{ 231{
232 server_name git.qin-juan-ge-zhu.top; 232 server_name git.player.com;
233 listen 443 ssl; 233 listen 443 ssl;
234 234
235 ssl_certificate /etc/letsencrypt/live/git.qin-juan-ge-zhu.top/fullchain.pem; 235 ssl_certificate /etc/letsencrypt/live/git.player.com/fullchain.pem;
236 ssl_certificate_key /etc/letsencrypt/live/git.qin-juan-ge-zhu.top/privkey.pem; 236 ssl_certificate_key /etc/letsencrypt/live/git.player.com/privkey.pem;
237 237
238 location @auth { 238 location @auth {
239 auth_basic "Git Server"; 239 auth_basic "Git Server";
@@ -354,15 +354,470 @@ usermod -aG git www-data
354 354
355此时再进行测试,应该就可以正常使用了。 355此时再进行测试,应该就可以正常使用了。
356 356
357## 其他存在的问题 357# cgit 拥抱图形化
358
359到了 http(s)服务这里,我们在命令行里进行 git 操作的需求已经基本得到了满足。但是,生命不息,折腾不止,我们发现有一个能图形化显示仓库的界面、并且要仍然能在命令行里进行仓库操作,最是舒坦。
360
361- GitList 的界面看起来不错,而且能展示源码、clone 链接之类的,整体非常像 github 的界面,可惜使用的是我不会的 php 语言,而且没有找到详细一些的安装使用教程
362- cgit 是一个用纯 C 语言开发的一个 git 裸库展示,虽然界面看起来比较古早,但功能简单、强大,能展示源码、自由切换分支、方便地查看提交历史(diss 一下 github,github 查看提交历史看起来真的很不方便很不直观)。诸如[Linux 内核](https://git.kernel.org)等项目都在使用。
363
364选择了 cgit,我找到了又一位大佬的[博客](https://blog.dejavu.moe/posts/hosting-minimal-git-server-with-cgit),非常详细。需要注意的是,**我们仍然需要一个专门的用户。**
365
366## 依赖
367
368`nginx`/`git`/`vim`等工具不必赘述,还有一些依赖项需要安装:
369
370```bash
371# apache2-utils是用其htpasswd命令创建认证文件的
372# fcgiwrap是用于将 FastCGI 转换为 HTTP 协议的工具
373# 这两个工具上文均已提到和使用,不再赘述
374sudo apt update
375sudo apt install -y apache2-utils fcgiwrap
376
377# 编译过程中需要openssl的头文件
378sudo apt install -y libssl-dev
379
380# 建议为cgit提供lua支持,用来进行个性化的设置
381# 本文以 lua5.1 为例
382sudo apt install liblua5.1-0 liblua5.1-0-dbg liblua5.1-dev lua5.1
383```
384
385## cgit 安装
386
387cgit 最近的正式发行版已经好几年了,但是它的开发仍然很活跃,所以建议从它的 git 仓库中获取最新的代码,而非直接安装:
388
389```bash
390git clone https://git.zx2c4.com/cgit
391cd cgit
392git submodule init
393git submodule update
394```
395
396在仓库目录下创建`cgit.conf`文件,用来存放 cgit 构建时可以覆盖的配置:
397
398```bash
399sed -n '3,31p' Makefile > cgit.conf
400```
401
402我们可以按需编辑之:
403
404```plaintext
405CGIT_VERSION = v1.2.3
406CGIT_SCRIPT_NAME = cgit.cgi
407CGIT_SCRIPT_PATH = /var/www/cgit # 本文只改了这里
408CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH)
409CGIT_CONFIG = /etc/cgitrc # 默认配置文件路径
410CACHE_ROOT = /var/cache/cgit
411prefix = /usr/local
412libdir = $(prefix)/lib
413filterdir = $(libdir)/cgit/filters
414docdir = $(prefix)/share/doc/cgit
415htmldir = $(docdir)
416pdfdir = $(docdir)
417mandir = $(prefix)/share/man
418SHA1_HEADER = <openssl/sha.h>
419GIT_VER = 2.39.0
420GIT_URL = https://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.xz
421INSTALL = install
422COPYTREE = cp -r
423MAN5_TXT = $(wildcard *.5.txt)
424MAN_TXT = $(MAN5_TXT)
425DOC_MAN5 = $(patsubst %.txt,%,$(MAN5_TXT))
426DOC_HTML = $(patsubst %.txt,%.html,$(MAN_TXT))
427DOC_PDF = $(patsubst %.txt,%.pdf,$(MAN_TXT))
428
429ASCIIDOC = asciidoc
430ASCIIDOC_EXTRA =
431ASCIIDOC_HTML = xhtml11
432ASCIIDOC_COMMON = $(ASCIIDOC) $(ASCIIDOC_EXTRA)
433TXT_TO_HTML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_HTML)
434```
435
436编译 && 安装:
437
438```bash
439# 如果不需要lua支持
440make NO_LUA=1
441# 有lua支持的话
442make LUA_PKGCONFIG=lua5.1
443
444# 安装,注意一下安装路径
445# 不妨将输出写到日志里,以便查看
446sudo make install | tee install.log
447```
448
449## nginx 配置
450
451首先,参照[这里](认证文件)生成一个自己的认证文件,再继续往下看。
452
453在`/etc/nginx/git-http-backend.conf`中写入以下内容,注意把域名、ssl 路径、htpasswd 认证文件换成自己的:
454
455```conf
456# /etc/nginx/git-http-backend.conf
457fastcgi_pass unix:/var/run/fcgiwrap.socket;
458include fastcgi_params;
459fastcgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend;
460fastcgi_param GIT_HTTP_EXPORT_ALL "";
461fastcgi_param GIT_PROJECT_ROOT /home/git;
462fastcgi_param PATH_INFO $1;
463fastcgi_param REMOTE_USER $remote_user;
464```
465
466而后,在`/etc/nginx/conf.d/cgit.conf`中写:
467
468```conf
469# /etc/nginx/conf.d/cgit.conf
470server {
471 listen 80;
472 server_name git.player.com;
473 return 301 https://$server_name$request_uri;
474}
475
476server {
477 server_name git.player.com;
478 listen 443 ssl http2;
479
480 ssl_certificate /etc/letsencrypt/live/git.player.com/fullchain.pem;
481 ssl_certificate_key /etc/letsencrypt/live/git.player.com/privkey.pem;
482
483 # SSL Security
484 ssl_protocols TLSv1.2 TLSv1.3;
485 ssl_prefer_server_ciphers on;
486 ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256;
487
488 ssl_session_timeout 1d;
489 ssl_session_cache shared:SSL:10m;
490
491 # Site Log path
492 access_log /var/log/nginx/cgit-access.log;
493 error_log /var/log/nginx/cgit-error.log;
494
495 root /var/www/cgit;
496 try_files $uri @cgit;
497 client_max_body_size 10m;
498
499 location @cgit {
500 include fastcgi_params;
501 # cgit's CGI script path
502 fastcgi_param SCRIPT_FILENAME /var/www/cgit/cgit.cgi;
503 fastcgi_param DOCUMENT_ROOT /usr/lib/git-core;
504 fastcgi_pass unix:/var/run/fcgiwrap.socket;
505 fastcgi_param PATH_INFO $uri;
506 fastcgi_param QUERY_STRING $args;
507 fastcgi_param HTTP_HOST $server_name;
508 fastcgi_param GIT_HTTP_EXPORT_ALL "";
509 fastcgi_param GIT_PROJECT_ROOT /home/git;
510
511 if ($arg_service = git-receive-pack) {
512 rewrite (/.*) /git_write/$1 last;
513 }
514
515 if ($uri ~ ^/.*/git-receive-pack$) {
516 rewrite (/.*) /git_write/$1 last;
517 }
518
519 if ($arg_service = git-upload-pack) {
520 rewrite (/.*) /git_read/$1 last;
521 }
522
523 if ($uri ~ ^/.*/git-upload-pack$) {
524 rewrite (/.*) /git_read/$1 last;
525 }
526 }
527
528 location ~ /git_read/(.*) {
529 include git-http-backend.conf;
530 }
531
532 location ~ /git_write/(.*) {
533 # HTTP Basic Authentication
534 auth_basic "Authentication Required To Push";
535 auth_basic_user_file /etc/nginx/conf.d/git.htpasswd;
536 include git-http-backend.conf;
537 }
538}
539```
540
541最后,重启 nginx 服务:
542
543```bash
544sudo nginx -s reload
545```
546
547_看吧,一个个仓库,向我们列队走来!_
548
549## cgit 高级配置
550
551可以安装一些包,用于 cgit 的代码高亮、Markdown 渲染、Gravatar 头像渲染等:
552
553```bash
554sudo apt install -y python3-docutils python3-markdown highlight python3-pygments
555
556# 编译安装 LuaoSSL
557# https://25thandclement.com/~william/projects/luaossl.html
558git clone https://github.com/wahern/luaossl.git && cd luaossl
559make LUAPKG=lua5.1
560sudo make install LUAPKG=lua5.1
561
562sudo mkdir -p /usr/local/share/cgit
563sudo ln -s /usr/local/lib/cgit/filters /usr/local/share/cgit/filters
564sudo chown -R www-data:www-data /usr/local/share/cgit/
565
566# 给下面使用 filter api 的脚本赋予可执行权限,比如
567sudo chmod +x /usr/local/share/cgit/filters/email-gravatar.lua
568```
569
570然后编辑上边我们已经指定的配置文件`/etc/cgitrc`,更多配置项参见[cgitrc.5.txt](https://git.zx2c4.com/cgit/tree/cgitrc.5.txt)。
571
572```plaintext
573# /etc/cgitrc
574# 包含 cgit 的所有运行时设置
575# 格式 NAME=VALUE
576# 以 "#" 开头的行是注释
577
578# 全局配置
579css=/cgit.css
580logo=/cgit.png
581favicon=/favicon.ico
582#footer=
583virtual-root=/
584# 禁用哑克隆
585enable-http-clone=0
586
587# Smart HTTP
588# 记得改成自己的链接
589clone-url=https://git.player.com/$CGIT_REPO_URL
590# 首页标题显示的内容,改成你想要的
591root-title=GIT.PLAYER.COM
592root-desc=YOUR.WORDS
593# 在首页展示的介绍信息,可用md/man/html等
594# 详参/usr/local/share/cgit/filters/about-formatting.sh
595root-readme=/var/www/cgit/README.md
596
597# 建议配置
598enable-index-owner=1
599enable-index-links=1
600enable-blame=1
601enable-log-filecount=1
602enable-log-linecount=1
603enable-commit-graph=1
604
605# 禁止搜素引擎索引
606robots=noindex, nofollow
607
608branch-sort=age
609commit-sort=date
610max-stats=quarter
611snapshots=tar.gz zip
612
613# 使用 RAM 的缓存大小 单位 MB
614cache-size=1024
615
616# 代码高亮
617source-filter=/usr/local/share/cgit/filters/syntax-highlighting.py
618
619# 格式化贡献者,显示Gravatar头像
620email-filter=lua:/usr/local/share/cgit/filters/email-gravatar.lua
621
622# 格式化 about 页面
623about-filter=/usr/local/share/cgit/filters/about-formatting.sh
624readme=:README.md
625readme=:readme.md
626readme=:README.txt
627readme=:readme.txt
628readme=:README
629readme=:readme
630
631# MIME 类型
632mimetype.html=text/html
633mimetype.gif=image/gif
634mimetype.jpg=image/jpeg
635mimetype.jpeg=image/jpeg
636mimetype.png=image/png
637mimetype.webp=image/webp
638mimetype.pdf=application/pdf
639mimetype.svg=image/svg+xml
640
641# 移除 .git 后缀,很有必要
642remove-suffix=1
643
644# 扫描路径
645scan-path=/home/git
646
647# 每个存储库配置
648#repo.url=reponame
649#repo.path=/home/git/reponame.git
650#repo.desc=Some description here
651#repo.owner=Owner Name
652#repo.logo=/repo-logo.png
653```
654
655### 高亮风格
656
657在上面的配置文件里,我们使用了[Pygments](https://pygments.org/styles/)的代码高亮。其默认使用的高亮是 pastie,我们可以根据自己的喜好修改高亮风格。
658
659首先,看看有哪些可用的高亮风格。
660
661```bash
662# 查看可用的高亮风格
663pygmentize -L styles
664
665# 编辑我们使用的代码高亮脚本
666sudo vim /usr/local/share/cgit/filters/syntax-highlighting.py
667```
668
669### Gravatar 头像
670
671在上述配置中,我们使用了 Gravatar 头像。[Gravatar](https://cn.gravatar.com/) 是一个全球通用的头像服务,根据你使用的邮箱(而非用户身份)来为你提供头像。换言之,只要你的邮箱注册了 Gravatar,那么你在任何一个支持 Gravatar 的网站上都可以使用你的 Gravatar 头像。这对于我们这种不想做登录、又想展示用户的网站来说,是一个很好的选择。
672
673- [中文官网](https://cn.gravatar.com/)
674- [英文官网](https://gravatar.com/)
675
676由于 Gravatar 中文官网访问比较慢(不知道为什么,英文官网我挂了梯子还上不去),我们可以使用国内的镜像服务。这里有一篇常用镜像服务的[博客](https://luoxx.top/archives/gravatar-mirror-2022)。我使用的是[Cravatar](https://cravatar.cn/)。
677
678使用流程都是基本一致的,在这个网站上注册账号,上传头像,然后根据网站提供的 API 来获取。一般方式为`https://域名.com/avatar/邮箱的md5值`。在我们使用的脚本`/usr/local/share/cgit/filters/email-gravatar.lua`中,将原有的域名替换为我们使用的域名即可。
679
680cgit 的[官网](https://git.zx2c4.com/cgit/)上不仅能实现 Gravatar 头像,还能在鼠标移动到头像上的时候以大图显示。这不是原生功能,而是需要动 lua 脚本自己实现。原博客大佬在 cgit 的[邮件列表](https://lists.zx2c4.com/pipermail/cgit/2014-March/002036.html)找到了实现方式。
681
682```bash
683sudo vim /usr/local/share/cgit/filters/email-libravatar-korg.lua
684```
685
686在脚本中写入以下内容:
687
688```lua
689-- This script may be used with the email-filter or repo.email-filter settings in cgitrc.
690-- It adds gravatar icons to author names. It is designed to be used with the lua:
691-- prefix in filters. It is much faster than the corresponding python script.
692--
693-- Requirements:
694-- luaossl
695-- <http://25thandclement.com/~william/projects/luaossl.html>
696--
697
698local digest = require("openssl.digest")
699
700function md5_hex(input)
701 local b = digest.new("md5"):final(input)
702 local x = ""
703 for i = 1, #b do
704 x = x .. string.format("%.2x", string.byte(b, i))
705 end
706 return x
707end
708
709function filter_open(email, page)
710 buffer = ""
711 md5 = md5_hex(email:sub(2, -2):lower())
712end
713
714function filter_close()
715 html("<span class='libravatar'>" ..
716 "<img class='inline' src='//www.gravatar.com/avatar/" .. md5 .. "?s=13&d=retro' />" ..
717 "<img class='onhover' src='//www.gravatar.com/avatar/" .. md5 .. "?s=128&d=retro' />" ..
718 "</span>" .. buffer)
719 return 0
720end
721
722function filter_write(str)
723 buffer = buffer .. str
724end
725```
726
727只有 lua 还不够,我们需要将以下内容添加到`/var/www/cgit/cgit.css`中:
728
729```css
730/* libgravatar */
731div#cgit span.libravatar img.onhover {
732 display: none;
733 border: 1px solid gray;
734 padding: 0px;
735 -webkit-border-radius: 4px;
736 -moz-border-radius: 4px;
737 border-radius: 4px;
738 width: 128px;
739 height: 128px;
740}
741
742div#cgit span.libravatar img.inline {
743 -webkit-border-radius: 3px;
744 -moz-border-radius: 3px;
745 border-radius: 3px;
746 width: 13px;
747 height: 13px;
748 margin-right: 0.4em;
749 opacity: 0.9;
750}
751
752div#cgit span.libravatar:hover > img.onhover {
753 display: block;
754 position: absolute;
755 margin-left: 1.5em;
756 background-color: #eeeeee;
757 box-shadow: 5px 5px 3px #bbb;
758}
759```
760
761而后,修改`/etc/cgitrc`中的`email-filter`的值为我们新建的脚本`lua:/usr/local/share/cgit/filters/email-libravatar-korg.lua`,就好了。
762
763### 添加 README
764
765在`/etc/cgitrc`中,我们指定了`root-readme`,这是用来在网站主页展示 README 的。我们可以编写一个 README 文件,然后在`/etc/cgitrc`中指明它的路径。README 可以使用`markdown`/`man`/`rst`/html`/`txt`等格式。
766
767我使用的是`markdown`格式,在`/var/www/cgit/`中创建了一个`README.md`文件,然后在`/etc/cgitrc`中指明了路径。
768
769### 样式修改
770
771对于 cgit 显示出来的界面,你可能并不太满意(比如我就嫌界面的字太小、颜色不舒适啥的)。修改办法也很简单,找到`/var/www/cgit/cgit.css`文件,然后修改之。
772
773而对于我们的 Markdown 或者别的什么语言写的 README,如果觉得渲染效果不好,都是可以自己去修改的。
774
775找到`/usr/local/share/cgit/filters/about-formatting.sh`文件,我们会看到以下内容:
776
777```bash
778#!/bin/sh
779
780# This may be used with the about-filter or repo.about-filter setting in cgitrc.
781# It passes formatting of about pages to differing programs, depending on the usage.
782
783# Markdown support requires python and markdown-python.
784# RestructuredText support requires python and docutils.
785# Man page support requires groff.
786
787# The following environment variables can be used to retrieve the configuration
788# of the repository for which this script is called:
789# CGIT_REPO_URL ( = repo.url setting )
790# CGIT_REPO_NAME ( = repo.name setting )
791# CGIT_REPO_PATH ( = repo.path setting )
792# CGIT_REPO_OWNER ( = repo.owner setting )
793# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting )
794# CGIT_REPO_SECTION ( = section setting )
795# CGIT_REPO_CLONE_URL ( = repo.clone-url setting )
796
797cd "$(dirname $0)/html-converters/"
798case "$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')" in
799 *.markdown|*.mdown|*.md|*.mkd) exec ./md2html; ;;
800 *.rst) exec ./rst2html; ;;
801 *.[1-9]) exec ./man2html; ;;
802 *.htm|*.html) exec cat; ;;
803 *.txt|*) exec ./txt2html; ;;
804esac
805```
806
807从这里可以看到,负责渲染的是`/usr/local/share/cgit/filters/html-converters`文件夹中的对于脚本。我们可以自己修改这些脚本,或者自己添加新的脚本,来实现自己想要的渲染效果。
808
809当然,除了网站主页的 README,我们还可以在每个仓库的主页上添加 README。只需要在仓库的根目录下添加 README 文件即可。然后网页上仓库的标签页就会有“About”标签页,显示 README.md 的内容。
810
811到这里,cgit 的配置就基本完成了。重启 nginx 服务,然后访问你的域名,就可以看到一个很漂亮的界面了;命令行里,也可以 clone、push、fetch、pull 我们托管的仓库。大功告成!
812
813# 其他存在的问题
358 814
359除了上述问题已经解决之外,还有一些问题依然存在: 815除了上述问题已经解决之外,还有一些问题依然存在:
360 816
361- 不管是 nginx 还是 git,在使用 http 上传的时候都会有一定的缓冲区限制,如果上传文件过大或累计多个 commit 才上传,很可能被拒收导致上传失败。这个问题在 github 上也存在,但是 github 的缓冲区限制比较大,一般不会出现这个问题。但是我们的服务器配置比较低,所以这个问题就比较严重了。解决办法是在 nginx 的配置文件中添加`client_max_body_size 100m;`,这样就可以将缓冲区限制扩大到 100M,一般来说足够了。 817- 不管是 nginx 还是 git,在使用 http 上传的时候都会有一定的**缓冲区限制,如果上传文件过大或累计多个 commit 才上传,很可能被拒收导致上传失败**。这个问题在 github 上也存在,但是 github 的缓冲区限制比较大,一般不会出现这个问题;我们的服务器配置比较低,所以这个问题就比较严重了。解决办法是在 nginx 的配置文件中添加`client_max_body_size 100m;`,这样就可以将缓冲区限制扩大到 100M,一般来说足够了。
362- 即使解决了缓冲区大小,偶尔也会被拒收,原因尚未查清 818- 即使解决了缓冲区大小,偶尔也会被拒收,原因尚未查清
363- 尚未能通过访问特定链接来实现 git 仓库的创建。据说是用 nginx 调用脚本,但暂时没弄出来 819- **尚未能通过访问特定链接来实现 git 仓库的创建。**据说是用 nginx 调用脚本,但暂时没弄出来
364- 没有一个比较好用且功能较为完备的图形化界面(就像 github 那样)。 820
365 - GitList 的界面看起来不错,而且能展示源码、clone 链接之类的,整体非常像 github 的界面,可惜使用的是我不会的 php 语言,而且没有找到详细一些的安装使用教程 821这篇博客前前后后有二十多天了,有空再折腾吧。看电视去也~
366 - cgit 是一个用纯 C 语言开发的一个 git 裸库展示,虽然界面看起来比较古早,但功能也很不错,能展示源码、自由切换分支、方便地查看提交历史(diss 一下 github,github 查看提交历史看起来真的很不方便很不直观)。美中不足的是**无法在界面上提供 clone 和源码下载功能**。不过毕竟是个开源软件,而且是我比较熟悉的 C,等有时间有能力了看看自己能不能实现这个功能吧。
367 822
368这篇博客前前后后有二十多天了,该结束了。闲言少叙,看电视去也~ \ No newline at end of file 823<!-- 2024.1.3 -->