文章目录
- [Forgejo 简介 · Docker 部署 · 使用说明](#Forgejo 简介 · Docker 部署 · 使用说明)
-
- [一、Forgejo 是什么](#一、Forgejo 是什么)
- 二、部署步骤
-
- [1. 前置确认](#1. 前置确认)
- [2. 准备目录](#2. 准备目录)
- [3. 写入 `docker-compose.yml`](#3. 写入
docker-compose.yml) - [4. 启动](#4. 启动)
- [5. 放行防火墙端口](#5. 放行防火墙端口)
- [6. 完成安装向导](#6. 完成安装向导)
- [7. 部署 Actions Runner(可选,要 CI 才做)](#7. 部署 Actions Runner(可选,要 CI 才做))
- 三、使用说明
-
- [3.1 组织结构](#3.1 组织结构)
- [3.2 五个对象各管什么](#3.2 五个对象各管什么)
- [3.3 日常研发流程](#3.3 日常研发流程)
- [3.4 议题 Issue:需求、设计、bug 的统一载体](#3.4 议题 Issue:需求、设计、bug 的统一载体)
- [3.5 里程碑 Milestone:什么时候做完](#3.5 里程碑 Milestone:什么时候做完)
- [3.6 看板 Projects:现在卡在哪一环](#3.6 看板 Projects:现在卡在哪一环)
- [3.7 百科 Wiki:设计文档与知识库](#3.7 百科 Wiki:设计文档与知识库)
- [3.8 Actions 最小示例](#3.8 Actions 最小示例)
- [3.9 备份与恢复](#3.9 备份与恢复)
- [3.10 常见问题排查](#3.10 常见问题排查)
- [附录 A:目录结构速查](#附录 A:目录结构速查)
- [附录 B:内核升级(仅 Actions 构建容器起不来时考虑)](#附录 B:内核升级(仅 Actions 构建容器起不来时考虑))
- [附录 C:有用命令](#附录 C:有用命令)
- 参考链接
- 欢迎使用Markdown编辑器
Forgejo 简介 · Docker 部署 · 使用说明
宿主机:CentOS 7.6(Docker 环境已就绪 )· 数据库:SQLite
一、Forgejo 是什么
一句话:Forgejo 是一个用 Go 写的单二进制自托管代码协作平台,可以理解为「轻量版 GitLab」------代码托管 + 议题 + 看板 + CI/CD + 包管理,一个进程全搞定。
血缘
Gogs (2014) ──fork──> Gitea (2016) ──fork──> Forgejo (2022.11)
Gitea 的商标与控制权转给商业公司 Gitea Ltd 后,部分核心贡献者分叉出 Forgejo,交由德国非营利组织 Codeberg e.V. 维护。知名公共实例 codeberg.org 就跑在 Forgejo 上;Fedora 项目也已从 Pagure 迁移到 Forgejo。
能力清单
| 模块 | 说明 |
|---|---|
| 代码托管 | Git over HTTP(S)/SSH、分支保护、合并请求与代码评审、Git LFS、Blame、在线编辑 |
| 协作 | 议题(含依赖关系)、标签、里程碑、多负责人、看板(项目)、百科、工时跟踪 |
| CI/CD | Forgejo Actions,YAML 语法兼容 GitHub Actions,需独立部署 Runner |
| 制品 | 内置包仓库:npm / Docker / Maven / PyPI / NuGet / Composer / RPM |
| 认证 | 本地账号、LDAP、OAuth2、OIDC、全实例强制 2FA |
| 集成 | Webhook、REST API、仓库级 access token、内容举报与审核后台 |
资源占用
| 规模 | CPU | 内存 | 数据库 |
|---|---|---|---|
| 个人 / ≤5 人 | 1 核 | 512 MB | SQLite 足够 |
| 5--20 人 | 2 核 | 1 GB | SQLite 可用,注意写并发 |
| 20 人以上 | 2--4 核 | 2 GB+ | 建议迁 PostgreSQL |
| + Actions Runner | 按需 | 每个并发任务约 1 GB | Runner 可放独立机器 |
| 对比:GitLab CE 单节点建议 8 vCPU / 16 GB。 |
关于 SQLite :它是单写者模型,多人同时提交议题/推送时会有写锁排队,小团队感知不到。后期要换 PostgreSQL 不支持原地切换 ,需新建实例后用
dump+ 导入迁移,所以别等数据量很大了才想起来换。
版本策略
- 每 3 个月一个 stable 版本
- 每年一个 LTS 版本,支持一年
- 求稳环境建议锁 LTS(当前 LTS = v15.0.6)
二、部署步骤
1. 前置确认
Docker 已装好,只需确认以下几项:
bash
docker version # Server 端能连上
docker-compose version # 本文统一使用 docker-compose
df -h /var/lib/docker # 预留 ≥ 20G
getenforce # 记下结果,Enforcing 时后面挂载要加 :Z
docker-compose可能是 v1(Python 独立版)或 v2(Go 独立二进制),本文命令两者都通用。compose 文件里刻意没写version:和name:顶层字段,就是为了兼容 v1。项目名默认取目录名/opt/forgejo→forgejo,符合预期。
2. 准备目录
bash
mkdir -p /opt/forgejo && cd /opt/forgejo
mkdir -p forgejo-data runner-data backup
chown -R 1000:1000 forgejo-data runner-data # 不能省,原因见下
| 目录 | 用途 |
|---|---|
forgejo-data |
挂载到容器 /data:仓库、SQLite 库、附件、配置、日志 |
runner-data |
Runner 缓存(不装 CI 可留空) |
backup |
存放 dump 备份包 |
⚠️
chown这步必须做。mkdir建出来的目录属主是root:root权限 755,而容器里的 Forgejo 跑在git用户下(UID/GID 1000,即 compose 里的USER_UID/USER_GID),对 root 属主目录没有写权限。漏了这步,到第 6 步点「立即安装」会报:
数据库设置无效:unable to open database file: no such file or directory这条报错有误导性------SQLite 的
SQLITE_CANTOPEN把「路径不存在」「无写权限」「SELinux 拒绝」三种情况报成同一句话,此处属于第二种。已经踩坑的完整定位与修复见 3.10 常见问题排查。
3. 写入 docker-compose.yml
bash
cat > /opt/forgejo/docker-compose.yml <<'EOF'
services:
server:
image: codeberg.org/forgejo/forgejo:15 # 锁 LTS;求新改 16
container_name: forgejo
environment:
- USER_UID=1000
- USER_GID=1000
- FORGEJO__database__DB_TYPE=sqlite3
- FORGEJO__database__PATH=/data/forgejo.db
- FORGEJO__server__DOMAIN=git.example.com # 改成你的域名或 IP
- FORGEJO__server__ROOT_URL=http://git.example.com:3000/
- FORGEJO__server__SSH_DOMAIN=git.example.com
- FORGEJO__server__SSH_PORT=222 # 用户 clone 时看到的端口
- FORGEJO__server__SSH_LISTEN_PORT=22 # 容器内实际监听端口
- FORGEJO__service__DISABLE_REGISTRATION=true # 首次装完建议关掉
- FORGEJO__actions__ENABLED=true
restart: unless-stopped
volumes:
- ./forgejo-data:/data:Z # :Z 见下方说明
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "222:22"
EOF
部署前必须改的三个值
| 变量 | 说明 |
|---|---|
DOMAIN / SSH_DOMAIN |
换成实际域名或服务器 IP |
ROOT_URL |
必须与浏览器访问地址完全一致(含端口、含结尾斜杠)。写错会导致邮件链接、OAuth 回调、附件 URL 全部指向错误地址 |
image 标签 |
15 = LTS,16 = 最新 stable |
| 两个容易踩的点 |
:Z(大写)是 SELinux 私有标签。CentOS 7 默认 enforcing,不加会导致容器对挂载目录permission denied,且日志里往往看不出原因。如果getenforce返回Disabled,可以去掉。SSH_PORT和SSH_LISTEN_PORT是两回事:前者是展示给用户 的端口(clone 地址里显示的 222),后者是容器内 sshd 实际监听的端口。宿主机222:22的映射必须和它们对得上,否则页面能打开但 clone 失败。
4. 启动
bash
cd /opt/forgejo
docker-compose pull
docker-compose up -d
docker-compose ps # STATUS 应为 Up
docker-compose logs -f server
日志里看到 Listen: http://0.0.0.0:3000 即成功,Ctrl+C 退出日志跟踪。
5. 放行防火墙端口
bash
firewall-cmd --permanent --add-port=3000/tcp # Web
firewall-cmd --permanent --add-port=222/tcp # Git over SSH
firewall-cmd --reload
Docker 发布端口时会直接写 iptables,通常已经绕过 firewalld 放行了。上面这步主要是让规则显式化、便于审计。
⚠️ CentOS 7 上
systemctl restart firewalld会清掉 Docker 写的 iptables 规则导致容器断网,重启 firewalld 后请一并systemctl restart docker。
6. 完成安装向导
- 浏览器打开
http://<服务器IP>:3000 - 首次进入是安装页。数据库部分已由环境变量预填为 SQLite,重点确认:
- 服务器域名 / Forgejo 基础 URL:与实际访问地址一致
- 禁用注册:建议勾选,之后由管理员手动建号
- 展开「管理员账号设置」,直接在这里创建管理员(跳过就得用命令行补)
- 点「立即安装」,等待自动重启并登录
若报
unable to open database file: no such file or directory,先用一条命令区分是权限、SELinux 还是路径填错:
bashdocker exec forgejo sh -c 'id; ls -ldZ /data; touch /data/_t && echo WRITE_OK || echo WRITE_FAIL; rm -f /data/_t'绝大多数情况是第 2 步漏了
chown(WRITE_FAIL且ls显示属主root),在宿主机执行下面两行后回到安装页重点一次「立即安装」即可:
bashchown -R 1000:1000 /opt/forgejo/forgejo-data cd /opt/forgejo && docker-compose restart server
WRITE_OK却仍然报错,说明是安装页表单里的路径问题;三种分支的完整对照见 3.10。忘了创建管理员时,用命令行补:
bash
docker exec -u git forgejo forgejo admin user create \
--username admin --password '强密码' \
--email admin@example.com --admin
7. 部署 Actions Runner(可选,要 CI 才做)
先在 Admin 面板 → Actions → Runners → New Runner 生成注册令牌,然后:
bash
cat > /opt/forgejo/.env <<'EOF'
RUNNER_TOKEN=粘贴上一步生成的令牌
EOF
chmod 600 /opt/forgejo/.env
在 docker-compose.yml 的 services: 下追加:
yaml
runner:
image: codeberg.org/forgejo-contrib/forgejo-runner:latest
container_name: forgejo-runner
restart: unless-stopped
depends_on: [server]
environment:
- FORGEJO_RUNNER_URL=http://server:3000
- FORGEJO_RUNNER_TOKEN=${RUNNER_TOKEN}
- FORGEJO_RUNNER_LABELS=alpine:docker://alpine:3.18,node:docker://node:20-alpine
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./runner-data:/data:Z
bash
docker-compose up -d runner
docker-compose logs -f runner # 看到 Successfully registered 即成功
⚠️ 内核 3.10 的兼容问题 :CentOS 7.6 内核较老,默认的
ubuntu-latest标签基于 Debian 系镜像,构建容器可能起不来。上面刻意只用 alpine 系标签 ,先跑通再按需扩展。仍然失败见附录 B。⚠️ 挂载
docker.sock等于把宿主机 root 权限交给 Runner。有外部贡献者的公开实例不要这么部署,改用独立 Runner 主机。
三、使用说明
3.1 组织结构
组织 Organization(对应一个团队 / 产品线)
├── 团队 Team(决定权限:只读 / 写入 / 管理员)
│ └── 成员 User(人挂在团队上,不是直接挂在组织上)
└── 仓库 Repository(权限从团队继承)
├── 议题 Issue
├── 看板 Projects
├── 里程碑 Milestone
├── 发布 Releases
├── 百科 Wiki
└── 流水线 Actions
推荐做法 :按产品线建组织,成员通过团队加进组织而不是逐个仓库加协作者,权限用团队统一管。这也是为什么上手顺序必须是「组织 → 团队 → 人 → 仓库」,详见 3.3。
3.2 五个对象各管什么
Forgejo 的项目管理能力全部围绕**议题(Issue)**展开,其余四个对象都是给议题加的维度。先建立这个心智模型,后面每一节就知道该往哪儿放东西。
| 对象 | 界面标签 | 回答的问题 | 定位 | 详见 |
|---|---|---|---|---|
| 议题 Issue | 议题 | 要做什么 | 需求、设计议题、bug 的唯一载体,所有讨论和状态都挂在它身上 | 3.4 |
| 里程碑 Milestone | 里程碑 | 什么时候做完 | 给一批议题套一个截止日期,看整体完成进度 | 3.5 |
| 看板 Projects | 项目 | 现在卡在哪一环 | 用「列」表示流转阶段,拖动议题改所在列 | 3.6 |
| 百科 Wiki | 百科 | 沉淀下来的知识 | 设计文档、接口说明、运维手册等长文档 | 3.7 |
| 发布 Releases | 版本发布 | 交付了什么 | 打 tag、传制品、写发布说明 | --- |
「界面标签」列是仓库页顶部标签栏里实际显示的名字(简体中文界面),照它找按钮不会错。注意看板在界面上叫「项目」 ,是最容易混淆的一个。
关键认知 :五个对象里只有议题是「内容」,其余四个都是给内容加的维度。同一批议题可以同时挂在一个里程碑上、拖在一块看板里、被百科文档引用------这几个对象不是各管一摊、互不相干,而是叠加使用。
3.3 日常研发流程
| 步骤 | 操作 |
|---|---|
| 建组织 | 右上 + → 创建组织 → 填组织名(它会直接成为 URL 里的一段,想好再填)、选可见性 |
| 建团队加人 | 组织 → 团队 → 新建团队 → 选权限(只读/写入/管理员)、按需勾「包含所有仓库」→ 加成员 |
| 建仓库 | 右上 + → 创建仓库 → 「所有者」下拉框选组织而不是自己 → 初始化 README/.gitignore |
| 新建议题 | 仓库 → 议题 标签 → 新建 → 选议题模板 → 打类型标签、指派负责人、挂里程碑 |
| 排迭代 | 建里程碑(标题 + 截止日期)→ 回议题列表批量勾选挂进去,详见 3.5 |
| 看板流转 | 建看板 → 自定义列 → 拖议题进列,详见 3.6 |
| 开发 | 从议题页面直接 Create branch,本地 git clone ssh://git@IP:222/org/repo.git |
| 提交评审 | Push 后页面提示创建合并请求 → 指定 Reviewer → 讨论 → 合并 |
| 记工时 | 议题页面「开始工作」跑秒表,或「手动记录时间」填小时 + 分钟 |
| 写文档 | 仓库 → 百科 标签 → 新建页面,详见 3.7 |
| 发版本 | 仓库 → 版本发布 标签 → 新建 → 选 tag → 上传制品 |
为什么必须先建组织、再建仓库
右上 + 菜单里「创建组织」和「创建仓库」是并列的两项,新用户很容易顺手先建仓库、建到自己个人名下。这个顺序错了有实际代价:
- 权限模型是
组织 → 团队 → 人。Forgejo 里没有独立的「组织成员」操作,把人加进组织的唯一方式就是把人加进组织下的某个团队;而仓库权限又是从团队继承的。仓库建在个人名下时,团队权限完全用不上,只能逐个仓库加协作者 - 事后转移会改 URL 。仓库地址是
/<所有者>/<仓库名>,从个人名下转到组织下,所有者变了地址就变了(/zhangsan/api→/backend-team/api),所有人的本地 remote、CI 配置、文档里的链接都得跟着改
两个相关细节: - 创建组织时会自动生成一个
Owners团队,创建人直接就是最高权限,不需要再把自己加进去 - 团队上最值得关注的开关是「包含所有仓库」:勾上后组织下新建的仓库会自动纳入该团队,不用每建一个仓库手动授权一次
💡 管理员建议 :内部实例可以在
app.ini的[admin]段设DISABLE_REGULAR_ORG_CREATION = true(默认false),禁止普通用户自建组织,避免仓库散落在各人乱建的组织里。
3.4 议题 Issue:需求、设计、bug 的统一载体
Forgejo 没有「议题类型」这个字段 ------不像禅道/Jira 那样新建时先选「需求/任务/缺陷」。它的设计思路是:一切皆议题,用标签(Label)区分类型。好处是类型体系完全自定义,代价是团队必须自己约定好标签规范,否则很快就乱。
用作用域标签区分类型
标签支持 作用域/值 写法,同一作用域下的标签互斥且可排序,这是官方专门为「类型」这类场景做的能力:
| 作用域 | 建议取值 | 用途 |
|---|---|---|
类型/ |
类型/需求、类型/设计、类型/缺陷、类型/任务 |
区分工作性质 |
优先级/ |
优先级/高、优先级/中、优先级/低 |
列表排序依据 |
模块/ |
模块/前端、模块/后端、模块/App |
跨仓库迭代时按模块筛 |
状态/ |
状态/待确认、状态/待验证 |
补充看板列覆盖不到的细分状态 |
| 建标签不用手工一个个来:仓库 → 设置 → 标签 → 「初始化标签」一键导入预设模板集,再按需改名。组织级也有一份标签集,供组织下所有仓库共用。 |
用议题模板规范提交内容
在仓库里放 .forgejo/ISSUE_TEMPLATE/ 目录(也兼容 .gitea/,.md 或 .yml 均可),新建议题时会先弹出模板选择。给需求和缺陷各配一个模板,能省掉大量「这 bug 怎么复现」的往返追问:
.forgejo/ISSUE_TEMPLATE/
├── 需求.md # 背景 / 目标 / 验收标准 / 涉及模块
└── 缺陷.md # 环境 / 复现步骤 / 期望结果 / 实际结果 / 日志或截图
议题右侧边栏能挂什么
这一列边栏就是议题的管理面板,所有管理维度都在这儿收口:
| 区块 | 作用 |
|---|---|
| 指派 Assignees | 负责人,支持多人 |
| 里程碑 Milestone | 属于哪个迭代/版本,见 3.5 |
| 项目 Projects | 在哪块看板的哪一列,见 3.6 |
| 依赖 Dependencies | Blocked by(被谁阻塞)/ Blocking(阻塞了谁)。需求拆解后标前后置关系,一眼看出卡在谁那里 |
| 时间跟踪 | 「开始工作」跑秒表,或「手动记录时间」填小时 + 分钟 |
三类工作各自怎么管
需求 :一个需求 = 一个议题,正文写清背景与验收标准。需求大时拆子任务,用依赖关系 串起来(父需求 Blocking 若干子任务)。长篇需求文档放百科,议题里只留结论和链接。
设计 :讨论过程用议题------评审意见、决策记录都留在评论区,有完整时间线;设计文档 放百科。议题正文用一行 设计文档:<百科链接> 关联,讨论和成果物各归其位又能互相跳转。
bug :必须走议题模板,强制填复现步骤和环境。配合 Bug 分诊 看板模板(见 3.6)做分诊流转。修复后在提交信息里写 Fixes #123,合并时议题自动关闭------这是 bug 闭环的关键,别让测试手工去关。
3.5 里程碑 Milestone:什么时候做完
设计初衷 :里程碑是给议题加的时间维度 。议题本身只回答「要不要做」,挂上里程碑才回答「什么时候必须做完」。一个迭代、一个版本、一个交付节点,各对应一个里程碑。
怎么用:
- 建 :仓库 → 顶部 议题 标签 → 议题列表右上「里程碑 」→「新建里程碑」→ 填标题 + 截止日期 + 描述
- 入口藏在议题标签页里,左侧菜单栏没有独立入口,很容易找不到
- 直达地址更快:
http://<服务器>:3000/<组织>/<仓库>/milestones
- 挂议题 :
- 单个 → 打开议题,右侧边栏「里程碑」下拉选
- 批量 → 议题列表勾选多个 → 顶部操作条 → 里程碑 → 选目标
- 看进度 :里程碑详情页有完成进度条(已关闭 / 总数)和逾期标红,可直接当迭代评审的入口
与版本发布的分工 :里程碑是计划视角 (截止日 + 进度),版本发布是产物视角 (tag + 制品 + 发布说明)。发版时两个都要有,别只建里程碑。
一个限制 :里程碑只有仓库级。迭代横跨前端/后端/App 多个仓库时,只能各仓库建同名里程碑,进度不汇总。要跨仓库的统一迭代视图,用组织级看板(3.6)。
3.6 看板 Projects:现在卡在哪一环
设计初衷 :看板是给议题加的状态流转维度 。里程碑告诉你「这批事到期了没」,看板告诉你「这批事现在各自卡在哪一环」。
⚠️ 最大的认知坑 :这里的「项目」不是 「一个研发项目/一个产品」,而是一块看板 。一个仓库可以建很多个「项目」,比如 Sprint 24、v2.0 发布、Bug 分诊,每个都是一块独立的板。名字起得很误导人,别按传统 PM 软件的「项目」去理解。
两种内置模板(建看板时可选,模板只是初始列名,建完可随意增删改):
| 模板 | 默认列 | 适用 |
|---|---|---|
| 基础看板 | 待办 / 进行中 / 已完成 | 迭代流转 |
| Bug 分诊 | 待分析 / 高优先级 / 低优先级 / 已关闭 | 缺陷分诊 |
对应的服务端配置项是 PROJECT_BOARD_BASIC_KANBAN_TYPE 和 PROJECT_BOARD_BUG_TRIAGE_TYPE,可在 app.ini 里改成团队自己的术语。 |
||
| 怎么用: |
- 建 :仓库 → 顶部 议题 标签 → 列表右上「项目」→ 新建 → 填名字、选模板
- 拖 :从议题列表拖进列,或在看板里列间拖动
⚠️ 拖动只改「在哪一列」,不改议题的开/关状态 。Forgejo 看板没有自动化规则,把议题拖到最后一列不会 自动关闭它(这点和 GitLab 的 Done 列行为不同)。关闭议题在议题页面操作,或在提交信息里写Fixes #编号(见 3.4)。
三个要点:
- 列 = 流转阶段,不是分组维度。一个议题在同一看板里只能待在一列,拖动即换列
- 合并请求也能进看板,不只是议题。把待评审的合并请求拖进「评审中」列,代码评审进度也能可视化
- 组织级看板能跨仓库:组织首页 → 「项目」标签,多个仓库的议题拖进同一块板,等于一个跨仓库迭代视图------这正是里程碑做不到而看板能做到的事
3.7 百科 Wiki:设计文档与知识库
设计初衷 :议题的评论区是过程 ,百科是结论 。设计文档、接口说明、环境搭建手册、运维 SOP 这类需要长期维护、反复查阅的长文档放百科,别埋在某个议题的第十八条回复里。
怎么用:
- 入口 :仓库 → 百科 标签(默认可能未启用,需先在仓库设置里打开百科单元)
- 导航 :建
_Sidebar.md自定义侧边栏目录、_Footer.md自定义页脚,页面多了靠这两个文件组织 - 历史 :每个页面都有版本历史和 diff,改错了能回滚
底层是独立的 git 仓库,这是百科最大的优势------可以本地批量写、纳入备份、整体迁移:
bash
git clone ssh://git@<服务器>:222/<组织>/<仓库>.wiki.git
# 用 VS Code 写,图片直接放进目录,Markdown 里用相对路径引用
git add . && git commit -m "docs: 补充部署手册" && git push
两条硬限制:
- 只有仓库级,没有组织级百科 。团队统一知识库的通行做法:建一个专门的
docs仓库,把它的百科当团队知识库 - 网页编辑器不支持拖拽上传图片(附件功能只覆盖议题和合并请求),图片必须走上面的 git 方式提交
3.8 Actions 最小示例
在仓库根目录建 .forgejo/workflows/ci.yml:
yaml
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: alpine # 必须对应 Runner 注册的 label
steps:
- uses: https://github.com/actions/checkout@v4
- name: Show env
run: |
uname -a
echo "branch=${{ forgejo.ref }}"
- name: Run tests
run: echo "replace with your real test command"
与 GitHub Actions 的三点差异
| 差异 | 说明 |
|---|---|
| 目录 | .forgejo/workflows/(不是 .github/workflows/) |
| 上下文变量 | ${``{ forgejo.* }} 替代 ${``{ github.* }}(有兼容映射但不完整) |
| 第三方 Action | GitHub Marketplace 的用不了 。actions/checkout、setup-node 等需社区移植版;任何调 GitHub API 的 Action 直接失效 |
3.9 备份与恢复
备份(建议每周至少一次,升级前必做)
bash
# 1. 先确认容器内配置文件路径(不同版本可能是 /data/gitea/conf 或 /data/forgejo/conf)
docker exec forgejo ls /data/gitea/conf/ 2>/dev/null || docker exec forgejo ls /data/forgejo/conf/
# 2. 执行 dump:仓库 + SQLite 库 + 附件 + 配置,打成一个 zip
docker exec -u git forgejo forgejo dump \
-c /data/gitea/conf/app.ini \
-f /data/backup/forgejo-$(date +%Y%m%d).zip
# 3. 拷出到宿主机
docker cp forgejo:/data/backup/. /opt/forgejo/backup/
定时任务(每天凌晨 2 点,保留 14 天):
bash
crontab -e
cron
0 2 * * * docker exec -u git forgejo forgejo dump -c /data/gitea/conf/app.ini -f /data/backup/forgejo-$(date +\%Y\%m\%d).zip && docker cp forgejo:/data/backup/. /opt/forgejo/backup/ && find /opt/forgejo/backup -name "forgejo-*.zip" -mtime +14 -delete
⚠️ 只拷 git 仓库目录是不够的 。Issue、PR、用户、密钥、看板全在 SQLite 库里,必须用
dump。恢复 :解压 dump 包 → 把仓库目录、SQLite 库、附件、
app.ini放回新的/data→ 启动。建议每季度在测试机上演练一次恢复,没验证过的备份等于没有备份。
3.10 常见问题排查
| 现象 | 原因 | 处理 |
|---|---|---|
安装页点「立即安装」报 unable to open database file: no such file or directory |
宿主机 forgejo-data 属主是 root:root,容器内 git 用户(UID 1000)写不进去。这是该报错最常见的原因 |
chown -R 1000:1000 /opt/forgejo/forgejo-data → docker-compose restart server → 回安装页重点「立即安装」(第 2 步已包含此操作,照做不会遇到) |
同上,但 chown 后依旧报错 |
SELinux 拒绝写入,目录标签不是 container_file_t |
ls -ldZ /opt/forgejo/forgejo-data 查看标签;执行 chcon -Rt container_file_t /opt/forgejo/forgejo-data,并确认 compose 挂载行带 :Z |
同上,但容器内 touch /data/_t 返回 WRITE_OK |
安装页表单里的「数据库文件路径」被改成了不存在的子目录(Forgejo 不会自动创建父目录) | 把路径改回 /data/forgejo.db |
容器起不来,日志 permission denied |
SELinux 拦截挂载目录 | 挂载加 :Z;或 setenforce 0 临时验证是不是它 |
| Web 能打开但 clone 失败 | SSH_PORT 与宿主机端口映射不一致 |
核对 222:22 映射与 SSH_PORT=222 |
clone 地址显示 localhost:3000 |
ROOT_URL / DOMAIN 没改 |
改 compose 环境变量后 docker-compose up -d |
| 邮件链接、头像、附件 URL 全错 | 同上,ROOT_URL 与访问地址不一致 |
--- |
| 环境变量改了不生效 | FORGEJO__ 前缀未被识别 |
换成 GITEA__ 前缀(兼容写法);或进容器直接改 app.ini |
| Actions 一直排队 | Runner 未注册或 label 不匹配 | docker-compose logs runner;核对 runs-on 与 FORGEJO_RUNNER_LABELS |
| 构建容器启动失败 | 宿主机内核 3.10 太老 | 换 alpine 系标签;仍失败见附录 B |
| 磁盘占用暴涨 | 容器日志未做轮转 | 在 /etc/docker/daemon.json 配 log-opts 后重启 docker |
| 重启 firewalld 后容器断网 | iptables 规则被清空 | systemctl restart docker |
SQLite 报 database is locked |
写并发过高 | 减少并发操作;长期方案是迁 PostgreSQL |
附录 A:目录结构速查
/opt/forgejo/
├── .env # Runner Token(chmod 600,不用 CI 可不建)
├── docker-compose.yml
├── forgejo-data/ # → 容器 /data:仓库、forgejo.db、附件、app.ini、日志
├── runner-data/ # → Runner 缓存
└── backup/ # dump 备份包
只要备份 forgejo-data + .env + docker-compose.yml,就能完整还原整个系统。
附录 B:内核升级(仅 Actions 构建容器起不来时考虑)
bash
# 装 ELRepo 源
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
yum install -y https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
# 长期支持内核 5.4(比 kernel-ml 稳)
yum --enablerepo=elrepo-kernel install -y kernel-lt
# 设为默认启动项并重启
grub2-setdefault 0
reboot
uname -r # 期望 5.4.x
内核升级属高风险操作,必须先在测试机验证、确认停机窗口、准备回滚方案。不用 Actions 的话完全没必要做。
附录 C:有用命令
bash
docker-compose ps # 服务状态
docker-compose logs -f server # 实时日志
docker exec -u git forgejo forgejo --version # 版本
docker exec -it forgejo sh # 进容器
docker exec -u git forgejo forgejo admin user list # 用户列表
docker exec -u git forgejo forgejo doctor check --all # 自检
参考链接
- 官网与文档:https://forgejo.org/docs/
- 源码仓库:https://codeberg.org/forgejo/forgejo
- Release Notes:https://codeberg.org/forgejo/forgejo/releases
- 配置项速查:https://forgejo.org/docs/latest/admin/config-cheat-sheet/
- Actions 文档:https://forgejo.org/docs/latest/user/actions/
欢迎使用Markdown编辑器
你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
新的改变
我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:
- 全新的界面设计 ,将会带来全新的写作体验;
- 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
- 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
- 全新的 KaTeX数学公式 语法;
- 增加了支持甘特图的mermaid语法[1](#甘特图的mermaid语法1) 功能;
- 增加了 多屏幕编辑 Markdown文章功能;
- 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
- 增加了 检查列表 功能。
功能快捷键
撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G
合理的创建标题,有助于目录的生成
直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。
如何改变文本的样式
强调文本 强调文本
加粗文本 加粗文本
标记文本
删除文本
引用文本
H2O is是液体。
210 运算结果是 1024.
插入链接与图片
链接: link.
图片:
带尺寸的图片:
居中的图片:
居中并且带尺寸的图片:
当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。
如何插入一段漂亮的代码片
去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.
javascript
// An highlighted block
var foo = 'bar';
生成一个适合你的列表
- 项目
- 项目
- 项目
- 项目
- 项目1
- 项目2
- 项目3
- 计划任务
- 完成任务
创建一个表格
一个简单的表格是这么创建的:
| 项目 | Value |
|---|---|
| 电脑 | $1600 |
| 手机 | $12 |
| 导管 | $1 |
设定内容居中、居左、居右
使用:---------:居中
使用:----------居左
使用----------:居右
| 第一列 | 第二列 | 第三列 |
|---|---|---|
| 第一列文本居中 | 第二列文本居右 | 第三列文本居左 |
SmartyPants
SmartyPants 是一个文本转换工具,主要功能是将普通的 ASCII 标点符号自动转换为更美观的印刷体标点符号。例如:
| 原始符号 | 转换后 | 说明 |
|---|---|---|
"引号" |
"引号" | 直引号变弯引号 |
'单引号' |
'单引号' | 直单引号变弯单引号 |
-- |
-- | 两个连字符变短破折号 |
--- |
--- | 三个连字符变长破折号 |
... |
... | 三个点变省略号 |
创建一个自定义列表
:
Text-to- conversion tool
: John
: Luke
如何创建一个注脚
一个具有注脚的文本。[2](#2)
注释也是必不可少的
Markdown将文本转换为 。
KaTeX数学公式
您可以使用渲染LaTeX数学表达式 KaTeX:
Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n−1)!∀n∈N 是通过欧拉积分
Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=∫0∞tz−1e−tdt.
你可以找到更多关于的信息 LaTeX 数学表达式here.
新的甘特图功能,丰富你的文章
#mermaid-svg-PbNPvntHSdx4R7fj{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PbNPvntHSdx4R7fj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PbNPvntHSdx4R7fj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PbNPvntHSdx4R7fj .error-icon{fill:#552222;}#mermaid-svg-PbNPvntHSdx4R7fj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PbNPvntHSdx4R7fj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PbNPvntHSdx4R7fj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PbNPvntHSdx4R7fj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PbNPvntHSdx4R7fj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PbNPvntHSdx4R7fj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PbNPvntHSdx4R7fj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PbNPvntHSdx4R7fj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PbNPvntHSdx4R7fj .marker.cross{stroke:#333333;}#mermaid-svg-PbNPvntHSdx4R7fj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PbNPvntHSdx4R7fj p{margin:0;}#mermaid-svg-PbNPvntHSdx4R7fj .mermaid-main-font{font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-PbNPvntHSdx4R7fj .exclude-range{fill:#eeeeee;}#mermaid-svg-PbNPvntHSdx4R7fj .section{stroke:none;opacity:0.2;}#mermaid-svg-PbNPvntHSdx4R7fj .section0{fill:rgba(102, 102, 255, 0.49);}#mermaid-svg-PbNPvntHSdx4R7fj .section2{fill:#fff400;}#mermaid-svg-PbNPvntHSdx4R7fj .section1,#mermaid-svg-PbNPvntHSdx4R7fj .section3{fill:white;opacity:0.2;}#mermaid-svg-PbNPvntHSdx4R7fj .sectionTitle0{fill:#333;}#mermaid-svg-PbNPvntHSdx4R7fj .sectionTitle1{fill:#333;}#mermaid-svg-PbNPvntHSdx4R7fj .sectionTitle2{fill:#333;}#mermaid-svg-PbNPvntHSdx4R7fj .sectionTitle3{fill:#333;}#mermaid-svg-PbNPvntHSdx4R7fj .sectionTitle{text-anchor:start;font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-PbNPvntHSdx4R7fj .grid .tick{stroke:lightgrey;opacity:0.8;shape-rendering:crispEdges;}#mermaid-svg-PbNPvntHSdx4R7fj .grid .tick text{font-family:"trebuchet ms",verdana,arial,sans-serif;fill:#333;}#mermaid-svg-PbNPvntHSdx4R7fj .grid path{stroke-width:0;}#mermaid-svg-PbNPvntHSdx4R7fj .today{fill:none;stroke:red;stroke-width:2px;}#mermaid-svg-PbNPvntHSdx4R7fj .task{stroke-width:2;}#mermaid-svg-PbNPvntHSdx4R7fj .taskText{text-anchor:middle;font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-PbNPvntHSdx4R7fj .taskTextOutsideRight{fill:black;text-anchor:start;font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-PbNPvntHSdx4R7fj .taskTextOutsideLeft{fill:black;text-anchor:end;}#mermaid-svg-PbNPvntHSdx4R7fj .task.clickable{cursor:pointer;}#mermaid-svg-PbNPvntHSdx4R7fj .taskText.clickable{cursor:pointer;fill:#003163!important;font-weight:bold;}#mermaid-svg-PbNPvntHSdx4R7fj .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163!important;font-weight:bold;}#mermaid-svg-PbNPvntHSdx4R7fj .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163!important;font-weight:bold;}#mermaid-svg-PbNPvntHSdx4R7fj .taskText0,#mermaid-svg-PbNPvntHSdx4R7fj .taskText1,#mermaid-svg-PbNPvntHSdx4R7fj .taskText2,#mermaid-svg-PbNPvntHSdx4R7fj .taskText3{fill:white;}#mermaid-svg-PbNPvntHSdx4R7fj .task0,#mermaid-svg-PbNPvntHSdx4R7fj .task1,#mermaid-svg-PbNPvntHSdx4R7fj .task2,#mermaid-svg-PbNPvntHSdx4R7fj .task3{fill:#8a90dd;stroke:#534fbc;}#mermaid-svg-PbNPvntHSdx4R7fj .taskTextOutside0,#mermaid-svg-PbNPvntHSdx4R7fj .taskTextOutside2{fill:black;}#mermaid-svg-PbNPvntHSdx4R7fj .taskTextOutside1,#mermaid-svg-PbNPvntHSdx4R7fj .taskTextOutside3{fill:black;}#mermaid-svg-PbNPvntHSdx4R7fj .active0,#mermaid-svg-PbNPvntHSdx4R7fj .active1,#mermaid-svg-PbNPvntHSdx4R7fj .active2,#mermaid-svg-PbNPvntHSdx4R7fj .active3{fill:#bfc7ff;stroke:#534fbc;}#mermaid-svg-PbNPvntHSdx4R7fj .activeText0,#mermaid-svg-PbNPvntHSdx4R7fj .activeText1,#mermaid-svg-PbNPvntHSdx4R7fj .activeText2,#mermaid-svg-PbNPvntHSdx4R7fj .activeText3{fill:black!important;}#mermaid-svg-PbNPvntHSdx4R7fj .done0,#mermaid-svg-PbNPvntHSdx4R7fj .done1,#mermaid-svg-PbNPvntHSdx4R7fj .done2,#mermaid-svg-PbNPvntHSdx4R7fj .done3{stroke:grey;fill:lightgrey;stroke-width:2;}#mermaid-svg-PbNPvntHSdx4R7fj .doneText0,#mermaid-svg-PbNPvntHSdx4R7fj .doneText1,#mermaid-svg-PbNPvntHSdx4R7fj .doneText2,#mermaid-svg-PbNPvntHSdx4R7fj .doneText3{fill:black!important;}#mermaid-svg-PbNPvntHSdx4R7fj .doneText0.taskTextOutsideLeft,#mermaid-svg-PbNPvntHSdx4R7fj .doneText0.taskTextOutsideRight,#mermaid-svg-PbNPvntHSdx4R7fj .doneText1.taskTextOutsideLeft,#mermaid-svg-PbNPvntHSdx4R7fj .doneText1.taskTextOutsideRight,#mermaid-svg-PbNPvntHSdx4R7fj .doneText2.taskTextOutsideLeft,#mermaid-svg-PbNPvntHSdx4R7fj .doneText2.taskTextOutsideRight,#mermaid-svg-PbNPvntHSdx4R7fj .doneText3.taskTextOutsideLeft,#mermaid-svg-PbNPvntHSdx4R7fj .doneText3.taskTextOutsideRight{fill:black!important;}#mermaid-svg-PbNPvntHSdx4R7fj .crit0,#mermaid-svg-PbNPvntHSdx4R7fj .crit1,#mermaid-svg-PbNPvntHSdx4R7fj .crit2,#mermaid-svg-PbNPvntHSdx4R7fj .crit3{stroke:#ff8888;fill:red;stroke-width:2;}#mermaid-svg-PbNPvntHSdx4R7fj .activeCrit0,#mermaid-svg-PbNPvntHSdx4R7fj .activeCrit1,#mermaid-svg-PbNPvntHSdx4R7fj .activeCrit2,#mermaid-svg-PbNPvntHSdx4R7fj .activeCrit3{stroke:#ff8888;fill:#bfc7ff;stroke-width:2;}#mermaid-svg-PbNPvntHSdx4R7fj .doneCrit0,#mermaid-svg-PbNPvntHSdx4R7fj .doneCrit1,#mermaid-svg-PbNPvntHSdx4R7fj .doneCrit2,#mermaid-svg-PbNPvntHSdx4R7fj .doneCrit3{stroke:#ff8888;fill:lightgrey;stroke-width:2;cursor:pointer;shape-rendering:crispEdges;}#mermaid-svg-PbNPvntHSdx4R7fj .milestone{transform:rotate(45deg) scale(0.8,0.8);}#mermaid-svg-PbNPvntHSdx4R7fj .milestoneText{font-style:italic;}#mermaid-svg-PbNPvntHSdx4R7fj .doneCritText0,#mermaid-svg-PbNPvntHSdx4R7fj .doneCritText1,#mermaid-svg-PbNPvntHSdx4R7fj .doneCritText2,#mermaid-svg-PbNPvntHSdx4R7fj .doneCritText3{fill:black!important;}#mermaid-svg-PbNPvntHSdx4R7fj .doneCritText0.taskTextOutsideLeft,#mermaid-svg-PbNPvntHSdx4R7fj .doneCritText0.taskTextOutsideRight,#mermaid-svg-PbNPvntHSdx4R7fj .doneCritText1.taskTextOutsideLeft,#mermaid-svg-PbNPvntHSdx4R7fj .doneCritText1.taskTextOutsideRight,#mermaid-svg-PbNPvntHSdx4R7fj .doneCritText2.taskTextOutsideLeft,#mermaid-svg-PbNPvntHSdx4R7fj .doneCritText2.taskTextOutsideRight,#mermaid-svg-PbNPvntHSdx4R7fj .doneCritText3.taskTextOutsideLeft,#mermaid-svg-PbNPvntHSdx4R7fj .doneCritText3.taskTextOutsideRight{fill:black!important;}#mermaid-svg-PbNPvntHSdx4R7fj .vert{stroke:navy;}#mermaid-svg-PbNPvntHSdx4R7fj .vertText{font-size:15px;text-anchor:middle;fill:navy!important;}#mermaid-svg-PbNPvntHSdx4R7fj .activeCritText0,#mermaid-svg-PbNPvntHSdx4R7fj .activeCritText1,#mermaid-svg-PbNPvntHSdx4R7fj .activeCritText2,#mermaid-svg-PbNPvntHSdx4R7fj .activeCritText3{fill:black!important;}#mermaid-svg-PbNPvntHSdx4R7fj .titleText{text-anchor:middle;font-size:18px;fill:#333;font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-PbNPvntHSdx4R7fj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 2014-01-07 2014-01-09 2014-01-11 2014-01-13 2014-01-15 2014-01-17 2014-01-19 2014-01-21 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid
- 关于 甘特图 语法,参考 这儿,
UML图表
可以使用UML图表进行渲染,例如下面产生的一个序列图:
王五 李四 张三 王五 李四 张三 #mermaid-svg-Tm0hqfvyiMV9KLm7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Tm0hqfvyiMV9KLm7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .error-icon{fill:#552222;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .marker.cross{stroke:#333333;}#mermaid-svg-Tm0hqfvyiMV9KLm7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Tm0hqfvyiMV9KLm7 p{margin:0;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Tm0hqfvyiMV9KLm7 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Tm0hqfvyiMV9KLm7 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-Tm0hqfvyiMV9KLm7 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .sequenceNumber{fill:white;}#mermaid-svg-Tm0hqfvyiMV9KLm7 #sequencenumber{fill:#333;}#mermaid-svg-Tm0hqfvyiMV9KLm7 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .messageText{fill:#333;stroke:none;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .labelText,#mermaid-svg-Tm0hqfvyiMV9KLm7 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .loopText,#mermaid-svg-Tm0hqfvyiMV9KLm7 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Tm0hqfvyiMV9KLm7 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .noteText,#mermaid-svg-Tm0hqfvyiMV9KLm7 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .actorPopupMenu{position:absolute;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-Tm0hqfvyiMV9KLm7 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Tm0hqfvyiMV9KLm7 .actor-man circle,#mermaid-svg-Tm0hqfvyiMV9KLm7 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-Tm0hqfvyiMV9KLm7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 李四想了很长时间, 文字太长了 不适合放在一行. 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 打量着王五... 很好... 王五, 你怎么样?
- 关于 UML图表 语法,参考 这儿,
流程图
#mermaid-svg-PF4HunrZuVR7QoQ6{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PF4HunrZuVR7QoQ6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PF4HunrZuVR7QoQ6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PF4HunrZuVR7QoQ6 .error-icon{fill:#552222;}#mermaid-svg-PF4HunrZuVR7QoQ6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PF4HunrZuVR7QoQ6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PF4HunrZuVR7QoQ6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PF4HunrZuVR7QoQ6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PF4HunrZuVR7QoQ6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PF4HunrZuVR7QoQ6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PF4HunrZuVR7QoQ6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PF4HunrZuVR7QoQ6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PF4HunrZuVR7QoQ6 .marker.cross{stroke:#333333;}#mermaid-svg-PF4HunrZuVR7QoQ6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PF4HunrZuVR7QoQ6 p{margin:0;}#mermaid-svg-PF4HunrZuVR7QoQ6 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PF4HunrZuVR7QoQ6 .cluster-label text{fill:#333;}#mermaid-svg-PF4HunrZuVR7QoQ6 .cluster-label span{color:#333;}#mermaid-svg-PF4HunrZuVR7QoQ6 .cluster-label span p{background-color:transparent;}#mermaid-svg-PF4HunrZuVR7QoQ6 .label text,#mermaid-svg-PF4HunrZuVR7QoQ6 span{fill:#333;color:#333;}#mermaid-svg-PF4HunrZuVR7QoQ6 .node rect,#mermaid-svg-PF4HunrZuVR7QoQ6 .node circle,#mermaid-svg-PF4HunrZuVR7QoQ6 .node ellipse,#mermaid-svg-PF4HunrZuVR7QoQ6 .node polygon,#mermaid-svg-PF4HunrZuVR7QoQ6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PF4HunrZuVR7QoQ6 .rough-node .label text,#mermaid-svg-PF4HunrZuVR7QoQ6 .node .label text,#mermaid-svg-PF4HunrZuVR7QoQ6 .image-shape .label,#mermaid-svg-PF4HunrZuVR7QoQ6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-PF4HunrZuVR7QoQ6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PF4HunrZuVR7QoQ6 .rough-node .label,#mermaid-svg-PF4HunrZuVR7QoQ6 .node .label,#mermaid-svg-PF4HunrZuVR7QoQ6 .image-shape .label,#mermaid-svg-PF4HunrZuVR7QoQ6 .icon-shape .label{text-align:center;}#mermaid-svg-PF4HunrZuVR7QoQ6 .node.clickable{cursor:pointer;}#mermaid-svg-PF4HunrZuVR7QoQ6 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PF4HunrZuVR7QoQ6 .arrowheadPath{fill:#333333;}#mermaid-svg-PF4HunrZuVR7QoQ6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PF4HunrZuVR7QoQ6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PF4HunrZuVR7QoQ6 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PF4HunrZuVR7QoQ6 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PF4HunrZuVR7QoQ6 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PF4HunrZuVR7QoQ6 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PF4HunrZuVR7QoQ6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PF4HunrZuVR7QoQ6 .cluster text{fill:#333;}#mermaid-svg-PF4HunrZuVR7QoQ6 .cluster span{color:#333;}#mermaid-svg-PF4HunrZuVR7QoQ6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PF4HunrZuVR7QoQ6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PF4HunrZuVR7QoQ6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-PF4HunrZuVR7QoQ6 .icon-shape,#mermaid-svg-PF4HunrZuVR7QoQ6 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PF4HunrZuVR7QoQ6 .icon-shape p,#mermaid-svg-PF4HunrZuVR7QoQ6 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PF4HunrZuVR7QoQ6 .icon-shape .label rect,#mermaid-svg-PF4HunrZuVR7QoQ6 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PF4HunrZuVR7QoQ6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PF4HunrZuVR7QoQ6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PF4HunrZuVR7QoQ6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 链接
长方形
圆
圆角长方形
菱形
- 关于 Mermaid 语法,参考 这儿,
FLowchart流程图
我们依旧会支持flowchart.js的流程图语法:
Created with Raphaël 2.3.0 开始 我的操作 确认? 结束 yes no
- 关于 Flowchart流程图 语法,参考 这儿.
导出与导入
导出
如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。
导入
如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。
-
注脚的解释 ↩︎
*[HTML]: 超文本标记语言