# git-panel **Repository Path**: C076lik/git-panel ## Basic Information - **Project Name**: git-panel - **Description**: 本地局域网git托管及自动流水线作业系统 - **Primary Language**: Unknown - **License**: LGPL-3.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2026-05-13 - **Last Updated**: 2026-09-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Git Panel 本地 Git 仓库与 CI 流水线管理平台,提供类 GitHub 的 Web 界面。 **它不是 Demo,而是已在生产环境长期运行的完整平台**:本机(龙芯 loongarch64 / AOSC OS)上托管着 9 个真实仓库,年复一年地承担推送、构建、部署与外部同步。文中列出的每一项能力都在真实仓库上验证过,包括那些"只在出问题时才用得到"的部分(快照回滚、孤儿构建校正、失效地址清理)。 零认证、零数据库、纯文件系统存储:插上硬盘、跑一条命令就能用。 ![仪表盘](docs/images/dashboard.png) > 更多界面见下方[界面预览](#界面预览)。 ## 功能特性 ### 仓库与协议 - **三重协议并行**:Git Smart HTTP(可推可拉)、SSH、`git://` daemon,局域网内免认证开放 - **任意存储路径**:仓库根可放在外部硬盘/USB,Web 界面一键修改;路径解析在后端、部署脚本、CI 三处统一 - **Git LFS 服务端**:完整的 Batch API(上传/下载协商),支持一键启用与关闭(关闭时保留对象,不破坏历史提交) - **分支与标签管理**:创建、删除、切换;分支切换状态不会被刷新重置 - **文件浏览**:目录树、README 渲染、原始字节下载、归档打包下载 - **多格式预览**:JSON 树、CSV 表格、Diff/Patch 着色、Log 级别高亮、PDF/图片/视频/音频、Markdown - **文件树实时搜索**、**全库代码搜索** - **分支对比**:任选两个分支/标签,查看文件级差异(状态、增删统计、按需展开单文件 patch) - **提交 diff 查看器**:点击提交查看该次改动的文件列表与逐文件差异 - **语言统计**:基于 `cloc`,自动排除文档/配置/脚本 ### 存储与快照 - **三级快照降级链**:btrfs 原生只读子卷快照(零额外空间、秒级)→ reflink 复制(XFS 等)→ 普通复制(ext4 等) - **不支持的磁盘自动退回普通复制**,并在界面上明确提示会占用额外空间,绝不静默失败 - **子卷转换**:把已有仓库原地转为 btrfs 子卷以启用原生快照,失败自动回滚(`fsck` 校验、旧数据不丢) - **快照恢复**:btrfs 用原子换名,保留原快照;支持快照列表、删除与保留策略 ### CI/CD - **推送自动触发构建**:`post-receive` 钩子从 stdin 解析真实分支并自动校正悬空 HEAD - **CI 配置自动识别**:GitHub Actions / GitLab CI 兼容,另有 Python·UV / C·C++ / Go / Rust / Java / TypeScript / Lua 多语言模板 - **CD 持续部署**:构建成功后执行部署步骤,也支持手动触发 - **构建看板与统计**:历史趋势、成功/失败占比、日历热力图 - **构建日志**:按步骤折叠、ANSI 颜色渲染、按日期分组 - **孤儿状态自愈**:服务重启后自动校正"卡在构建中"的残留状态(三重存活校验,防 PID 复用误判) - **构建产物清理**:按保留策略清理旧 Release,支持预览,开发版始终保留 - **外部智能体接口**:`GET /build-summary` 供轮询最新状态;`/api/help` 自描述全部 99 个端点 ### 通知与集成 - **Webhook 统一管理页**:按**地址**而不是按仓库汇总,一眼看到每个地址被哪些仓库使用、投递成功率、最后投递时间,可一次性从所有引用处移除 - **历史残留地址识别**:自动找出"已不在任何配置里、却仍在刷失败记录"的地址(换 IP / 服务下线后的残留),支持逐个或批量清理 - **通知中心**:全局聚合投递记录、未读角标、按事件类型静音、桌面系统通知(KDE 等 Linux 桌面实测可用) - **记录清理**:按天数 / 只清失败 / 清空全部,支持按仓库或按地址限定;先预览条数再执行 - **远程同步**:一键推送到 Gitee / GitCode / GitHub 等外部远端 ### 权限与运维 - **SSH 公钥管理**:支持 `curl` 一键提交(`/api/ssh-keys/raw`) - **部署令牌管理**:面向 CI/脚本的访问令牌 - **用户显示名与颜色**:按客户端 IP 记录,活动日志中可区分是谁 - **活动日志(审计)**:全量操作留痕,按日期折叠,可跳转仓库 - **磁盘监控**、**存储能力探测** - **系统配置**:仓库路径、数据路径、全局 Webhook 集中配置 - **一键重启服务**(需配置 NOPASSWD sudoers 规则) ### 工程与质量 - **17 个测试套件、236 个用例**:覆盖钩子生成、版本解析、快照降级链、diff 解析、通知水位线、孤儿判定、清理边界等易错路径 - 其中 `webhook-api.test.ts` 会**真起服务进程 + 真发 HTTP**(隔离临时目录),因为有些缺陷只有跑起来才暴露 - **后端核心逻辑抽成无副作用模块**,可被测试直接引入 - **99 个 API 端点全部登记进 `/api/help`**,并有测试守护防止漏登 - **Vue 3 SPA 前端**,GitHub Dark Dimmed 主题,响应式布局 - **Nginx 反向代理**(关闭缓冲以支持大仓库推送),配置由模板生成、模板本身保持可移植 - **systemd 托管**:`KillMode=process` 保证重启面板不会连带杀掉正在跑的构建 ## 这工具适合谁? | ✅ 适合 | ❌ 不适合 | |--------|----------| | 3-5 人小团队,**不想买 GitHub Pro / GitLab 企业版** | 你需要多租户、RBAC 权限管理(请用 GitLab) | | 你在**局域网/内网**开发,没有公网 IP 和域名 | 你需要 GitHub Actions 的云端并行构建矩阵 | | 你的构建产物很大,想**存到外部硬盘/USB** | 你需要 Kubernetes + Docker 的容器化 CI | | 你想**推送代码后自动构建、自动发版**,但不想写 YAML | 你需要复杂的流水线编排(如 Jenkins Pipeline) | | 你的服务器是**龙芯/ARM 等特殊架构**,主流 CI 不支持 | 你需要 SaaS 托管(如 GitHub Actions、Travis CI) | | 你想**秒级备份仓库**(btrfs 原生快照 / reflink),硬盘坏了不怕 | 你已经有完善的 DevOps 基础设施 | | 你想让**外部智能体/设备**通过 Webhook 与构建状态接口接入 | 你的仓库必须放到公网(本项目为可信局域网设计,无鉴权) | 一句话:**当你想在自己的局域网里搭一个"够用"的 GitHub,零认证、零数据库、插上硬盘就能跑的时候。** > ⚠️ **安全边界**:面板默认无鉴权,**仅供可信局域网使用**,不要直接暴露到公网。若需公网访问,请自行在反向代理层加认证与 TLS。 --- ## 界面预览 以下截图取自真实运行环境(龙芯 loongarch64,浏览器全屏访问 `http://192.168.1.64`),其中托管着 9 个真实仓库。 **落地页** —— 打开面板先看到连接方式与上手说明:三种协议怎么用、怎么建仓库、CI/CD 怎么接 ![落地页](docs/images/landing.png) **仪表盘** —— 存储路径、磁盘余量、仓库列表与最近活动一屏可见 ![仪表盘](docs/images/dashboard.png) **仓库详情** —— 文件树、README 渲染、分支切换、提交历史;右侧是当前提交的说明 ![仓库详情](docs/images/repo-detail.png) **CI/CD 构建历史** —— 按日期分组折叠、今天默认展开;上方是当前构建的步骤与实时状态 ![CI/CD 构建历史](docs/images/ci-build.png) **Webhook 统一管理** —— 按**地址**而不是按仓库汇总:谁在用、成功率、最后投递时间,失效地址可从所有引用处一次移除 ![Webhook 统一管理](docs/images/webhook-manager.png) **通知中心** —— 全局聚合投递记录,支持按事件类型静音、桌面系统通知与按条件清理(先预览条数再执行) ![通知中心](docs/images/notifications.png) --- ## 项目结构 ``` git-panel/ ├── client/ # Vue 3 + TypeScript 前端 │ └── src/ │ ├── components/ # 页面与通用组件(仓库、快照、令牌、Webhook 管理…) │ ├── extensions/ # 扩展页(构建统计、磁盘监控、代码搜索、通知中心) │ ├── App.vue │ └── main.ts ├── server/ # Express + TypeScript 后端 │ ├── server.ts # 主入口(99 个 API 端点) │ ├── ci-runner.py # CI 编排器(构建、部署、Webhook 投递) │ ├── hooks-template.ts # post-receive 钩子的唯一权威实现 │ ├── storage-fs.ts # 快照三级降级链与子卷转换 │ ├── diff-engine.ts # 分支/提交 diff │ ├── webhook-cleanup.ts # 投递记录清理的判定逻辑 │ ├── git-process-reaper.ts # 收割重启遗留的孤儿 git-http-backend │ ├── deploy-config.ts # 仓库根解析(后端/部署脚本/CI 共用) │ ├── version.ts # 版本号解析 │ ├── tests/ # 17 个套件、236 个用例 │ └── extensions/ # 扩展路由(构建统计、磁盘、代码搜索) ├── scripts/ # 特权助手(btrfs)与安装脚本 ├── web-dist/ # 前端构建产物 ├── nginx-full.conf # Nginx 配置模板(含占位符) ├── deploy.sh # 一键部署脚本 └── 版本记录.html # 完整变更历史(含每项的动机与验证方式) ``` ## 快速开始 ### 方式一:npm 全局安装(推荐) ```bash npm install -g @076lik/git-panel # 启动服务(普通用户) git-panel # 自定义端口或仓库路径 git-panel --port=8080 --repo-root=/data/git ``` **系统部署(一次性,需要 sudo):** ```bash sudo git-panel-deploy ``` `git-panel-deploy` 会自动完成:环境预检 → 安装依赖 → 编译前后端 → 生成 nginx 配置 → 创建 systemd 服务 → 配置防火墙 → 启动服务。 ### 方式二:源码一键部署 ```bash cd /home/lik/git-panel sudo bash deploy.sh ``` `deploy.sh` 会自动完成:环境预检 → 安装依赖 → 编译前后端 → 生成 nginx 配置 → 创建 systemd 服务 → 配置防火墙 → 启动服务。 **环境变量覆盖(可选):** ```bash sudo USER=lik REPO_DIR=/home/lik/git PORT=3456 bash deploy.sh ``` ### 方式三:手动开发模式 如需本地开发调试: ```bash # 后端(ts-node 热重载) cd server && npm install && npm run dev # 前端(Vite 热重载) cd client && npm install && npm run dev ``` ### 仓库存储路径 默认存储在 `~/git`,支持通过前端「系统配置」面板修改,保存后点击「重启服务」即可生效(无需手动操作命令行)。 ### Nginx 与防火墙 `deploy.sh` 已自动配置。如需手动: ```bash # Nginx sudo nginx -c /home/lik/git-panel/nginx-full.conf # 防火墙(firewalld 示例) sudo firewall-cmd --add-port=80/tcp --permanent sudo firewall-cmd --add-port=9418/tcp --permanent sudo firewall-cmd --reload ``` ### 防火墙配置(如需手动) 某些发行版(如 AOSC OS)默认会拒绝 1-1024 端口的入站连接。 **图形化方式(AOSC OS):** 打开 **系统设置 → WiFi 和互联网 → 网络设置 → 防火墙设置** → 在列表中 **勾选 `http`** → 点击 **确定** → 点击 **应用**。 **命令行方式(firewalld):** ```bash # 仅允许局域网(推荐) sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.3.0/24" service name="http" accept' sudo firewall-cmd --reload # 全局开放(不推荐暴露在公网) sudo firewall-cmd --add-service=http --permanent sudo firewall-cmd --reload ``` ## 连接方式 | 协议 | 地址 | 说明 | |------|------|------| | Web 面板 | `http://192.168.3.130/` | Nginx 反向代理,标准 80 端口 | | Git (只读) | `git://192.168.3.130/repo.git` | git daemon,端口 9418 | | HTTP (推送) | `http://192.168.3.130/api/git/repo.git` | Nginx → Node.js 3456 | | SSH | `lik@192.168.3.130:/run/media/lik/git/repo.git` | 标准 22 端口 | ## 技术栈 - **后端**: Node.js 20, Express, TypeScript, `git-http-backend` CGI 代理 - **前端**: Vue 3, TypeScript, Vite, highlight.js, marked - **基础设施**: Nginx, btrfs/XFS(快照后端自动探测), Git LFS - **测试**: Node 内置断言 + 真实 git 仓库集成测试(无第三方测试框架依赖) - **工具链**: `cloc`(语言统计) ## 语言统计过滤规则 语言统计基于 `cloc` 计算代码行数,**自动排除**以下非代码类别: | 类型 | 被排除的语言 | |------|-------------| | 文档 | Markdown、reStructuredText、TeX、Text | | 配置/数据 | JSON、YAML、XML、TOML、INI、CSV | | 样式 | HTML、CSS、SCSS、Less、Sass | | 构建/脚本 | Dockerfile、Containerfile、Makefile、make、CMake、Gradle、Shell、Bash、PowerShell、Batch | | 其他 | Log、Source Map、SVG | 如果排除后没有剩余语言,则自动回退显示全部结果(避免空列表)。 ## 推送大仓库优化 ```bash git config --global pack.windowMemory 512m git config --global pack.threads 4 git config --global http.postBuffer 2097152000 ``` > 以上为可选的**性能**调优。需要说明一个曾经的真实缺陷及其修复,避免你再踩: > > **曾经:pack 体积超过 `http.postBuffer`(默认仅 1 MiB)时推送必然失败。** > 超过该阈值后 git 会改用 **chunked 传输**(无 `Content-Length`),而服务端代理把 > 环境变量写成了 `CONTENT_LENGTH: req.headers['content-length'] || '0'` —— git 的 > receive-pack 在缺 `Content-Length` 时是直接报错退出的,`'0'` 等于告诉它「没有请求体」, > 于是客户端看到: > > ``` > send-pack: unexpected disconnect while reading sideband packet > 致命错误:远端意外挂断了 > ``` > > **已修复**:仅在客户端真的给了 `Content-Length` 时才设置该变量,未给则交由 > `git http-backend` 按「读到 stdin EOF」处理(这正是 chunked 所需)。 > 修复后 2.38 MB 的载荷在**默认配置**下推送成功,包体完整(`fsck` 干净、对象可读)。 > 回归测试 `server/tests/git-http-push.test.ts` 用 `-c http.postBuffer=1` 强制走 > chunked 路径,已实测可复现该缺陷(还原缺陷代码即变红)。 > > 这与仓库大小无关,只与**单次推送的 pack 体积**有关 —— 纯文本小提交在很大的仓库上 > 一直都能正常推送,这也解释了为什么它长期难以定位。 ## 测试 后端核心逻辑已抽成无副作用模块,并有回归测试覆盖: ```bash cd server && npm test # 17 个套件,236 个用例 ``` | 套件 | 覆盖内容 | |------|---------| | `post-receive-hook.test.ts` | 钩子从 stdin 解析分支、HEAD 自动校正、删除/标签推送不触发构建 | | `version.test.ts` | 版本号解析(源码布局 / npm 安装布局 / 兜底) | | `deploy-config.test.ts` | 仓库根解析优先级、尾斜杠归一化、配置损坏降级、CLI 输出洁净度 | | `storage-backend.test.ts` | 快照三级降级链的判定与命令分派、路径穿越防护、转换失败回滚 | | `ci-liveness.test.ts` | CI 孤儿状态判定(三重存活校验、pid 复用防护) | | `diff-engine.test.ts` | ref 注入防护、numstat/name-status 解析、改名与二进制边界 | | `notif-read.test.ts` | 通知未读水位线语义与边界 | | `notif-prefs.test.ts` | 按事件类型静音、桌面通知三重过滤、通知文案 | | `info-page-icons.test.ts` | 落地页内联图标与 `client/src/icons/index.ts` 一致性 | | `api-help-coverage.test.ts` | 所有 Express 路由都已登记进 `/api/help` | | `ci-runner-paths.test.ts` | 后端 / `deploy.sh` / `ci-runner.py` 三方的路径优先级一致(且后两者复用同一实现) | | `webhook-cleanup.test.ts` | 投递历史清理的判定边界(时间缺失一律保留、失败判定、按地址过滤与排除) | | `git-process-reaper.test.ts` | 孤儿 `git-http-backend` 收割的保守判定(后代链、命令行、仓库根三重校验) | | `git-backend-env.test.ts` | **`CONTENT_LENGTH` 构造规则**(chunked 缺该头时绝不能设成 `'0'`)+ 其余 CGI 变量 | | `git-http-push.test.ts` | **真起服务 + 真跑 `git push`**:chunked(大 pack)推送、pack 完整性与 `fsck` | | `webhook-api.test.ts` | **真起服务进程 + 真发 HTTP**:统一管理聚合、残留地址识别、清理模式与确认守卫、`scope="all"` 覆盖全部仓库 | > 测试由 `npm test` **自动发现** `dist/tests/*.test.js` —— 新增套件无需改脚本, > 避免手工清单漏跑而静默失去保护(`api-help-coverage` 就曾被漏掉)。 > > 测试**不能继承调用方的 git 上下文**(CI 的构建目录本身是裸仓库,会导出 `GIT_DIR`), > 统一通过 `server/tests/helpers.ts` 的 `gitEnv()` 隔离。验证时可用 > `GIT_DIR=<裸仓库> npm test` 复现 CI 条件。 ## 作者声明 **作者**: H076lik 本项目由 H076lik 独立构思、设计并主导开发。所有功能均根据实际局域网 DevOps 需求设计,技术栈(Vue 3 + Express + btrfs/XFS 快照后端 + Python CI Runner)由作者自主决定。 开发过程中使用了 AI 智能体(如 Crush、Claude Code 等)作为代码生成与调试的辅助工具。AI 智能体仅作为开发工具使用,类似于 IDE、编译器等辅助软件,不构成共同创作。所有代码的架构决策、功能设计、逻辑审查、测试验证以及最终知识产权均归属于 H076lik。 --- ## 赞助名单 > 如果您觉得本项目对您有帮助,欢迎赞助支持开发。 > 联系方式与赞助方式待补充... | 赞助者 | 金额 / 方式 | 日期 | 留言 | |--------|------------|------|------| | 待填写 | — | — | — | --- ## 许可证 本项目采用 **GNU Lesser General Public License v3.0 (LGPL-3.0)** 开源许可。 - **核心源码**(`client/src/`、`server/`、配置文件及部署脚本)均已在文件头部添加 LGPL-3.0 标准声明 - 允许商用、修改与再分发,但修改后的库文件需以相同许可证开源 - larger work(调用本平台的应用程序)可独立使用不同许可证,无需强制开源 - 完整许可证文本见仓库根目录 [`LICENSE`](./LICENSE) 文件 **法律说明**:本项目为独立实现的 Git 仓库与 CI/CD 管理平台。功能接口与 DevOps 流程参考了开源社区(包括 GitHub、GitLab)的成熟实践,但全部代码由 H076lik 独立编写。 Copyright (C) 2025-2026 H076lik ## CI/CD 完整指南 Git Panel 内置完整的持续集成/持续部署流水线,支持自动构建、部署和外部通知。 ### CI 流水线(自动构建) 推送代码后自动触发: 1. 检出代码到 `deploy/{repo}` 2. 执行配置的构建步骤(如 `npm run build`、`cargo build`、`go test`) 3. 支持自动检测项目类型(Rust/Go/TypeScript/Python/C/C++/Java/Lua) 4. 自动识别 `.github/workflows/*.yml` 和 `.gitlab-ci.yml` 5. **CI 配置工作流化**:手动配置的构建步骤保存为 `.github/workflows/git-panel-ci.yml` 并自动 `git commit`,配置与代码一起版本控制 6. **自动发布起始版本号**:Dev Release 支持设置起始版本号(如 `2.0.0`),自动递增 `v2.0.1` → `v2.0.2` ### CD 持续部署 构建成功后自动执行部署步骤: - 在 CI 配置中勾选「构建成功后自动部署」 - 添加部署命令(如 `cp target/release/app /opt/bin/`) - 支持手动触发 `POST /api/repos/{name}/deploy` ### Webhook 通知 构建/部署完成后向局域网内其他设备/智能体发送 HTTP POST 通知: ```bash # 配置 Webhook(前端 CI/CD → 配置 Webhook) # 或使用 API POST /api/repos/{name}/webhook { "enabled": true, "url": "http://192.168.3.xxx:8080/webhook", "events": ["build.failed", "build.success", "deploy.failed", "deploy.success"] } ``` 推送内容示例: ```json { "event": "build.failed", "repo": "YouLiLong", "branch": "master", "commit": "c993fe94...", "commitMsg": "refactor(dap): ...", "runId": "1778663640", "status": "failed", "steps": [{"name": "Build release", "status": "failed"}], "timestamp": "2026-05-13T17:34:00", "server": "git-panel" } ``` ### 构建摘要 API(外部智能体查询) ```bash GET /api/repos/{name}/build-summary ``` 返回示例: ```json { "repo": "YouLiLong", "ci": { "status": "success", "runId": "1778665915", "branch": "master", "commit": "13aa0970...", "duration": 8, "steps": [{"name": "Build Client", "status": "success"}], "deployStatus": "success" }, "deploy": { "status": "success", "runId": "1778665915" }, "lastUpdated": "2026-05-13T17:52:03Z" } ``` ### CI 日志折叠与 ANSI 颜色 - 构建日志按步骤自动折叠(▶/▼ 切换) - ANSI 颜色转义码自动转换为 HTML 颜色(红/绿/黄等) - 实时轮询更新(3秒间隔) ### Python 项目 UV 支持 检测到 `uv.lock` 或 `pyproject.toml` 中包含 `tool.uv` 时自动使用 `uv sync`: ```json {"steps": [ {"name": "UV Sync", "command": "uv sync || uv pip install -e . || true"}, {"name": "Test", "command": "uv run pytest || true"} ]} ```