Forgejo

文章目录

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/forgejoforgejo,符合预期。

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_PORTSSH_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. 完成安装向导

  1. 浏览器打开 http://<服务器IP>:3000
  2. 首次进入是安装页。数据库部分已由环境变量预填为 SQLite,重点确认:
    • 服务器域名 / Forgejo 基础 URL:与实际访问地址一致
    • 禁用注册:建议勾选,之后由管理员手动建号
  3. 展开「管理员账号设置」,直接在这里创建管理员(跳过就得用命令行补)
  4. 点「立即安装」,等待自动重启并登录

若报 unable to open database file: no such file or directory,先用一条命令区分是权限、SELinux 还是路径填错:

bash 复制代码
docker exec forgejo sh -c 'id; ls -ldZ /data; touch /data/_t && echo WRITE_OK || echo WRITE_FAIL; rm -f /data/_t'

绝大多数情况是第 2 步漏了 chownWRITE_FAILls 显示属主 root),在宿主机执行下面两行后回到安装页重点一次「立即安装」即可:

bash 复制代码
chown -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.ymlservices: 下追加:

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:什么时候做完

设计初衷 :里程碑是给议题加的时间维度 。议题本身只回答「要不要做」,挂上里程碑才回答「什么时候必须做完」。一个迭代、一个版本、一个交付节点,各对应一个里程碑。

怎么用

  1. :仓库 → 顶部 议题 标签 → 议题列表右上「里程碑 」→「新建里程碑」→ 填标题 + 截止日期 + 描述
    • 入口藏在议题标签页里,左侧菜单栏没有独立入口,很容易找不到
    • 直达地址更快:http://<服务器>:3000/<组织>/<仓库>/milestones
  2. 挂议题
    • 单个 → 打开议题,右侧边栏「里程碑」下拉选
    • 批量 → 议题列表勾选多个 → 顶部操作条 → 里程碑 → 选目标
  3. 看进度 :里程碑详情页有完成进度条(已关闭 / 总数)和逾期标红,可直接当迭代评审的入口
    与版本发布的分工 :里程碑是计划视角 (截止日 + 进度),版本发布是产物视角 (tag + 制品 + 发布说明)。发版时两个都要有,别只建里程碑。
    一个限制 :里程碑只有仓库级。迭代横跨前端/后端/App 多个仓库时,只能各仓库建同名里程碑,进度不汇总。要跨仓库的统一迭代视图,用组织级看板(3.6)。

3.6 看板 Projects:现在卡在哪一环

设计初衷 :看板是给议题加的状态流转维度 。里程碑告诉你「这批事到期了没」,看板告诉你「这批事现在各自卡在哪一环」。

⚠️ 最大的认知坑 :这里的「项目」不是 「一个研发项目/一个产品」,而是一块看板 。一个仓库可以建很多个「项目」,比如 Sprint 24v2.0 发布Bug 分诊,每个都是一块独立的板。名字起得很误导人,别按传统 PM 软件的「项目」去理解。

两种内置模板(建看板时可选,模板只是初始列名,建完可随意增删改):

模板 默认列 适用
基础看板 待办 / 进行中 / 已完成 迭代流转
Bug 分诊 待分析 / 高优先级 / 低优先级 / 已关闭 缺陷分诊
对应的服务端配置项是 PROJECT_BOARD_BASIC_KANBAN_TYPEPROJECT_BOARD_BUG_TRIAGE_TYPE,可在 app.ini 里改成团队自己的术语。
怎么用
  1. :仓库 → 顶部 议题 标签 → 列表右上「项目」→ 新建 → 填名字、选模板
  2. :从议题列表拖进列,或在看板里列间拖动
    ⚠️ 拖动只改「在哪一列」,不改议题的开/关状态 。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

两条硬限制

  1. 只有仓库级,没有组织级百科 。团队统一知识库的通行做法:建一个专门的 docs 仓库,把它的百科当团队知识库
  2. 网页编辑器不支持拖拽上传图片(附件功能只覆盖议题和合并请求),图片必须走上面的 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/checkoutsetup-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-datadocker-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-onFORGEJO_RUNNER_LABELS
构建容器启动失败 宿主机内核 3.10 太老 换 alpine 系标签;仍失败见附录 B
磁盘占用暴涨 容器日志未做轮转 /etc/docker/daemon.jsonlog-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    # 自检

参考链接

欢迎使用Markdown编辑器

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

新的改变

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法[1](#甘特图的mermaid语法1) 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销: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. 项目1
  2. 项目2
  3. 项目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文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,

继续你的创作。


  1. mermaid语法说明 ↩︎

  2. 注脚的解释 ↩︎

*[HTML]: 超文本标记语言

相关推荐
smartpi_ai6 小时前
空调内机做语音控制选哪颗?CI-03T 的红外码库优势、“5V 供电≠3.3V 串口“的电平误区与声学结构规范
人工智能·ci/cd·语音识别
领麦微红外1 天前
W-6D2红外测温赋能:电磁炉精准控温与成本优化
产品经理·智能硬件
跨境数据猎手1 天前
拆解反向海淘:当海外博主开始教老外“淘宝”
团队开发·产品经理·需求分析
极小狐1 天前
干掉流水线里的长期密钥:用 OIDC 让 CI/CD 与云以临时凭证对接
microsoft·ci/cd·gitlab·devops·ci·cd·oidc
领麦微红外2 天前
告别进口依赖,FW系列打造远距离红外测温国产方案
产品经理·智能硬件
极小狐2 天前
CI 流水线提速实战:缓存设计与依赖代理的工程实践
缓存·ci/cd·gitlab·devops
11路没有终点2 天前
CI/CD 集成:GitHub Actions
ci/cd·github
harmony&2 天前
DevOps 实战:从概念到 CI/CD 持续交付全流程
运维·ci/cd·devops
DevOps老兵3 天前
AI Infra实战11:模型部署Pipeline——CI/CD自动化
人工智能·ci/cd·ai·自动化·gitlab