Redmine 5.1.4 这个版本,我前后给几个项目环境都部署过,每次都会被同一个问题卡一下:代码仓库到底怎么跟项目管理串起来。很多团队把 Redmine 只当成任务看板来用,研发在 Git 里提交代码,Redmine 里完全看不到痕迹,评审的时候还要跑到 Git 平台上去翻 commit,来回切换效率很低。这篇文章我按实际安装顺序,把 Redmine 5.1.4 里接入 Git 仓库、以及安装 Additionals 插件的完整过程写下来,包括内置 Git 模块的配置、Additionals 的依赖与迁移、以及进阶路线里 SSH 认证失败的排查思路,适合负责 Redmine 维护的运维同学参考,也适合刚接手项目管理系统、想把代码和任务打通的团队技术负责人照着操作。
1. 先盘清楚:Redmine 的 Git 支持有哪些档次,Additionals 又是干什么的
1.1 集成 Git 的三条路线,别一上来就选最重的
Redmine 5.1.4 本身不是一个空白系统,它核心代码里已经内置了版本库(Repository)模块,天然支持 Git。很多朋友第一次接触时会被"Git 插件"这个说法带偏,以为必须装额外的插件才能用 Git,实际上不是这样。从集成深度来看,主要有三条路:
- 内置 Git 模块:Redmine 自带功能,只要服务器上装了 Git 命令行工具,然后在项目设置里填一个 Git 裸仓库的路径,就可以浏览代码、看提交历史、做版本对比。这是最轻量、最稳定、兼容性最好的方式。
- 第三方 Git 托管插件(redmine_git_hosting):这类插件不仅让 Redmine 能读取 Git 仓库,还能直接在 Redmine 里创建仓库、管理系统用户、管理 SSH 公钥,相当于把 Redmine 变成了一个轻量级 Git 托管平台。功能强,但安装配置复杂度明显上升,还会改变仓库的存储方式,迁移成本高。
- 对接外部 Git 平台(Gitea、GitLab、Bitbucket):通过插件或 API 把外部平台的仓库同步到 Redmine 显示。适合已经有正式代码托管平台的团队,但引入的依赖比较多,一般企业环境用不上。
我这次安装采用"内置模块为主、redmine_git_hosting 作为进阶方案"的组合。为什么这么选?因为生产环境最重要的是稳定可复现。内置模块是 Redmine 核心团队维护的,升级时不容易出兼容性问题;而 redmine_git_hosting 这类第三方插件虽然好用,但它的底层依赖(SSH、OpenSSH 配置、多用户权限)一旦和服务器既有配置冲突,排查起来非常费时间。如果你的团队连 Git 服务器都还没有,那就另说,后面我会单独写清楚什么时候必须上托管插件。
1.2 Additionals 解决的是"默认功能不够顺手"这一类问题
Additionals 是一个综合性的 Redmine 增强插件,不属于版本库范畴,但它几乎是 Redmine 装上之后用的最频繁的扩展之一。它解决的问题很琐碎,但都很真实:比如项目列表想加收藏功能、页面标题想显示文档名而不是文件路径、Wiki 里想插入到期日期提醒和倒计时、帮助菜单想自定义成团队自己的规范——这些都是 Redmine 默认不提供、又确实影响日常使用体验的小需求。Additionals 把这类零散增强集中到一个插件里,避免为了一个小功能装一堆插件导致依赖打架。
安装 Additionals 本身不算复杂,但有一个很容易被忽略的点:它的版本必须和 Redmine 5.1.4 匹配。Additionals 的 GitHub 仓库 README 里有一张版本兼容矩阵表,4.x 系列对应 Redmine 5.x。装之前如果不看这个,直接 clone 最新分支,很可能在bundle install阶段就报 gem 依赖错误。
1.3 本次安装路线图
为了让你对后面的步骤有个整体概念,我先用一张表把安装主线列出来:
| 阶段 | 操作对象 | 预期结果 |
|---|---|---|
| 环境检查 | Redmine 实例、Ruby、Git | 确认版本与命令可用 |
| 路径规划 | 裸仓库目录、Redmine 运行用户 | 权限正确,仓库可读写 |
| 内置 Git 接入 | 项目设置中的版本库模块 | 能浏览提交历史和代码差异 |
| Additionals 安装 | plugins 目录、数据库迁移 | 管理后台插件列表出现 Additionals |
| 托管插件进阶 | redmine_git_hosting 与 SSH 配置 | 服务端 SSH 认证可正常推送 |
| 验证与维护 | 测试仓库、升级流程 | 功能全部可用且可备份恢复 |
下面每一步我都会说清楚命令、原理和容易踩的坑。
2. 环境检查与路径规划:装之前不踩坑
2.1 先确认 Redmine 版本和 Ruby 环境
不管你是用什么方式装的 Redmine(源码包、Bitnami 镜像、Docker),第一步永远是对版本。Redmine 5.1.4 对应的 Ruby 要求是 2.7 到 3.1 之间,Rails 版本是 6.1。版本不匹配的问题一般不会在启动时报,而是在你执行bundle install或者插件数据库迁移时突然爆炸,所以最好提前确认。
cd /var/www/redmine ruby bin/about这个命令会打印出 Redmine 版本、Ruby 版本、Rails 版本、以及当前已安装的插件列表。如果这里显示的版本不对,先别往下走,解决基础环境问题比排查插件问题容易十倍。
同时检查一下plugins目录是否存在、是否归当前运行用户拥有。Redmine 源码包安装后,这个目录默认存在,但有些一键安装包会把它放在别的路径,或者权限很怪。我用的是源码包,目录直接在/var/www/redmine/plugins,后面所有插件都往这里放。
2.2 Git 命令路径:Redmine 能不能找到 git 是关键
Redmine 内置 Git 模块本身不包含 Git 的读仓库逻辑,它是通过调用服务器上的 git 命令行来完成的。所以服务器必须装有 Git,而且 Redmine 运行用户必须能在 PATH 环境变量里找到 git。
git --version which git如果输出类似/usr/bin/git,那一般没问题。但有一个特殊场景很容易中招:Bitnami 安装的 Redmine。Bitnami 出于隔离考虑,启动 Redmine 服务时的 PATH 经常不包含/usr/bin,于是 Redmine 后台扫描版本库时提示找不到 git 命令。解决办法是在 Redmine 的配置里显式指定 git 路径,在config/configuration.yml中加入 scm 相关设置,或者通过管理后台的"管理 -> 设置 -> 版本库 -> Git 命令路径"来填写绝对路径。我实际遇到的情况就是后者,填上/usr/bin/git之后刷新就正常了。
提示:填绝对路径之前先确认 git 的真实位置,不要想当然。
which git输出在哪个目录就填哪个目录。
2.3 裸仓库目录规划与运行用户授权
这里是一个非常高频的翻车点。Redmine 通过 Web 进程运行,默认用户可能是www-data、redmine或者daemon,不同安装方式不一样。如果你把 Git 裸仓库放在一个 Web 进程没有读权限的目录里,Redmine 界面上版本库标签会一直转圈,然后日志里报权限错误。
我推荐的目录规划是这样的:
sudo mkdir -p /srv/git/repositories sudo chown -R redmine:redmine /srv/git/repositories注意这个redmine用户要根据你实际的运行用户来替换。怎么确认当前 Redmine 跑在哪个用户下?用ps aux | grep redmine或者ps aux | grep puma/passenger看进程归属。确认之后,除了仓库目录的读写权限,还要验证运行用户能否调用 git:
sudo -u redmine bash -lc 'git --version'如果这一步报git: command not found,那么问题就回到了 2.2,你需要调整 PATH 或者改配置。这一步很多人跳过,结果后面仓库怎么都加不进去,绕了一大圈才发现是运行用户调不到 git 命令。
2.4 时区与日志检查习惯
这一步虽然不是必须,但我强烈建议先养成习惯:排查 Redmine 问题时,第一现场永远是log/production.log。在处理版本库问题时,Redmine 会在这里记录 fetch 和 git 命令执行的报错信息。
tail -f /var/www/redmine/log/production.log打开一个终端窗口挂着,后面配置仓库和插件的时候,你会看到很多界面上看不出来的细节。
3. 内置 Git 模块接入企业仓库:从裸仓库到 Issue 联动
3.1 初始化 Git 裸仓库
Redmine 的 Git 集成要求仓库是裸仓库(bare repository),也就是没有工作区的仓库。这个设计很合理:Redmine 只负责读对象数据、展示提交历史和代码差异,不需要 checkout 出文件,所以裸仓库既节省空间又避免了工作区冲突。
cd /srv/git/repositories git init --bare --initial-branch=main myproject.git--initial-branch=main是 Git 2.28 以后的参数,指定初始分支名。如果你们团队还在用master,也可以不写这个参数,但这不重要,重要的是初始分支名要和后续 Push 的分支一致。git init --bare之后,目录里没有源代码,只有objects、refs、HEAD等管理文件,这就是裸仓库的核心特征。
对开发同事来说,使用方式没有任何变化:
git remote add origin redmine-server:/srv/git/repositories/myproject.git git push -u origin main从这里开始,代码就进入 Redmine 的可视范围了。
3.2 在 Redmine 项目设置中登记仓库
仓库初始化好之后,回到 Redmine 界面。进入某个项目,点"设置 -> 版本库 -> 新建版本库",核心配置项如下:
- 版本控制系统:选择 Git
- 仓库路径:填
/srv/git/repositories/myproject.git这个绝对路径 - 标识:给仓库起一个显示名称,比如
main-repo - 分支/标签:一般默认即可,Redmine 会动态读取
保存之后,Redmine 会尝试读取这个裸仓库。如果配置正确,项目左侧的"版本库"标签下立刻就能看到文件列表和提交记录。第一次读取如果仓库历史很长,可能需要等几秒,Redmine 是异步 fetch 的,日志里会有记录。
常见的一种情况是保存后版本库页面显示"The entry or revision was not found in the repository"(条目或版本在仓库中不存在)。这个报错 80% 是因为仓库路径填错,或者 Redmine 运行用户读不了那个目录。先检查路径是否有拼写错误,再用 2.3 里的sudo -u redmine验证一下读权限,基本都能解决。
3.3 提交信息自动关联 Issue:团队协作的隐形纽带
内置 Git 模块最有价值的点,是提交信息可以和 Issue 自动关联。开发者在提交代码时,只要在 commit message 里写上#问题编号,Redmine 就会在对应问题下自动显示这条提交记录,同时版本库页面也能反查到这个问题。
比如:
git commit -m "修复登录超时问题 #123"提交并推送后,Redmine 会通过 git log 解析提交信息,在问题 #123 的活动历史里出现"关联的修订版本"记录。对于团队管理来说,这意味着从需求到代码的完整链路被串起来了:产品看点状态,开发点提交记录,测试点问题修复历史,都在同一个系统里完成。
这个"引用关键词"不是写死的,Redmine 允许自定义。路径在"管理 -> 设置 -> 版本库",里面有关键词配置,默认支持refs、references、Related等,修复类关键词fixes甚至可以配合状态流转自动关闭问题。如果你的团队想统一用close #123这种格式,在那里配置就行。
3.4 查看提交历史和差异对比的正确姿势
仓库接入之后,日常用的最多的就是两个功能:一是版本库页面的提交历史,按时间倒序列出所有 commit,点击任意一条可以看这次提交改了哪些文件、每处改动的内容是什么;二是文件浏览,可以直接在网页上查看某个文件的最新内容,还可以点进历史版本查看演进过程。
Redmine 5.1.4 在这个模块上比较成熟,分支切换、标签浏览都支持。代码评审时我们团队的习惯是:评审者打开版本库页面,按分支筛选提交,逐条看 diff,看完直接在对应 Issue 下写评论。整个过程不需要离开 Redmine,也不需要给评审者开 Git 平台的权限,这在跨团队协作时能省不少事。
3.5 初始仓库为空时的小技巧
如果你的项目是从零开始的,仓库里还没有任何提交,Redmine 在版本库页面会提示"仓库仓库是空的"之类的内容,这是正常的。但要注意一点:如果初始分支名和 Redmine 默认读取的分支不一致,比如裸仓库初始分支是master,而开发同事推送的是main,版本库页面可能显示为空。遇到这种情况,在分支选择器里切换一下分支即可,不用重新配置仓库。
4. Additionals 插件安装实录:从代码下载到功能启用
4.1 版本匹配是第一步,不是 clone 是第一步
Additionals 插件的官方仓库是https://github.com/AlphaNodes/additionals,安装位置在 Redmine 的plugins目录下:
cd /var/www/redmine/plugins git clone https://github.com/AlphaNodes/additionals.git cd additionals git checkout 4.x注意我写了git checkout 4.x这一行,这是整个 Additionals 安装里最容易翻车的地方。Additionals 有很多版本分支和标签,直接 clone 默认分支不一定与 Redmine 5.1.4 兼容。我建议去看一眼 README 里的"Requirements"段落,里面会明确写当前分支支持哪些 Redmine 版本。以 Installation 时的情况为例,Additionals 4.2.x 支持 Redmine 5.1.x,这个组合是经过多人验证的。
4.2 bundle install 安装依赖:耐心等,别中断
Redmine 的插件本质上是 Rails 引擎,Additionals 引入了自己的 gem 依赖,所以下载完代码不是结束,而是刚开始。
cd /var/www/redmine bundle install --without development test这一步会安装插件依赖的 gem,时长取决于网络和系统环境,可能几分钟到十几分钟。有几个点需要特别注意:
- bundle 命令要以 Redmine 项目根目录为工作目录,不能在
plugins/additionals里执行,否则 bundler 找不到 Redmine 的 Gemfile。 - 不要用
--jobs强行并行编译,有些 gem(尤其带原生扩展的)并行编译反而容易出错。 - 如果中途报
nokogiri或ffi相关编译错误,一般是系统缺少编译依赖,先安装对应的开发包再重试,比硬绕过去靠谱。
4.3 插件数据库迁移:这一步不做等于白装
插件会创建自己的数据表和保存配置项的存储记录,所以需要执行迁移命令。这是所有 Redmine 插件的统一操作:
bundle exec rake redmine:plugins:migrate RAILS_ENV=production执行完会看到类似"迁移插件 Additionals 成功"的输出。迁移命令是可重复执行的,Redmine 会记录每个插件的迁移版本号,升级插件后再次执行只会执行新增的迁移,不会重复跑旧迁移。这也是为什么后面你每次升级 Additionals 时,都要把这个命令重新跑一遍的原因。
然后重启 Redmine。使用 Passenger 部署的话,执行:
touch /var/www/redmine/tmp/restart.txt如果是 systemd 服务:
systemctl restart redmine重启后进入"管理 -> 插件"页面,列表里应该能看到 Additionals 及其版本号。看到版本号只说明插件的骨架注册成功了,功能还需要配置。
4.4 按团队习惯启用功能,别一股脑全开
Additionals 的特点之一是功能模块很多,安装后默认不会全部开启,需要在项目设置或插件设置里逐个启用。我这次实际启用的模块和理由如下:
| 功能模块 | 作用 | 适用场景 |
|---|---|---|
| 项目收藏 | 项目列表加星标收藏,常用项目置顶 | 项目数量多的团队,避免每次翻列表 |
| Wiki 宏扩展 | 在 Wiki 里插入日期提醒、倒计时等动态内容 | 需要页面提示截止日期的场景 |
| 页面标题增强 | 显示文档标题而不是文件路径 | 文档浏览体验提升明显 |
| 自定义菜单 | 增加团队自己的全局菜单项 | 放常用入口或外部链接 |
这些功能对日常使用体验的提升很直接,尤其项目收藏和页面标题增强,几乎是装了就能感受到差别。但我不建议把 Additionals 的所有开关一次性全部打开,一是部分功能会改变 Redmine 原有页面的布局,二是功能多了之后,一旦出现页面异常,排查范围会被扩大。
4.5 Additionals 和 Git 模块的组合用法
既然标题里同时提到了 Git 和 Additionals,我多说一句两者联动的地方。Additionals 的 Wiki 增强功能可以让你在每个项目的 Wiki 首页做一个"项目状态页",把当前分支、最新提交、关联任务整理成一张看板。具体做法是:在 Wiki 页面里插入自定义宏,将提交动态和任务到期提醒集中展示。这种用法在我们的项目里效果很好,产品经理打开项目首页就能看到代码进展和任务风险,不需要再单独翻版本库和问题列表。
5. 升级路线:redmine_git_hosting 托管方案与 SSH 认证排错
5.1 什么时候才需要上重量级托管插件
内置 Git 模块的定位是"读取和展示",它不负责创建仓库、管理用户权限、处理 SSH 密钥。如果你的团队只有三五个人,代码仓库已经由运维手动创建好了,那内置模块完全够用。但如果你希望 Redmine 能承担 Git 托管职责——开发同事在 Redmine 界面里创建新仓库、管理 SSH 公钥、自主建分支——那就要上redmine_git_hosting这类托管插件了。
这里要先给你打个预防针:托管插件改变了仓库的存储方式和管理模型。安装之后,插件会把仓库路径重新组织,以项目标识作为子目录,原有裸仓库需要迁移。这意味着从内置模块切换到托管方案,不是简单插一个插件,需要规划数据迁移。所以我的建议是:先想清楚需求边界,再决定走哪条路,如果只是想让 Redmine 能看代码和关联任务,内置模块永远是最稳的选择。
5.2 redmine_git_hosting 的安装与关键配置
如果确认需要托管方案,安装步骤可以参考下面的流程:
cd /var/www/redmine/plugins git clone https://github.com/jbox-web/redmine_git_hosting.git cd /var/www/redmine bundle install bundle exec rake redmine:plugins:migrate RAILS_ENV=production touch tmp/restart.txt安装本身和 Additionals 流程类似,但配置上复杂很多,核心在config/configuration.yml中加入插件参数。通常需要指定:
redmine_git_hosting: gitUser: git gitRepositoriesBasePath: /srv/git/repositoriesgitUser是执行 git 命令的系统用户,gitRepositoriesBasePath是仓库根目录。这背后涉及 SSH 公钥管理和用户身份切换,插件文档里对这两个参数有详细说明。你需要根据自己的 SSH 环境调整,不能照抄。
这里我还想强调一个容易忽略的点:redmine_git_hosting 这类插件对 Redmine 版本、Ruby 版本的敏感程度远高于 Additionals。安装前一定要确认 README 里的兼容矩阵,否则bundle install阶段就会因为 Ruby 版本不支持而失败。
5.3 SSH 认证失败的高频原因和完整排查链路
既然热搜词里反复出现"ssh认证失败 git",我把这个问题单独拿出来说。用托管插件后,开发同事推送代码走的是 SSH 协议,最常见的报错是Permission denied (publickey)。这个报错让很多人头疼,但排查链路其实很固定,从客户端到服务端逐层缩小范围:
第一步:确认公钥已经添加到 Redmine 个人账号。在 Redmine 中打开个人账号设置,找到 SSH 密钥管理区域,把客户端的~/.ssh/id_ed25519.pub内容粘贴进去。注意要确认粘贴的是公钥而不是私钥,这个错误出现的频率比想象中高。
第二步:确认服务端 sshd 允许公钥认证。检查 Redmine 服务器的/etc/ssh/sshd_config:
grep -E "PubkeyAuthentication|AuthorizedKeysFile" /etc/ssh/sshd_configPubkeyAuthentication必须为yes,否则一切公钥都登不上。改完配置记得systemctl restart sshd。
第三步:确认托管用户和 shell 配置。托管插件通常用专门系统用户(如git)执行仓库操作,这个用户不能是普通可登录用户,一般配置git-shell或插件的专用 shell。如果系统用户配置错误,认证会直接被拒绝。检查:
grep "^git:" /etc/passwd如果 shell 字段是/bin/bash而不是限制 shell,公钥认证即使成功也会因为无法执行受限命令而失败。
第四步:看服务端日志。/var/log/auth.log或/var/log/messages里会记录 SSH 拒绝的具体原因,这一步能直接定位到是密钥匹配失败、还是用户配置问题。
第五步:测试连接。配置完成后,用ssh -T git@redmine-server测试,托管插件一般会输出欢迎信息或可执行的命令列表。能连上就说明认证链路通了,剩下的就是仓库初始化配置问题。
这五步按顺序走下来,90% 的 SSH 认证问题都能定位。我这里之所以把排查链路写在安装流程里,是因为很多同学装完托管插件之后发现推送不上去,第一反应是重装插件,其实问题根本不在插件层面。
6. 安装后的验证清单与日常维护要点
6.1 功能验证清单:装没装成,用这张表说话
安装完成不等于配置完成,配置完成不等于业务可用。我每次交付环境前都会按下面这张表逐项验证,任何一项不通过都要当场解决,而不是留到上线后:
| 检查项 | 操作 | 期望结果 |
|---|---|---|
| Redmine 版本 | ruby bin/about | 显示 5.1.4 |
| Git 命令可用 | 管理后台版本库设置 | 显示 Git 可用及命令路径 |
| 仓库读取 | 项目版本库页面 | 文件列表和提交历史正常显示 |
| 提交关联 | 推送带#问题号的 commit | Issue 下出现关联修订记录 |
| Additionals | 管理 -> 插件 | 列表出现且版本匹配 |
| Additionals 功能 | 项目设置中启用项目收藏 | 项目列表出现收藏星标 |
| SSH 认证(托管方案) | ssh -T git@服务器 | 连接成功无报错 |
6.2 升级 Redmine 和插件时的正确顺序
Redmine 的插件升级有一个原则:先升级 Redmine 主程序,再升级插件,最后执行插件迁移。升级插件之前,先看插件的 README 兼容矩阵,确认它支持当前的 Redmine 版本。Additionals 做得比较好,它对版本兼容的说明很明确;redmine_git_hosting 这类依赖重的插件,升级前最好先在测试环境完整走一遍,避免生产环境直接在bundle install阶段爆炸。
升级后的迁移命令就是前面用过的:
bundle exec rake redmine:plugins:migrate RAILS_ENV=production只要 Redmine 和插件版本都兼容,这个命令可以安全重复执行。
6.3 备份策略里必须包含三项内容
最后说备份。Redmine 的备份容易漏东西,很多人只备数据库,结果插件配置和仓库全丢了。我建议至少把下面三样纳入备份范围:
- 数据库:Redmine 的问题、项目配置、插件设置全在数据库里。
- Redmine 应用目录:
plugins/目录下的插件代码,以及config/configuration.yml。 - 仓库目录:
/srv/git/repositories下的所有裸仓库,连同 hooks 和描述文件一起备份。
裸仓库备份非常简单,直接打包整个目录就行,恢复时解压到原路径、确认权限正确、Redmine 界面刷新即可重新识别。这个方案实测了很多次,是同类场景里最可靠的做法。
按照这套流程走一遍,Redmine 5.1.4 的 Git 仓库接入和 Additionals 插件配置基本不会出现意外。如果中途卡住了,先回看日志,再对照本文的环境检查部分逐步排查——大部分问题其实都出在最初的环境准备阶段。