你有没有认真想过一个问题:代码放在别人的服务器上,真的完全踏实吗?
我经常被问到“Git自建用什么工具比较好”,尤其是2025年的现在,各大托管平台的免费额度越来越抠,隐私合规的要求越来越多,团队对代码资产的控制欲也越来越强。大家嘴上说得很随意,其实背后都是在纠结同一个事情:脱离开源社区那套“托管在别人家”的默认玩法,我们能不能自己把代码仓库撑起来,而且撑得舒服?
这篇文章就是来回答这个问题的。我会从“到底要不要自建”开始聊,然后把2025年主流的几个自建方案拉出来,从资源占用、功能覆盖、维护成本、适合场景几个维度扎扎实实对比一遍。最后用一套完整的实操步骤,带你跑通一个能日常使用的自建Git服务,包括HTTPS、SSH、备份和客户端配合。无论你是个人开发者、小团队技术负责人,还是公司内部基础设施的维护者,都能在这篇里找到适合自己的答案。
1. 先搞清楚你到底需不需要自建Git仓库
很多人一上来就问“Gitea和GitLab哪个好”,我每次都要先拦一下:这个问题问早了。选型是第二步,第一步是你得先确认自己是不是真的需要自建。否则工具再强,对你也是负担。
1.1 自建Git服务的几个典型场景
这些年我接触过的自建需求,基本逃不出下面四类情况。
第一类是合规和内网隔离需求。公司内部项目涉及客户数据、核心算法,或者干脆整个研发环境就在内网,和外网物理隔离。这种情况下代码绝对不能出内网,公网托管平台直接出局。第二类是定制化和集成需求。很多团队不满足于“有个地方放代码”,他们想把代码仓库和内部的CI/CD系统、工单系统、统一登录认证(LDAP/OAuth2)深度打通,还要控制Webhook、权限模型、分支策略。这在公有平台上能实现,但自建显然更灵活。第三类是性能和数据主权需求。在海外平台上托管代码,访问速度忽快忽慢,动辄clone一个仓库等半天;或者你对平台条款不放心,希望代码资产的存储、备份、迁移进程都由自己掌控。第四类最简单,也最容易被忽略——个人长期知识资产的沉淀。你写了十年的代码、脚本、笔记、配置,存在第三方平台免费账户里,哪天号被封了或者平台调整政策,你的“数字资产”说没就没。自建等于给这些东西买了一份“产权保险”。
如果你中了以上任意一条,自建Git就是值得投入的事。一条都不中的话,建议慎重。一个人用公有平台的免费私有仓库足够了,没必要给自己找一台服务器天天折腾。
1.2 自建之前先想明白的几个问题
决定自建之后,我建议先回答四个问题,想清楚了,选型其实自己会浮出水面。
第一个问题:团队规模到底有多大?1到5人的个人项目,和100人的研发团队,用的工具完全不是一回事。前者追求轻量、简单、省心,后者追求权限模型、代码评审、审计日志、高可用。第二个问题:服务器资源能给到什么程度?一台2核4G的云主机,和一台16核64G的物理服务器,能承载的方案差距巨大。第三个问题:谁来维护?是开发人员顺带管,还是有专职运维?这决定了你要不要选一个“自动升级、少碰配置”的方案,还是一个“灵活但需要精心照料”的方案。第四个问题:你需要哪些周边能力?光是存代码,最轻的方案一个半小时就能跑起来。但如果要内置CI/CD、制品库、依赖扫描、安全检测这些全家桶能力,那就得上重型的完整平台。
我见过太多人,团队一共五个人,却按五百人的规模上了全套GitLab,折腾三个月还没稳定,最后又退回轻量方案。记住一个原则:选型不是选最强的,是选“刚好够用且有余量”的。
2. 2025年Git自建主流方案全景对比
2025年这个时间点,Git自建方案比几年前成熟太多了。现在你再也不用从零开始搭Git裸仓库加一堆辅助脚本,拿现成的开源方案部署就行。主流的选手无非这几个:Gitea、Forgejo、GitLab CE、Gogs、Gerrit,以及它们各自带的各种形态的变种。
2.1 轻量级的主力:Gitea与Forgejo
Gitea是我个人用得最多的方案,没有之一。它是Go语言写的,最大的特点就是“轻”。整个服务就是一个二进制文件,部署起来简单得离谱,内存占用通常在300MB以内,1核512MB的服务器就能跑得很欢快。功能上,Pull Request评审、Issue追踪、里程碑、Wiki、Webhook、分支保护、LFS大文件支持,这些日常用得上的东西它全都具备。而且Gitea的界面非常接近GitHub,迁移成本极低,团队上手几乎不需要培训。
Gitea还有一点我很喜欢,就是它对资源和硬件的要求非常宽容。树莓派、NAS、吃灰的旧笔记本,都能变成一个小型Git服务器。2025年Gitea对内置Actions的支持也完善了很多,虽然比不上GitLab CI那么完整,但跑常规的构建、测试、部署流水线绰绰有余。
Forgejo是Gitea的一个硬分叉,诞生原因是社区对Gitea治理模式的分歧。它的核心理念是“把软件的控制权保留在社区和用户手中”。功能层面,Forgejo和Gitea大体保持一致,曾经的版本号分裂(Gitea 1.x和Forgejo 7.x并用)现在已经逐步收敛。如果让我给一个简单建议:单纯求稳、求省事就选Gitea;如果你对社区治理有追求,或者想支持那把“去中心化”的火,选Forgejo也不会踩坑。
2.2 功能全家桶:GitLab Community Edition
GitLab CE是“重型自建”的标准答案。它的功能覆盖面之广,在开源Git服务平台中可以说是独一档:内置CI/CD(GitLab Runner)、容器镜像仓库、依赖扫描、安全测试、代码质量、效能分析……基本上一个平台覆盖了从代码托管到运维发布的完整链路。界面风格现代,代码评审体验做得也细致,支持多级权限体系、审计事件、合并请求规则等企业级功能。
但所有这些能力都是有代价的。GitLab CE基于Ruby on Rails,资源消耗和Gitea完全不是一个量级。官方推荐的最低配置是4GB内存起步,实测8GB内存跑起来才比较从容。而且它的升级、排障、备份恢复都要比轻量方案复杂不少,手动装一次就能把人折腾掉一层皮。所以GitLab CE真正适合的是:团队规模够大(至少几十人),有专门的服务器资源,并且需要全家桶能力一体化交付的场合。
2.3 括号里的选项:Gogs与Gerrit
Gogs是Gitea的前辈,同样用Go写,同样极轻。但问题是它的开发节奏明显放缓,功能迭代跟不上时代,中文文档和UI也偏旧。除非你是老用户,维护着历史系统不想迁移,否则新项目不建议在2025年再选Gogs了。
Gerrit则是另一个维度的存在。它本质上是为“代码评审”而生的系统,Git只是它管理的对象,核心工作是强制所有变更走“Push for Review”的审阅流程,评审通过之后才能真正合入代码。很多开源项目(比如Android)早期就是用Gerrit管理代码的。但它的工作流学习曲线非常陡峭,对团队协作纪律要求极高,不是所有人都能适应。如果你的团队主要诉求是严谨的代码评审而非快速迭代,可以看看Gerrit;大多数人和团队,我还是建议在Gitea和GitLab之间做选择。
2.4 各方案核心参数速览
为了让你一眼看清差距,我把主推的几个方案汇总成一张表。
| 方案 | 开发语言 | 最低内存参考 | 内置CI/CD | 代码评审能力 | 权限粒度 | 维护成本 | 适合场景 |
|---|---|---|---|---|---|---|---|
| Gitea | Go | 256MB 能跑,1GB 舒服 | 支持Actions | 基础PR评审,够用 | 组织/仓库/分支 | 低 | 个人、小团队、内网环境 |
| Forgejo | Go | 约同Gitea | 支持Forgejo Runner | 同Gitea | 同Gitea | 低 | 推崇社区治理的小团队 |
| GitLab CE | Ruby | 4GB起步,8GB舒服 | 完整CI/CD | 强,支持多级审批 | 多级、细化 | 高 | 中大型团队、完整DevOps平台 |
| Gogs | Go | 128MB能跑 | 弱 | 基础 | 基础 | 低 | 极简场景,不建议新用 |
| Gerrit | Java | 2GB起步 | 弱 | 极强,评审为核心 | 细 | 高 | 强代码评审流程的团队 |
这张表你可以存下来。后面所有讨论,基本都离不开这五个维度:资源、功能、评审、权限、维护。
3. 动手实操:以Gitea为例搭建生产可用的Git服务
既然对比完了,我们来点实在的。我以Gitea为例,从零开始搭建一套能日常使用的自建Git服务,把部署、HTTPS、SSH、备份、客户端配合全走一遍。之所以选Gitea,是因为它轻、快、适合大多数人的第一台自建服务器,这套流程你跑通了之后,换到Forgejo或者GitLab也只是换汤不换药。
3.1 准备工作与部署方式选择
在动手之前,你要准备好三样东西:一台Linux服务器(Ubuntu 22.04 LTS或Debian 12都行,1核2G内存起步)、一个域名(可选,但强烈建议,后面配置HTTPS省心非常多)、以及一个学习的心态。
安装Gitea常见有三种方式:直接下载二进制、用Docker部署、用系统包管理器安装。我个人最推荐Docker Compose方式。原因很简单:Gitea依赖数据库(MySQL/MariaDB/SQLite)和反向代理,用容器编排可以把这些组件一次性拉起,环境隔离干净,升级和回滚都很方便,备份也只要管几个数据卷。你不需要在一台干净服务器上手工装MySQL、装Nginx、再配一堆环境变量,这些环节最容易出错。
第一次尝试的话,请务必在你的服务器上装好Docker和Docker Compose插件,然后用我下面这份配置。
3.2 利用Docker Compose快速部署Gitea
docker-compose.yml文件直接写成这样:
version: "3" services: gitea: image: gitea/gitea:latest container_name: gitea environment: - USER_UID=1000 - USER_GID=1000 - GITEA__database__DB_TYPE=mysql - GITEA__database__HOST=db:3306 - GITEA__database__NAME=gitea - GITEA__database__USER=gitea - GITEA__database__PASSWD=gitea restart: always volumes: - ./gitea:/data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro ports: - "3000:3000" - "2222:2222" depends_on: - db db: image: mysql:8.0 restart: always environment: - MYSQL_ROOT_PASSWORD=gitea - MYSQL_DATABASE=gitea - MYSQL_USER=gitea - MYSQL_PASSWORD=gitea volumes: - ./mysql:/var/lib/mysql在配置所在目录执行:
docker compose up -d等镜像拉取完成、容器启动之后,浏览器访问http://服务器IP:3000,就能看到Gitea的首次安装引导页面。
这里有几个细节值得注意。首先是MySQL密码不要用示例里的弱口令,生产环境请换成强度足够的密码,并同步修改环境变量和连接地址。其次是端口映射,我把Gitea的Web服务映射到主机的3000端口,把Gitea自带的SSH服务映射到主机的2222端口。为什么不用22?因为22端口通常被服务器自身的SSH占用了,让Gitea的SSH服务换到2222,可以避免和系统SSH冲突,也更安全。
首次安装页面里,数据库类型、主机、名称、用户、密码这些我已经通过环境变量预设好了,你只需要确认站点名称、服务器域名、SSH服务器端口是否填写正确。这里有一个老手常踩的坑:如果你打算后面用域名加HTTPS访问,站点URL一定要提前填成https://git.example.com,不要先用IP地址。因为Gitea会把站点URL写入数据库,后面再改会导致某些资源路径和仓库克隆地址还是旧的。
3.3 配置HTTPS、SSH端口与备份策略
Gitea自带的Web服务是HTTP的,生产环境绝对不能直接暴露裸端口。我建议用反向代理把它包一层。这里极力推荐Caddy,它最香的特性是自动申请和续期HTTPS证书,无需手动配置。Caddyfile只需要三行:
git.example.com { reverse_proxy 127.0.0.1:3000 }把域名解析到服务器IP,启动Caddy,证书自动签发,HTTPS直接生效。第一次访问可能会等个十几秒,那是证书签发的时间。如果你用的是Nginx,也可以,但没有Caddy那么省心。在我实际使用中,Caddy这步基本零配置,非常稳。
SSH端口的配置就稍麻烦一点。由于Gitea的SSH服务监听在2222端口,所有clone地址默认会是ssh://git@git.example.com:2222/owner/repo.git,这种带端口的地址虽然能用,但丑,而且有些开发工具对非标准SSH端口支持不友好。更优雅的方式是让客户端通过配置自动识别。比如在开发者的~/.ssh/config文件里加一段:
Host git.example.com HostName git.example.com Port 2222 User git这样clone时只需要写git@git.example.com:owner/repo.git,SSH会自动跳转到2222端口连Gitea,体验和标准SSH一模一样。
备份是我最想强调的一件事。自建服务最大的风险不是宕机,而是数据丢失。Gitea自带了数据导出命令,在容器里执行:
docker exec -u git gitea gitea dump --config /data/gitea/conf/app.ini这个命令会把仓库、数据库、配置、附件全部打包成一个zip文件,输出到/data目录下。我的建议是写一个简单的脚本,每周自动执行一次dump,然后把产物rsync到另一台机器或者对象存储,实现异地备份。这个动作虽然简单,但它决定了你的自建服务能不能长期稳定运行下去。不要等到硬盘损坏了再后悔。
3.4 Git客户端配合与日常使用要点
搭建好服务之后,客户端这边也要做一些基础配置。首先在Windows上安装Git for Windows(就是你平时用的那个git bash套装),安装时保持默认选项即可。安装完成后,打开Git Bash,设置用户信息:
git config --global user.name "你的名字" git config --global user.email "you@example.com"接着生成SSH密钥。2025年了,推荐直接上ed25519:
ssh-keygen -t ed25519 -C "you@example.com"一路回车生成密钥,然后把~/.ssh/id_ed25519.pub里的内容粘贴到Gitea后台的SSH密钥管理页面。之后clone、push、pull就都不需要输密码了。
日常开发中,很多人习惯直接用IDE自带的Git插件提交代码,比如IDEA和VS Code。IDEA里配置Git时,只需要在Settings -> Version Control -> Git中指定git可执行文件的路径,然后把仓库地址通过SSH方式clone下来,剩下的操作都在图形界面里完成。VS Code则可以通过安装GitLens之类的插件增强代码历史和评审的查看体验。如果你在Windows上习惯了右键小乌龟式的操作,TortoiseGit也可以正常使用,但要注意它默认的SSH客户端是TortoiseGitPlink,需要把SSH客户端切换为OpenSSH,否则密钥又要重配一遍。
另外不要忽视分支保护和团队协作规则。在Gitea项目的Settings -> Branches里,可以设置受保护分支,比如main分支禁止直接push,所有变更必须通过Pull Request流程并经过指定成员审核后才能合入。这种机制实现起来不过几行配置,但对团队代码质量的提升是立竿见影的。
4. 自建Git后必踩的坑与排查技巧
自建Git服务看着简单,实际跑起来之后,总会碰到这样那样的奇怪问题。我把自己踩过和帮别人排查过的高频问题整理一下,按出现概率从高到低列出来,你能少走很多弯路。
4.1 SSH连接与认证问题
最典型的问题是Host key verification failed。这个一般出现在服务器重装系统或者重建容器之后,客户端的known_hosts里还保留着旧的服务器指纹。解决方法很简单,在客户端执行:
ssh-keygen -R git.example.com清掉旧指纹,下次连接时重新确认信任即可。我第一次踩到的时候还以为被中间人攻击了,后来才发现只是换过一台机器。
还有一个高频问题是Permission denied (publickey)。对着日志排查了半天,最后发现是公钥没粘贴完整。.pub文件里是一整行的文本,从ssh-ed25519开始到邮箱结尾,复制的时候漏了一截,或者多了换行,都会导致认证失败。检查一下Gitea后台显示的密钥,再对照本地公钥文件,确保完全一致。
4.2 push和clone过程异常
很多新手在执行Git命令时会看到fatal: not a git repository (or any of the parent directories): .git。这个不是Git服务端的问题,是你在错误的目录下执行命令了。Git去寻找仓库目录是从当前目录向上查找.git文件夹的,如果当前目录本身不是仓库,父目录里也没有仓库,就会报这个错。解决方式就是cd到正确的仓库目录,或者先执行git init初始化再操作。
还有一个更隐蔽的问题是,当你在IDE里提交代码时报login failed. check api token or gitlab version. log in via git...。如果你用的是GitLab,这个报错一般是Personal Access Token失效、过期,或者API地址填错了。去用户设置里重新生成一个Token,确认勾选了api和read_repository权限,再检查一下IDE中填写的GitLab地址是否以/api/v4结尾。很多第三方工具和脚本都会踩这个坑,不是服务器没搭好,纯粹是Token权限对不上。
大文件push不上去也是老生常谈。每次有人问我“Git仓库越来越大有啥办法”,我都会先摇头:Git本身就不是设计来存大文件的,几百MB的二进制包塞进Git仓库,仓库会急剧膨胀,clone慢、push慢、占用磁盘,谁都受不了。正确解法是用Git LFS(Large File Storage)。Gitea和GitLab的都原生支持LFS,客户端只需要:
git lfs install git lfs track "*.psd" "*.zip" "*.tar.gz" git add .gitattributes之后这些类型的文件会走LFS存储,普通开发者几乎感觉不到差别,但仓库的Git体积能小一个数量级。
4.3 备份恢复与服务维护
备份恢复了也是许多自建团队容易忽略的点。Gitea的dump文件拿到之后,恢复流程大致是:把容器停掉,把/data目录备份出来,解压dump包覆盖回去,再执行docker compose up -d启动。注意在恢复之前一定要先停服务,否则数据库文件正在被写入,恢复出来的数据可能是损坏的。
服务也需要定期升级。Gitea的升级相对省心,Docker镜像更新只要改一下image标签再重新创建容器。但千万不要在升级前不做备份,我相信不是每个人都经历过“升级失败后回滚,却发现数据库还停留在中间状态”的那种痛苦。我的惯例是:升级前必做一次dump,哪怕只是从1.22升到1.23这种小版本。
4.4 权限模型与误操作防范
权限模型是团队使用中最容易“野蛮生长”的部分。Gitea的组织权限模型包含所有者、管理员、写权限、读权限几种角色,仓库可以继承组织的权限,也可以单独设置协作者权限。我建议从一开始就给团队建立清晰的规则:主分支受保护,release分支一般只有维护者能推,个人开发分支随便折腾。
人的误操作永远比系统故障多。我见过有人因为一时手误,强制推送覆盖了main分支,导致团队一上午的工作全部丢失。这个问题的直接对策就是开启分支保护,在Settings -> Branches里勾选“禁止强制推送”和“需要Pull Request审批”。这个配置太重要了,一个人在五个人以上的团队里,这个选项就是保命符。
5. 选型建议:不同场景下的最终判断
一个方案好不好,从来不取决于它本身的功能列表有多长,而取决于它适不适合你当前的处境。最后这部分我直接给结论,你可以对号入座。
5.1 给个人开发者
如果你只是一个人用,偶尔有几个协作者,服务器配置也不高,那么闭眼选Gitea或者Forgejo就行。数据库直接用内置的SQLite,不需要额外起MySQL,一个容器就能跑起来。内存占用小,功耗低,放在家里的NAS上都毫无压力。为了获得更好的备份习惯,建议拿到域名配置HTTPS,然后把备份脚本挂上cron,每周自动dump一次传一份到云端。个人用的话,CI/CD不是必须的,先不加。
5.2 给小团队
2到20人的团队,我会优先推荐Forgejo或Gitea搭配MySQL,用Caddy做HTTPS反向代理,SSH走非标端口。同时把LFS打开,把分支保护规则建立起来。如果团队有轻量CI/CD需求,Gitea Actions已经可以覆盖大部分场景,不需要单独再起一套Jenkins之类的东西。整体维护成本比较低,一个同事在部署时花半天就能搞定,之后基本不用太操心。
5.3 给中大型组织和DevOps完整需求
团队到了几十人以上,对权限划分、审计日志、多环境CI/CD、制品管理都有明确要求的时候,GitLab CE会全面一些。它的一体化能力特别出色,GitLab CI可以做到从代码提交到测试、构建、部署的端到端追踪,这是分散组合Gitea加外部CI工具很难比拟的。代价就是你需要给它配上足够的内存、磁盘和运维精力。我建议用官方Omnibus包或者Docker镜像安装,千万不要手动编译安装GitLab,那是自寻烦恼。
5.4 给代码评审驱动的团队
如果你的团队对代码评审的要求高于一切,比如合规要求每一行变更都必须经过指定级别的评审和记录,Gerrit依然是那个无情的评审机器。但你要评估团队能不能接受它的工作流。实在不愿意折腾,用GitLab CE的合并请求审批功能,也能实现类似的流程,只是没有Gerrit那么极致。
最后再说一个我自己反复使用的判断方法:先用Docker在本机或者一台临时服务器上把候选方案跑起来,把团队一两个真实仓库推上去,让核心成员实际用两周,再决定上不上生产。真正的适配,亲身体验胜过任何参数对比。
我个人在实际操作中的体会是:自建Git这件事,工具只是最表层的一环。真正决定体验的,是你能不能把HTTPS、SSH、备份、权限、分支保护这套配套体系一起做对。方案选得好,能让你省心;方案选得不对,再强大的功能也只是浪费你的服务器和心情。2025年了,Git自建早就不是什么高门槛的事,它真正考验的是一个团队的工程素养和执行细节。希望这篇对比和实操能帮你找到合适的答案。