1. Git 和 GitLab 到底解决的是什么事——先搞清楚定位再动手
先纠正一个搜索时特别常见的问题:很多人把 GitLab 拼成 gitlib,在搜索引擎和公司群里反复问“gitlib 怎么装”。其实你找的是 GitLab,少一个 a 是另一个完全不相关的东西。Git 和 GitLab 的组合,本质上是给团队一套“代码托管 + 版本控制 + 协作评审”的基础设施。Git 管的是你本地代码的每一次变更记录,GitLab 管的是这些变更如何被集中存储、审查、合并、发布。
很多刚接触团队协作的开发者,最大的误区是把 Git 当成网盘一样用:每天git add .、git commit、git push,以为把代码推到远端就完事了。实际上企业级 Git 协作的核心不是“推送代码”,而是“控制代码如何进入主干”。谁有权限合并、代码合入前要经过什么检查、发布分支如何保护、历史提交如何回溯,这些才是 GitLab 这类平台真正解决的问题。
这篇文章适合谁?两类人。一类是刚负责搭建研发基础设施的运维或技术负责人,需要在一台服务器上把 GitLab 跑起来并设计协作规范;另一类是团队里还没系统用过 Git 的开发者,想搞明白从安装配置到日常提交、解决冲突、走代码评审的完整链路。下面所有步骤都是我实际部署和日常使用中验证过的,不搞那种“装了能跑就行”的糊弄做法。
2. Git 客户端安装与环境配置:三平台通用姿势
Git 本身只是个命令行工具,但不同操作系统安装方式差别很大,而且安装过程中有几个选项会直接影响后面所有操作,必须一开始就选对。
2.1 Windows 下装 Git 最容易忽视的两个选项
Windows 用户大部分会去官网下载 exe 安装包,一路 Next 装完。但这里有两个选择直接影响后续体验。
第一个是默认编辑器。旧版 Git for Windows 默认用 Vim 作为提交信息的编辑器,很多人在git commit时误入 Vim 界面出不来了。安装过程中建议直接选 Notepad++ 或者 VS Code,也可以装完之后用命令改:
git config --global core.editor "code --wait"第二个是“调整 PATH 环境变量”那一步,必须选择中间项 “Git from the command line and also from 3rd-party software”。如果选了默认的第一项,Git 只能在 Git Bash 里用,在 PowerShell 或 VS Code 终端里敲git会直接提示无法识别。
装完验证版本,同时确认环境变量已经生效:
git --version which git注意:如果
git --version正常但which git找不到,说明 PATH 配置有问题,重新执行安装程序修复即可,手动改系统环境变量的方式反而容易出错。
2.2 macOS 与 Linux 的安装方式差异
macOS 上有两种路径。装了 Homebrew 的直接brew install git,这是最省事的方式,会自动处理依赖。不建议去官网下载 pkg 安装包,因为 macOS 自带 xcode command line tools 里就已经集成了一个 Git,直接下载 pkg 容易造成版本冲突,运行git -v时可能是旧版。
Linux 端更简单,用发行版自带的包管理器即可:
# Ubuntu/Debian sudo apt update && sudo apt install -y git # CentOS/RHEL sudo yum install -y git装完先配置全局身份信息,这一步不做,后面每次提交都会报错或者提交到错误的人名下:
git config --global user.name "Your Name" git config --global user.email "your.email@company.com" git config --global init.defaultBranch main最后一行init.defaultBranch main是近几年比较重要的一个配置,把默认分支从 master 改为 main,新初始化的仓库不会因为分支名产生歧义。
2.3 生成 SSH 密钥并完成免密登录
用 HTTPS 方式连接 GitLab 需要每次输入账号密码,虽然可以配置 credential helper 缓存,但企业环境里经常因为密码策略强制过期,导致每天上午都要重新登录一次。SSH 密钥是团队协作里最推荐的认证方式,一次配置,长期使用。
生成密钥并添加到 GitLab 后台:
ssh-keygen -t ed25519 -C "your.email@company.com"连续回车使用默认路径~/.ssh/id_ed25519。企业内网有特殊安全要求、不支持 ed25519 算法的环境,改用 RSA:
ssh-keygen -t rsa -b 4096 -C "your.email@company.com"查看公钥内容:
cat ~/.ssh/id_ed25519.pub把输出内容完整复制,粘贴到 GitLab 的 “Preferences -> SSH Keys” 页面。验证是否成功:
ssh -T git@gitlab.example.com第一次连接会出现 host key 确认提示,输入yes回车即可。如果返回类似Welcome to GitLab, @username!的信息,说明免密登录已经生效。
3. GitLab 服务端部署全流程
GitLab 的部署方式比绝大多数人想象的简单,它提供了 Omnibus 一体化安装包,把 Ruby、PostgreSQL、Redis、Nginx 等所有依赖打包在一起。单机环境下不需要自己单独安装数据库和 Web 服务器,这也是企业内网快速搭建代码托管平台的首选方案。
3.1 部署方式怎么选:源码包、Omnibus 还是 Docker
先明确一点:除非你们团队有专职的 GitLab 二次开发需求,否则永远不要选择源码安装。源码方式需要手动配置十几个组件,每次升级都要处理依赖兼容问题,出了问题排查成本极高。
Omnibus 包是官方推荐的标准方式,适合绝大多数生产环境。它的优势在于升级简单、配置统一、目录结构固定。
Docker 部署适合资源有限的测试环境或者想快速验证的场景。一条命令就能启动一个实例,但生产环境需要额外处理数据卷持久化、容器重启策略、以及后续升级时的数据迁移问题。
我的建议:企业正式环境直接用 Omnibus 安装包,测试环境可以用 Docker,不要一开始就在 K8s 上折腾 GitLab Operator,那是大团队才需要的能力。
3.2 单机部署 GitLab 的完整步骤
以 Ubuntu 20.04/22.04 + GitLab CE 为例,先安装依赖:
sudo apt update sudo apt install -y curl openssh-server ca-certificates postfix这里 postfix 是发邮件用的,如果不装,GitLab 也可以运行,但注册确认邮件、密码找回、合并请求通知都会失效。企业内网没有邮件服务器的话,postfix 可以选择仅本地投递或者完全不配,后续在 GitLab 配置里关掉相关功能即可。
下载并安装 GitLab CE 软件源和安装包:
curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash sudo EXTERNAL_URL="http://gitlab.example.com" apt install gitlab-ceEXTERNAL_URL是初始化时最重要的参数,它决定了 GitLab 生成的仓库地址、页面内嵌链接以及后续 CI/CD 的 webhook 地址。如果没有独立域名,可以直接设为http://<服务器IP>,比如http://192.168.1.100。域名或者 IP 写错,后面再改需要额外执行 reconfigure,比较麻烦。
安装完成后,GitLab 会自动执行初始化,输出一排带勾的检查项。看到gitlab Reconfigured!就说明安装成功。
访问http://gitlab.example.com,第一次打开会要求设置 root 用户的初始密码。设置完成后登录,一个可用的 GitLab 实例就上线了。
如果是 CentOS/RHEL 系统,命令略有差异:
sudo yum install -y curl policycoreutils openssh-server openssh-clients postfix curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash sudo EXTERNAL_URL="http://gitlab.example.com" yum install -y gitlab-ce3.3 初始化配置:域名、邮箱、管理员账号
安装完成之后,有几个配置项必须第一时间检查。
修改/etc/gitlab/gitlab.rb里的关键配置:
# 外部访问地址,部署时已设置则无需重复修改 external_url 'http://gitlab.example.com' # 时区,默认是 UTC,不修改会导致提交记录时间显示相差 8 小时 gitlab_rails['time_zone'] = 'Asia/Shanghai' # 关闭用户自助注册,防止外部人员随意创建账号 gitlab_rails['gitlab_signup_enabled'] = false # 限制创建项目权限,仅允许 Maintainer 以上角色创建 gitlab_rails['gitlab_default_can_create_group'] = false每次修改完 gitlab.rb,必须执行重配置才能生效:
sudo gitlab-ctl reconfigure常用运维命令需要记一下:
# 查看所有组件状态 sudo gitlab-ctl status # 重启全部组件 sudo gitlab-ctl restart # 查看 GitLab 主日志 sudo gitlab-ctl tail注意:
gitlab-ctl reconfigure不等于restart。它不只是重启服务,还会重新生成所有配置文件、执行数据库迁移、刷新 Nginx 配置。修改 gitlab.rb 之后必须用 reconfigure,直接 restart 是不会加载新配置的。
4. 企业级团队协作的标准流程设计
GitLab 装好只是开始,真正决定团队协作效率的是流程设计。没有流程的 GitLab 就是一个带 Web 界面的网盘,代码照样乱套。
4.1 分支模型的选择:Trunk-based 还是 Git Flow
分支模型直接决定团队日常开发节奏。Git Flow 是最广为人知的一套模型,有 master、develop、feature、release、hotfix 五种分支,流程严谨但偏重,适合版本发布周期比较长的传统团队。Trunk-based 则是主干开发,所有开发者直接在主干或短命特性分支上工作,配合 CI 和特性开关控制发布,适合迭代节奏快的互联网团队。
我的建议:大部分企业团队从 Git Flow 裁减后开始,保留主干分支和特性分支即可,不需要一开始就完整上五分支模型。先约定以下规则:
main分支是唯一可发布的分支,受保护,任何人不能直接推代码- 开发从
main拉出feature/xxx分支,功能完成后通过 Merge Request 合入 - 修复紧急线上问题从
main拉hotfix/xxx分支,修复后同时合入main和当前开发分支
这套简化模型已经覆盖了 80% 企业的实际需求,不要再为“理论完整性”增加流程负担。
4.2 权限体系与代码评审规则
GitLab 的角色权限从低到高分为 Guest、Reporter、Developer、Maintainer、Owner 五级。企业协作里,普通开发者分配 Developer,技术负责人分配 Maintainer,只有极少数人拥有 Owner 权限。这个分配不是越严越好,但有一类权限必须收拢:合并权限。
在 GitLab 项目设置的 “Settings -> Repository -> Protected branches” 里,把main设置为受保护分支,并做两项配置:
- “Allowed to merge”:Maintainer
- “Allowed to push”:No one(禁止直接推送代码)
这样设置之后,所有向 main 分支的代码变更都必须通过 Merge Request 完成,Developer 角色的成员只能把自己的分支推送远端,然后提起 MR,由 Maintainer 或指定评审人审查后合入。
代码评审规则建议这样定:每个 MR 至少 1 名评审人通过才能合并,涉及数据库迁移或核心支付逻辑的 MR 必须 2 人评审。这些规则可以在 GitLab 的 “Merge request approval rules” 里直接配置,强制生效。
4.3 一套可直接抄走的 MR 流转规范
很多团队卡在“不知道 MR 描述怎么写”。我提供一个可以直接复制改写的 MR 模板:
## 背景 这个变更要解决什么问题?(简述业务背景,不要只写"修复 bug") ## 变更内容 - 修改了哪些文件/模块 - 新增了哪些功能点 ## 测试验证 - 本地执行了哪些测试用例 - 联调环境验证结果 ## 关联信息 - 关联 Issue/需求编号 - 是否需要同步更新文档MR 标题的格式建议统一为type(scope): description,例如:
feat(auth): 新增 LDAP 登录支持 fix(order): 修复订单金额精度丢失问题 refactor(api): 重构用户信息查询接口这个格式来自 Conventional Commits 规范,好处有二:一是 MR 列表一眼能看出变更类型,二是配合 GitLab 的自动生成 changelog 功能,提交规范直接转化为版本发布记录。
5. 高频协作场景的命令实战
流程定好了,接下来是日常开发中最常用的命令组合。我把团队协作里高频出现的场景分成三类,每一类都给出最稳妥的操作路径。
5.1 从零拉取一个项目:clone、branch、checkout
新成员加入团队,拿到 GitLab 上的项目地址后,第一步克隆代码:
git clone git@gitlab.example.com:group/project.git克隆完成进入项目目录,先看当前分支和远端分支情况:
git branch -a开发新功能前,先确认本地 main 分支是最新的,然后基于最新的 main 拉取特性分支:
git checkout main git pull origin main git checkout -b feature/user-login这里有个细节:git pull等同于git fetch && git merge。如果远端 main 有更新而本地 main 落后,直接基于旧的本地 main 拉分支,后面合并时大概率产生冲突。正确顺序永远是先拉取,再拉分支。
5.2 日常提交流程:add、commit、push、MR
代码写完后,查看变更状态:
git status git diff确认无误后暂存改动并提交。这里强烈建议不要使用git add .无脑添加所有文件,只添加本次改动相关的文件:
git add src/controller/user.go git add src/service/user.go git commit -m "feat(user): 增加用户登录接口"如果中间有多个文件的改动打散在多次 commit 里,在推到远端之前可以用rebase合并提交记录:
git rebase -i HEAD~3把前面几个 commit 的指令改为squash(或简写s),合并成一个语义清晰的提交。这一步的价值在于:推送到远端的提交历史是给团队其他人看的,应该是一个完整的功能或修复,而不是“改了第一次”“改了第二次”这种流水账。
推送并创建 MR:
git push origin feature/user-login推送后会返回一个 GitLab 地址,打开地址填写 MR 描述即可发起代码评审。
5.3 冲突处理:从发现问题到解决验证
多人开发同一文件时,合并冲突是最常见的问题。发生冲突时,Git 会在冲突文件里标记:
<<<<<<< HEAD 当前分支的内容 ======= 合并进来的内容 >>>>>>> feature/other-branch需要手工把两个版本的代码调整为想要的结果,删除冲突标记。这一步的难点不在操作,而在“怎么判断保留哪部分”。我的经验是:冲突解决不是选 A 还是选 B,而是要理解双方改动的意图,必要时要和对方确认。如果同一段逻辑两个人都在改,解决冲突最好的办法是拉上对方视频通话对着屏幕看,而不是自己埋头猜。
解决完冲突后按常规流程暂存并提交:
git add src/controller/user.go git commit -m "merge: 合并 feature/user-login 到 main" git push注意:如果使用的是
git merge,冲突解决后需要额外一次 commit;如果使用的是git rebase,冲突解决后执行git rebase --continue。这两种方式的解决命令不一样,先确认自己当前处在 merge 还是 rebase 状态,别急着 commit。
6. 我踩过的高频坑与排查思路
这章记录几个我在企业环境里反复看到的故障,也是 GitLab 协作中最影响效率的问题。每一条都给到完整的排查链路,不是只给结论。
6.1 "fatal: not a git repository" 这类路径问题
新人在项目根目录外执行 Git 命令,最容易遇到这个报错:
fatal: not a git repository (or any of the parent directories): .git这个报错的原因很直接:当前目录不是 Git 仓库,或者不在任何 Git 仓库的子目录中。排查顺序:
- 执行
pwd确认当前目录是否正确 - 执行
ls -la查看是否存在.git目录 - 如果
.git目录存在但依然报错,检查环境变量GIT_DIR是否被设置,执行env | grep GIT_DIR
还有一个容易忽略的情况:仓库本身在/home/user/project,但你使用sudo执行 Git 命令时,HOME 环境变量变成了/root,Git 会去/root下面找仓库路径。遇到这个情况,不要用sudo git,改用普通用户权限执行。
Windows 环境下还有一个特殊问题:.git目录因为权限或杀毒软件被锁定,导致仓库读取为不完整。排查时在项目根目录执行git config --local --list,如果提示error: cannot open .git/config,用文件管理器检查.git目录读取权限。
6.2 GitLab 登录失败与 API Token 校验问题
GitLab 相关的疑难杂症里,最典型的是 Web IDE 或外部工具调用 API 时报错:
Login failed. check api token or gitlab version. log in via git if the version is lower than 5.0这个报错通常不是密码错误,而是 API Token 无效或者 GitLab 版本不满足工具的最低要求。排查步骤:
- 确认 GitLab 版本,登录管理员账号进入 “Admin Area -> Overview”,查看版本号
- 在 “User Settings -> Access Tokens” 页面重新生成一个新 token,权限勾选
api和read_repository - 检查外部工具(比如 IDE 插件、CI 脚本)引用的 token 环境变量是否被正确注入
- 确认 token 的过期时间,GitLab 支持为 token 设置有效期,设置过短会频繁失效
还有一个安全相关的默认行为:如果管理员在/etc/gitlab/gitlab.rb中开启了gitlab_rails['gitlab_signup_enabled'] = false,那么新用户只能由管理员在后台手动创建。如果团队成员反映“注册不了账号”,先检查这个开关。
6.3 大文件入库导致的仓库膨胀
团队里总有同事习惯把编译产物、静态资源包、数据库备份文件直接提交到 Git 仓库。Git 保存的是所有历史版本,某个文件哪怕后来删除了,它的历史记录仍然保留在.git目录里,仓库会越来越大,最终导致git clone和git fetch极慢。
排查仓库大小和占空间最多的文件:
# 查看仓库占用空间 git count-objects -vH # 找出历史记录中体积最大的文件 git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | awk '/^blob/ {print $3, $4}' | sort -rn | head -10如果已经有大文件被提交进历史,单纯的删除文件并提交新 commit 并不能让仓库变小,必须重写历史。常规方案是使用 git filter-repo:
# 删除路径中包含 output/ 的所有历史记录 git filter-repo --path output/ --invert-paths # 清理并回收空间 git reflog expire --expire=now --all git gc --prune=now --aggressive注意:
git filter-repo会重写所有提交哈希,执行完成后所有成员都需要重新克隆代码库,本地旧分支直接作废。这种操作一定要在这个项目只有你一个人改、或者已经和所有人确认过之后再做。
团队规范层面,最好的防御是在 GitLab 后台开启推送限制:“Settings -> Push rules” 里设置禁止提交超过指定大小的文件,超过直接拦截,从根源上杜绝问题。
6.4 commit 信息写错了怎么办:amend 的边界
git commit --amend是修正最近一次提交信息的命令,但它有一个容易被忽略的副作用:amend 会生成一个全新的提交对象,旧的提交记录被替换。如果这个提交已经推送到远端,amend 之后远端会拒绝普通 push,必须强制推送。
场景区分:
- commit 尚未推送,直接 amend 没有副作用,推荐使用
- commit 已经推送但只有你一个人在改这个分支,amend 后使用
git push --force-with-lease强制推送
关键是要慎用git push --force,这个命令会无条件覆盖远端记录。而--force-with-lease会在推送前检查远端是否有人推送了新提交,如果有,推送会被拒绝,防止覆盖别人的工作。团队协作中建议只使用后者,禁止裸用--force。
至于 amend 只能修改最近一条提交,如果你要修改的内容跨了多个提交,需要用git rebase -i选择对应的提交后执行reword选项。
另外提一个容易踩的坑:amend 不只是改提交信息,如果你执行 amend 时工作区里还有新改动没提交,这些改动也会被打包进被 amend 的提交里,导致一次提交里混进不相关的变更。所以执行 amend 前先看git status,确认工作区是干净的。
7. 关于规范化协作的几点延伸建议
GitLab 安装完成、团队流程跑起来之后,还有几个点值得花时间做,它们会让整个协作体验再上一个档次。
第一个是开启 MR 流水线校验。GitLab CI/CD 可以在 MR 创建和更新时自动跑测试、静态检查、构建验证。设置 “Pipeline must succeed” 作为 MR 合并前置条件之后,坏代码根本没有机会合入主干。这部分依赖于你们项目的 CI 配置,但 GitLab 侧只需要在项目设置的 “General merge request settings” 里勾选对应选项即可。
第二个是善用 Group 层级管理。不要每个项目单独设置一遍权限,在 GitLab 里创建一个 Group(例如engineering),把相关项目都归到该 Group 下,然后在 Group 级别配置成员和权限体系。新成员入职时只需要在 Group 里添加一次,项目权限自动继承。
第三个是定期做仓库健康检查。我建议每个月用管理员账号看一次 GitLab 的 “Admin Area -> Overview -> Projects”,留意异常增大的仓库;查看 “Admin Area -> Monitoring -> Background Jobs” 确认后台任务没有堆积。单机部署环境下,磁盘空间被日志和 CI artifact 撑满是最常见的故障原因。
第四个是数据备份。Omnibus 安装的 GitLab 提供了内置备份命令:
sudo gitlab-backup create建议配合 crontab 做每日备份,并将备份文件同步到独立存储或者远端备份服务器。备份文件本身包含所有仓库和数据库数据,务必限制访问权限,不要把它放在一个所有人都能读的目录下。
Git 协作的复杂度不在于命令多寡,而在于规范和习惯。工具只是强制约束的载体,真正让团队协作顺畅的,是每个人都理解为什么要走 MR、为什么要写清晰的提交信息、为什么要保护主干分支。这篇文章的每一步都是围绕“让代码变更可控、可追踪、可回滚”展开的,照着这套流程搭起来,至少能让团队在代码协作层面少吵很多架。