返回笔记首页

Git 工作流设计 - 深度剖析

主题配置

简历项目经验描述

版本1 - 适合初中级

plain
参与团队 Git 工作流规范制定,提升代码管理效率
- 采用 GitFlow 分支管理策略,规范开发、测试、发布流程
- 制定 Commit 提交规范,使用 commitizen 工具,代码提交质量提升 60%
- 配置 Husky 钩子,实现提交前代码检查,避免低级错误 80%+

版本2 - 适合高级

plain
设计并推行团队 Git 工作流体系,显著提升协作效率
- 建立 GitFlow + Trunk-Based 混合分支策略,适配敏捷开发节奏,发布周期缩短 50%
- 搭建 Commit 规范 + Changelog 自动生成系统,版本文档生成效率提升 10 倍
- 实施 MR/PR 强制评审机制,引入 Code Review 标准,线上 Bug 率降低 40%
- 开发冲突自动检测工具,提前识别合并冲突,解决冲突时间减少 70%

版本3 - 适合架构方向

plain
主导 Git 工作流架构设计,建立标准化的代码协作体系
- 设计多环境分支策略,支持开发/测试/预发/生产四环境,部署准确率 99%+
- 建立 Git Hooks + CI/CD 联动机制,自动化检查覆盖率达 90%,人工介入减少 80%
- 制定代码评审标准和流程,培训 Code Review 最佳实践,团队代码质量评分提升 35%
- 优化大仓库 Git 性能,通过浅克隆、稀疏检出等技术,克隆时间从 30 分钟降至 3 分钟

面试标准回答话术

Q1: GitFlow 分支管理是什么?你们是怎么用的?

标准回答

"GitFlow 是一种 Git 分支管理模型,通过不同的分支承载不同的职责,让团队协作更规范。

基本分支
  1. master/main 分支 - 生产环境代码,只能从 release 或 hotfix 合并
  2. develop 分支 - 开发分支,集成所有开发完成的功能
  3. feature 分支 - 功能开发分支,从 develop 切出,完成后合并回 develop
  4. release 分支 - 发布分支,从 develop 切出,测试通过后合并到 master 和 develop
  5. hotfix 分支 - 紧急修复分支,从 master 切出,修复后合并到 master 和 develop
我们团队的实际用法
日常开发流程
bash
# 1. 从 develop 切出功能分支
git checkout develop
git pull origin develop
git checkout -b feature/user-login

# 2. 开发功能,提交代码
git add .
git commit -m "feat: 实现用户登录功能"

# 3. 推送到远程
git push origin feature/user-login

# 4. 在 GitLab/GitHub 创建 MR/PR
# 5. Code Review 通过后,合并到 develop
# 6. 删除功能分支
git branch -d feature/user-login
发布流程
bash
# 1. 从 develop 切出 release 分支
git checkout develop
git pull origin develop
git checkout -b release/v1.2.0

# 2. 在 release 分支上做发布准备(修改版本号、更新 changelog 等)
npm version 1.2.0
git add .
git commit -m "chore: 发布 v1.2.0"

# 3. 测试通过后,合并到 master
git checkout master
git pull origin master
git merge --no-ff release/v1.2.0
git tag -a v1.2.0 -m "Release v1.2.0"
git push origin master --tags

# 4. 同时合并回 develop
git checkout develop
git merge --no-ff release/v1.2.0
git push origin develop

# 5. 删除 release 分支
git branch -d release/v1.2.0
紧急修复流程
bash
# 1. 从 master 切出 hotfix 分支
git checkout master
git pull origin master
git checkout -b hotfix/fix-login-bug

# 2. 修复 bug
git add .
git commit -m "fix: 修复登录时的空指针问题"

# 3. 合并到 master
git checkout master
git merge --no-ff hotfix/fix-login-bug
git tag -a v1.2.1 -m "Hotfix v1.2.1"
git push origin master --tags

# 4. 合并到 develop
git checkout develop
git merge --no-ff hotfix/fix-login-bug
git push origin develop

# 5. 删除 hotfix 分支
git branch -d hotfix/fix-login-bug
分支命名规范
plain
feature/功能名称    例如: feature/user-profile
bugfix/问题描述     例如: bugfix/fix-login-error
hotfix/问题描述     例如: hotfix/fix-payment-bug
release/版本号      例如: release/v1.2.0
我们还做了一些优化
  1. 小团队简化 - 如果团队小(3-5人),可以去掉 release 分支,直接从 develop 合并到 master
  2. 结合 CI/CD - 每个分支推送后自动触发 CI 流程,跑测试和构建
  3. 保护分支 - master 和 develop 设置为保护分支,只能通过 MR 合并,不能直接 push

这套流程在我们 10 人团队里用了 2 年,很稳定,代码管理很清晰。"

Q2: Commit 规范是什么?怎么保证团队遵守?

标准回答

"Commit 规范就是统一提交信息的格式,让提交历史清晰易读。我们用的是 Angular 规范。

Commit 格式
plain
<type>(<scope>): <subject>

<body>

<footer>
type(必须)
  • feat: 新功能
  • fix: 修复 bug
  • docs: 文档更新
  • style: 代码格式(不影响代码运行)
  • refactor: 重构(既不是新功能,也不是修 bug)
  • perf: 性能优化
  • test: 测试相关
  • chore: 构建过程或辅助工具的变动

scope(可选): 影响的范围,如: user, product, order

subject(必须): 简短描述

例子
bash
feat(user): 添加用户注册功能

实现了用户注册的完整流程:
- 表单验证
- 邮箱验证
- 密码加密

Closes #123
如何保证团队遵守?
1. 使用 commitizen 工具

安装:

bash
npm install -g commitizen
npm install cz-conventional-changelog --save-dev

配置 package.json:

json
{
  "config": {
    "commitizen": {
      "path": "cz-conventional-changelog"
    }
  },
  "scripts": {
    "commit": "git-cz"
  }
}

使用:

bash
# 不用 git commit,改用
npm run commit

# 会出现交互式提示
? Select the type of change: (Use arrow keys)
> feat:     A new feature
  fix:      A bug fix
  docs:     Documentation only changes
  style:    Changes that do not affect the meaning of the code
  refactor: A code change that neither fixes a bug nor adds a feature
  perf:     A code change that improves performance
  test:     Adding missing tests

? What is the scope of this change (e.g. component or file name): user
? Write a short description: 添加用户注册功能
? Provide a longer description: (press enter to skip)
? Are there any breaking changes? No
? Does this change affect any open issues? Yes
? Add issue references: #123
2. 使用 commitlint 检查

安装:

bash
npm install --save-dev @commitlint/cli @commitlint/config-conventional

配置 commitlint.config.js:

javascript
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      [
        'feat',
        'fix',
        'docs',
        'style',
        'refactor',
        'perf',
        'test',
        'chore',
        'revert'
      ]
    ],
    'subject-case': [0], // 不限制 subject 大小写
    'subject-max-length': [2, 'always', 100] // subject 最长 100 字符
  }
}
3. 使用 Husky 钩子

安装:

bash
npm install --save-dev husky
npx husky install

添加 commit-msg 钩子:

bash
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit $1'

现在提交不规范的 commit 会被拦截:

bash
git commit -m "随便写的"

# 报错
⧗   input: 随便写的
✖   subject may not be empty [subject-empty]
✖   type may not be empty [type-empty]

✖   found 2 problems, 0 warnings
4. 自动生成 Changelog

安装:

bash
npm install --save-dev standard-version

配置 package.json:

json
{
  "scripts": {
    "release": "standard-version"
  }
}

生成 changelog:

bash
npm run release

# 会自动:
# 1. 根据 commit 生成 CHANGELOG.md
# 2. 更新版本号
# 3. 创建 git tag

CHANGELOG.md 示例:

markdown
# Changelog

## [1.2.0] - 2024-01-15

### Features

- **user**: 添加用户注册功能 (#123)
- **product**: 支持产品批量导入 (#124)

### Bug Fixes

- **login**: 修复登录时的空指针问题 (#125)

### Performance Improvements

- **list**: 优化列表加载性能,提升 50% (#126)
完整的提交流程
bash
# 1. 修改代码
vim src/user.js

# 2. 添加到暂存区
git add src/user.js

# 3. 使用规范的 commit
npm run commit

# 4. 推送
git push

# 5. 发版时生成 changelog
npm run release

我们团队实施这套规范后,提交历史清晰了很多,发版文档也不用手写了,自动生成就行。"

Q3: MR/PR 评审机制是怎么做的?

标准回答

"MR (Merge Request) 或 PR (Pull Request) 评审就是代码合并前,让其他同事 review 一下,保证代码质量。

我们的评审流程
1. 提交 MR/PR

开发完成后,在 GitLab/GitHub 创建 MR:

bash
# 推送功能分支
git push origin feature/user-login

# 在 GitLab 页面创建 MR
# 填写以下信息:
# - 标题: feat(user): 添加用户登录功能
# - 描述: 实现了用户登录的完整流程
# - 指派给: @reviewer
# - 标签: feature, frontend

MR 描述模板:

markdown
## 改动内容
实现了用户登录功能,包括:
- 登录表单
- 密码加密
- Session 管理

## 相关 Issue
Closes #123

## 测试说明
1. 访问 /login 页面
2. 输入用户名密码
3. 点击登录,验证是否跳转到首页

## 截图
![登录页面](screenshot.png)

## Checklist
- [x] 代码通过 ESLint 检查
- [x] 添加了单元测试
- [x] 更新了文档
2. 自动检查

MR 创建后,自动触发 CI 流程:

yaml
# .gitlab-ci.yml
stages:
  - lint
  - test
  - build

lint:
  stage: lint
  script:
    - npm run lint
  only:
    - merge_requests

test:
  stage: test
  script:
    - npm run test
  coverage: '/Statements\s+:\s+(\d+\.\d+)%/'
  only:
    - merge_requests

build:
  stage: build
  script:
    - npm run build
  only:
    - merge_requests

检查内容:

  • 代码规范(ESLint)
  • 单元测试(Jest)
  • 测试覆盖率(至少 80%)
  • 构建是否成功
3. Code Review

Reviewer 检查代码,提出意见:

检查清单:

markdown
## 功能
- [ ] 功能是否完整?
- [ ] 是否有边界情况考虑不周?
- [ ] 是否有性能问题?

## 代码质量
- [ ] 代码是否易读易懂?
- [ ] 命名是否规范?
- [ ] 是否有重复代码?
- [ ] 是否有 TODO 或 FIXME?

## 测试
- [ ] 是否有单元测试?
- [ ] 测试覆盖率是否足够?
- [ ] 测试用例是否完整?

## 文档
- [ ] 是否更新了相关文档?
- [ ] 复杂逻辑是否有注释?

评论示例:

plain
Line 25: 这里建议用 async/await 代替 Promise.then,代码更清晰

Line 45: 这个魔法数字 10000 建议提取为常量

Line 60: 这个 if 条件太复杂,建议抽取为单独的函数

整体看下来代码质量不错,就这几个小问题,改完就可以合并了。
4. 修改和再次评审

开发者根据意见修改代码:

bash
# 修改代码
vim src/user.js

# 提交修改
git add .
git commit -m "fix: 根据 review 意见优化代码"
git push origin feature/user-login

# MR 自动更新,CI 重新跑
5. 合并

评审通过后,合并到目标分支:

bash
# 在 GitLab 页面点击 "Merge" 按钮
# 或使用命令行
git checkout develop
git merge --no-ff feature/user-login
git push origin develop

# 删除功能分支
git push origin --delete feature/user-login
评审标准

我们团队的标准:

  • 至少 1 人 approve 才能合并
  • 关键模块(支付、权限)至少 2 人 approve
  • CI 必须全部通过
  • 测试覆盖率不能降低
评审工具

除了 GitLab/GitHub 自带的,我们还用:

  • SonarQube: 自动代码质量分析
  • Danger: 自动评论常见问题
  • CodeClimate: 代码可维护性评分
评审效率优化
  1. 小而频繁的 MR - 每个 MR 改动不超过 500 行,容易 review
  2. 及时响应 - 规定 MR 创建后 2 小时内要有人 review
  3. 结对编程 - 复杂功能提前和 reviewer 沟通,减少返工
  4. 知识分享 - 每周分享 review 中发现的典型问题

通过这套机制,我们团队的代码质量提升了很多,线上 bug 明显减少。"

Q4: 代码冲突怎么解决?有什么预防措施?

标准回答

"代码冲突就是两个人改了同一个地方,Git 不知道该保留谁的,需要手动解决。

常见冲突场景
  1. 同时修改同一文件的同一位置
  2. 一个人修改文件,另一个人删除文件
  3. 文件名冲突(一个人重命名,另一个人也在改这个文件)
解决方法
场景1: 合并分支时冲突
bash
git checkout develop
git merge feature/user-login

# 提示冲突
Auto-merging src/user.js
CONFLICT (content): Merge conflict in src/user.js
Automatic merge failed; fix conflicts and then commit the result.

# 查看冲突文件
git status

# 打开冲突文件
vim src/user.js

冲突标记:

javascript
<<<<<<< HEAD
function login(username, password) {
  // develop 分支的代码
  return api.login({ username, password })
}
=======
function login(user, pass) {
  // feature 分支的代码
  return api.userLogin({ user, pass })
}
>>>>>>> feature/user-login

手动解决:

javascript
// 保留正确的代码,删除冲突标记
function login(username, password) {
  return api.login({ username, password })
}

提交解决:

bash
git add src/user.js
git commit -m "merge: 解决 user.js 冲突"
git push origin develop
场景2: Rebase 时冲突
bash
git checkout feature/user-login
git rebase develop

# 提示冲突
CONFLICT (content): Merge conflict in src/user.js

# 解决冲突后
git add src/user.js
git rebase --continue

# 如果有多个冲突,会继续提示,重复解决
# 如果想放弃 rebase
git rebase --abort
场景3: Pull 时冲突
bash
git pull origin develop

# 提示冲突
CONFLICT (content): Merge conflict in src/user.js

# 解决后提交
git add src/user.js
git commit -m "merge: 解决冲突"
git push origin develop
冲突解决工具
  1. VS Code - 内置冲突解决工具,可视化很友好
plain
显示:
Accept Current Change | Accept Incoming Change | Accept Both Changes
  1. GitKraken - 图形化工具,三方对比
  2. 命令行工具:
bash
# 使用 vimdiff
git mergetool --tool=vimdiff

# 使用 meld
git mergetool --tool=meld
预防冲突的措施
1. 频繁同步
bash
# 每天开始工作前,先同步 develop
git checkout develop
git pull origin develop

# 再合并到自己的分支
git checkout feature/user-login
git merge develop
2. 小步提交

不要攒了一周的代码一次提交,每天多次提交,减少冲突概率。

3. 功能拆分

大功能拆成小功能,多个分支并行,互不影响。

4. 沟通协作

如果知道要改同一个文件,提前沟通,约定谁先改。

5. 代码格式统一

使用 Prettier 统一代码格式,避免格式差异导致的冲突:

bash
npm install --save-dev prettier

# .prettierrc
{
  "semi": false,
  "singleQuote": true,
  "trailingComma": "es5"
}

# 格式化代码
npx prettier --write "src/**/*.{js,vue}"
6. 文件锁定(特殊场景)

对于一些不能冲突的文件(如配置文件),可以用 Git LFS 锁定:

bash
git lfs track "config.json"
git lfs lock config.json

# 修改后解锁
git lfs unlock config.json
自动检测冲突

我们写了个脚本,在 MR 创建时自动检测潜在冲突:

javascript
// scripts/check-conflicts.js
const { execSync } = require('child_process')

function checkConflicts(sourceBranch, targetBranch) {
  try {
    // 尝试模拟合并
    execSync(`git fetch origin ${targetBranch}`)
    execSync(`git merge-tree $(git merge-base ${sourceBranch} origin/${targetBranch}) ${sourceBranch} origin/${targetBranch}`)

    console.log('✓ 没有冲突')
    return true
  } catch (error) {
    console.error('✗ 检测到潜在冲突:')
    console.error(error.stdout.toString())
    return false
  }
}

checkConflicts('feature/user-login', 'develop')

在 GitLab CI 中运行:

yaml
check-conflicts:
  stage: check
  script:
    - node scripts/check-conflicts.js
  only:
    - merge_requests

通过这些措施,我们团队的冲突率降低了 70%,即使有冲突,也能快速解决。"


核心难点与解决方案

难点1: 大型仓库的 Git 性能优化

问题描述: 项目越来越大,Git 操作越来越慢。clone 仓库要 30 分钟,pull 要 5 分钟,严重影响开发效率。

解决方案

"大型仓库的性能问题主要是历史提交太多、二进制文件太大。我做了几个优化:

优化1: 浅克隆(Shallow Clone)

只克隆最近的提交,不要完整历史:

bash
# 只克隆最近 1 次提交
git clone --depth 1 https://github.com/user/repo.git

# 只克隆某个分支
git clone --depth 1 --branch develop https://github.com/user/repo.git

# 后续需要历史时,再拉取
git fetch --unshallow

效果:

  • 完整克隆: 30 分钟,5GB
  • 浅克隆: 3 分钟,500MB
优化2: 稀疏检出(Sparse Checkout)

只检出需要的文件夹:

bash
git clone --filter=blob:none --sparse https://github.com/user/repo.git
cd repo

# 设置稀疏模式
git sparse-checkout init --cone

# 只检出 src 目录
git sparse-checkout set src

# 后续添加更多目录
git sparse-checkout add docs
优化3: Git LFS (大文件存储)

把大文件(图片、视频、设计稿)放到 LFS:

bash
# 安装 Git LFS
git lfs install

# 跟踪大文件
git lfs track "*.psd"
git lfs track "*.mp4"
git lfs track "design/**"

# 提交 .gitattributes
git add .gitattributes
git commit -m "chore: 配置 Git LFS"

LFS 的好处:

  • 大文件不存在 Git 历史里,只存指针
  • Clone 时只下载指针,按需下载大文件
  • 仓库体积减小 90%+
优化4: 清理历史大文件

如果仓库里已经有大文件,需要清理:

bash
# 找出大文件
git rev-list --objects --all | \
  git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
  sed -n 's/^blob //p' | \
  sort --numeric-sort --key=2 | \
  tail -20

# 使用 BFG 清理
brew install bfg  # macOS
# 或下载 https://rtyley.github.io/bfg-repo-cleaner/

# 删除大于 10MB 的文件
bfg --strip-blobs-bigger-than 10M repo.git

# 清理和垃圾回收
cd repo.git
git reflog expire --expire=now --all
git gc --prune=now --aggressive
优化5: Git 配置调优
bash
# 启用文件系统缓存
git config core.fscache true

# 启用 preload 索引
git config core.preloadindex true

# 增加压缩级别
git config core.compression 9

# 启用并行处理
git config pack.threads 0

# 增加 pack 文件大小
git config pack.packSizeLimit 2g
优化6: Monorepo 工具

如果项目特别大,考虑用 Monorepo 工具:

bash
# 使用 git-worktree 分离工作目录
git worktree add ../repo-feature feature/new-feature

# 或使用 sparse-index
git config index.sparse true
效果对比

优化前:

  • Clone: 30 分钟
  • Pull: 5 分钟
  • Checkout: 2 分钟
  • 仓库大小: 5GB

优化后:

  • Clone: 3 分钟
  • Pull: 30 秒
  • Checkout: 10 秒
  • 仓库大小: 500MB

团队反馈开发体验好了很多,不用等半天才能开始工作了。"

难点2: 多人协作的分支管理策略

问题描述: 团队有 20 个人,每天都有新功能和 bug 修复,分支太多太乱,经常不知道哪个分支是干什么的。

解决方案

"我们制定了详细的分支管理策略和自动化工具:

策略1: 分支命名规范
bash
# 功能分支
feature/用户名-功能描述
例: feature/zhangsan-user-login

# Bug 修复
bugfix/用户名-问题描述
例: bugfix/lisi-fix-login-error

# 紧急修复
hotfix/问题描述
例: hotfix/fix-payment-crash

# 发布分支
release/版本号
例: release/v1.2.0

# 测试分支
test/测试环境
例: test/qa-env
策略2: 分支生命周期管理

自动清理过期分支:

bash
# scripts/clean-branches.sh
#!/bin/bash

# 删除已合并的本地分支
git branch --merged | grep -v "\*\|master\|develop" | xargs -n 1 git branch -d

# 删除远程已删除的本地跟踪分支
git fetch --prune

# 删除 30 天前的远程分支(排除保护分支)
git for-each-ref --format '%(refname:short) %(committerdate:raw)' refs/remotes/origin | \
  while read branch date timestamp; do
    if [ $(($(date +%s) - $timestamp)) -gt 2592000 ]; then
      # 跳过保护分支
      if [[ ! $branch =~ (master|develop|release/) ]]; then
        echo "删除过期分支: $branch"
        git push origin --delete ${branch#origin/}
      fi
    fi
  done

定时运行:

yaml
# .gitlab-ci.yml
clean-branches:
  stage: cleanup
  script:
    - bash scripts/clean-branches.sh
  only:
    - schedules
  when: manual
策略3: 分支保护规则

GitLab 设置:

yaml
# master 分支保护
Protected branches:
  - master
    - Allowed to merge: Maintainers
    - Allowed to push: No one
    - Require approval: 2 approvals
    - Require passing pipeline

# develop 分支保护
  - develop
    - Allowed to merge: Developers
    - Allowed to push: No one
    - Require approval: 1 approval
    - Require passing pipeline
策略4: 分支关联 Issue

每个分支都要关联 Issue:

bash
# 从 Issue 创建分支
# Issue #123: 实现用户登录功能

git checkout -b feature/zhangsan-123-user-login

# 提交时关联 Issue
git commit -m "feat: 实现用户登录 #123"

# MR 描述中关联
Closes #123

好处:

  • 可追溯:知道每个分支是为了解决什么问题
  • 自动关闭:MR 合并后自动关闭 Issue
  • 统计方便:可以统计每个人的工作量
策略5: 分支可视化

用 GitKraken 或在线工具查看分支图:

bash
# 命令行查看分支图
git log --graph --oneline --all

# 更美观的输出
git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --all

配置别名:

bash
git config --global alias.tree "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --all"

# 使用
git tree
策略6: 分支权限管理

不同角色的权限:

plain
实习生: 只能创建 feature 分支,不能合并
初级: 可以合并到 develop,不能合并到 master
中级: 可以创建 release 分支
高级: 可以合并到 master,可以创建 hotfix

通过这套策略,20 人团队的分支管理井井有条,很少出现混乱。"

难点3: CI/CD 与 Git Hooks 的深度集成

问题描述: 代码提交前没有检查,经常提交有问题的代码,导致 CI 失败,浪费时间。

解决方案

"我们建立了完整的 Git Hooks + CI/CD 联动体系:

本地 Hooks (Husky)
bash
npm install --save-dev husky lint-staged

# 初始化
npx husky install

# 添加到 package.json
npm set-script prepare "husky install"
pre-commit: 提交前检查
bash
npx husky add .husky/pre-commit "npx lint-staged"
javascript
// package.json
{
  "lint-staged": {
    "*.{js,vue}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{css,scss}": [
      "stylelint --fix",
      "prettier --write"
    ],
    "*.md": [
      "markdownlint --fix",
      "prettier --write"
    ]
  }
}
commit-msg: 提交信息检查
bash
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit $1'
pre-push: 推送前检查
bash
npx husky add .husky/pre-push "npm run test"
javascript
// .husky/pre-push
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

# 运行测试
npm run test

# 检查是否有未解决的冲突标记
if git diff --cached --name-only | xargs grep -l "<<<<<<< HEAD" 2>/dev/null; then
  echo "Error: 发现未解决的冲突标记"
  exit 1
fi

# 检查是否有 TODO
if git diff --cached --name-only | xargs grep -l "TODO" 2>/dev/null; then
  echo "Warning: 发现 TODO 标记,确认要推送吗? (y/n)"
  read answer
  if [ "$answer" != "y" ]; then
    exit 1
  fi
fi
服务端 Hooks

在 GitLab 服务器上配置:

bash
# /var/opt/gitlab/git-data/repositories/project.git/hooks/pre-receive
#!/bin/bash

# 检查提交大小
while read oldrev newrev refname; do
  # 获取推送的文件
  files=$(git diff --name-only $oldrev $newrev)

  # 检查单个文件大小
  for file in $files; do
    size=$(git cat-file -s $newrev:$file 2>/dev/null)

    if [ "$size" -gt 10485760 ]; then  # 10MB
      echo "Error: 文件 $file 大小超过 10MB"
      exit 1
    fi
  done
done
GitLab CI 配置
yaml
# .gitlab-ci.yml
stages:
  - pre-check
  - lint
  - test
  - build
  - deploy

variables:
  NODE_VERSION: "18"

# 缓存
cache:
  paths:
    - node_modules/

# 安装依赖
before_script:
  - npm install

# 代码规范检查
lint:
  stage: lint
  script:
    - npm run lint
  only:
    - merge_requests
    - develop
    - master

# 单元测试
test:
  stage: test
  script:
    - npm run test
  coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml
  only:
    - merge_requests
    - develop
    - master

# 构建
build:
  stage: build
  script:
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 week
  only:
    - develop
    - master
    - /^release\/.*$/

# 部署到测试环境
deploy:test:
  stage: deploy
  script:
    - npm run deploy:test
  environment:
    name: test
    url: https://test.example.com
  only:
    - develop
  when: manual

# 部署到生产环境
deploy:prod:
  stage: deploy
  script:
    - npm run deploy:prod
  environment:
    name: production
    url: https://example.com
  only:
    - master
  when: manual
  needs:
    - build
自动化流程图
plain
开发者提交代码
    ↓
pre-commit hook (格式化代码)
    ↓
commit-msg hook (检查提交信息)
    ↓
pre-push hook (运行测试)
    ↓
推送到 GitLab
    ↓
GitLab CI 开始运行
    ↓
Lint (代码规范检查)
    ↓
Test (单元测试)
    ↓
Build (构建)
    ↓
Deploy (部署) - 手动触发
效果
  • 本地就能发现 90% 的问题
  • CI 失败率从 30% 降到 5%
  • 代码质量显著提升

这套体系让我们团队的代码质量上了一个台阶。"


完整技术实现

1. 项目初始化脚本

bash
# scripts/init-git-workflow.sh
#!/bin/bash

echo "🚀 初始化 Git 工作流..."

# 1. 安装依赖
echo "📦 安装依赖..."
npm install --save-dev \
  husky \
  lint-staged \
  @commitlint/cli \
  @commitlint/config-conventional \
  commitizen \
  cz-conventional-changelog \
  standard-version

# 2. 初始化 Husky
echo "🐶 配置 Husky..."
npx husky install
npm set-script prepare "husky install"

# 3. 添加 Git Hooks
npx husky add .husky/pre-commit "npx lint-staged"
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit $1'
npx husky add .husky/pre-push "npm run test"

# 4. 创建配置文件
echo "📝 创建配置文件..."

# commitlint.config.js
cat > commitlint.config.js << 'EOF'
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      [
        'feat',
        'fix',
        'docs',
        'style',
        'refactor',
        'perf',
        'test',
        'chore',
        'revert'
      ]
    ],
    'subject-max-length': [2, 'always', 100]
  }
}
EOF

# 5. 配置 package.json
echo "⚙️  配置 package.json..."
npm set-script commit "git-cz"
npm set-script release "standard-version"

# 添加 lint-staged 配置
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
pkg['lint-staged'] = {
  '*.{js,vue}': ['eslint --fix', 'prettier --write'],
  '*.{css,scss}': ['stylelint --fix', 'prettier --write']
};
pkg.config = {
  commitizen: {
    path: 'cz-conventional-changelog'
  }
};
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));
"

# 6. 创建分支管理脚本
mkdir -p scripts

cat > scripts/clean-branches.sh << 'EOF'
#!/bin/bash

echo "🧹 清理已合并的分支..."
git branch --merged | grep -v "\*\|master\|develop" | xargs -n 1 git branch -d

echo "🔄 更新远程分支信息..."
git fetch --prune

echo "✅ 完成!"
EOF

chmod +x scripts/clean-branches.sh

echo "✨ Git 工作流初始化完成!"
echo ""
echo "使用方法:"
echo "  npm run commit  - 规范化提交"
echo "  npm run release - 生成 changelog 并发布"
echo "  bash scripts/clean-branches.sh - 清理分支"

2. MR 模板

markdown
<!-- .gitlab/merge_request_templates/Default.md -->
## 改动类型
<!-- 勾选适用的类型 -->
- [ ] 新功能 (feat)
- [ ] Bug 修复 (fix)
- [ ] 性能优化 (perf)
- [ ] 代码重构 (refactor)
- [ ] 文档更新 (docs)
- [ ] 其他

## 改动内容
<!-- 详细描述这次改动 -->


## 相关 Issue
<!-- 如果有相关 Issue,请关联 -->
Closes #

## 测试说明
<!-- 如何测试这次改动 -->
1.
2.
3.

## 截图/录屏
<!-- 如果是 UI 改动,请提供截图或录屏 -->


## Checklist
- [ ] 代码通过 ESLint 检查
- [ ] 添加了必要的单元测试
- [ ] 测试覆盖率不低于 80%
- [ ] 更新了相关文档
- [ ] 本地测试通过
- [ ] 没有遗留 console.log 或 debugger
- [ ] 没有遗留 TODO 或 FIXME

## 额外说明
<!-- 其他需要说明的内容 -->

3. Changelog 生成配置

javascript
// .versionrc.js
module.exports = {
  types: [
    { type: 'feat', section: '✨ Features' },
    { type: 'fix', section: '🐛 Bug Fixes' },
    { type: 'perf', section: '⚡ Performance' },
    { type: 'refactor', section: '♻️ Refactor' },
    { type: 'docs', section: '📝 Documentation' },
    { type: 'style', section: '💄 Styles' },
    { type: 'test', section: '✅ Tests' },
    { type: 'chore', hidden: true }
  ],

  // 跳过的提交类型
  skip: {
    bump: true,
    changelog: true,
    commit: true,
    tag: true
  },

  // Changelog 文件路径
  infile: 'CHANGELOG.md',

  // 首次生成时的版本
  firstRelease: false,

  // 提交消息格式
  commitUrlFormat: '{{host}}/{{owner}}/{{repository}}/commit/{{hash}}',
  compareUrlFormat: '{{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}',
  issueUrlFormat: '{{host}}/{{owner}}/{{repository}}/issues/{{id}}',

  // 自定义更新文件
  bumpFiles: [
    {
      filename: 'package.json',
      type: 'json'
    },
    {
      filename: 'package-lock.json',
      type: 'json'
    }
  ]
}

面试常见追问

Q: 如何处理紧急上线和常规开发并行?

"我们用双轨制:

正常功能走 develop -> release -> master

紧急修复走 master -> hotfix -> master + develop

bash
# 紧急修复流程
git checkout master
git pull
git checkout -b hotfix/urgent-fix

# 修复后合并到 master
git checkout master
git merge hotfix/urgent-fix
git tag v1.2.1

# 同时合并到 develop
git checkout develop
git merge hotfix/urgent-fix
```"

### Q: 如何回滚已发布的版本?

"有几种方案:

#### 方案1: Revert
```bash
# 撤销某次提交
git revert <commit-hash>
git push

方案2: Reset(慎用)

bash
# 回退到某个版本
git reset --hard <commit-hash>
git push --force
方案3: 重新部署旧版本
bash
# 切换到旧 tag
git checkout v1.2.0
npm run build
npm run deploy

我们一般用方案1,保留历史记录。"

Q: 大文件误提交了怎么办?

"用 BFG 清理:

bash
# 克隆裸仓库
git clone --mirror https://github.com/user/repo.git

# 删除大文件
bfg --delete-files *.mp4 repo.git

# 清理
cd repo.git
git reflog expire --expire=now --all
git gc --prune=now --aggressive

# 推送
git push

注意:这会改写历史,需要团队协调。"


项目经验总结

踩过的坑

  1. force push 覆盖他人代码 - 禁用 force push,改用 force-with-lease
  2. merge 和 rebase 混用 - 统一用 merge,保留完整历史
  3. 大文件提交 - 没配置 Git LFS,导致仓库巨大
  4. 提交信息随意 - 实施 commitlint 后才规范

性能数据

  • Commit 规范遵守率:95%+
  • MR 平均审查时间:< 2小时
  • CI 失败率:5%(优化前 30%)
  • 代码冲突率:< 10%(优化前 40%)

可以吹的点

  • 建立完整的 Git 工作流体系
  • Commit 规范 + 自动生成 Changelog
  • Git Hooks + CI/CD 深度集成
  • 大仓库性能优化,clone 时间减少 90%
  • 团队代码质量显著提升