git完整工作流程

Git 多人协作工作流完整指南

本文档面向使用 GitHub 进行多人协作开发的团队,涵盖从仓库初始化到日常开发的完整流程。
以 Qt UI 插件组件库项目为实际背景编写。


一、仓库初始化

1.1 创建远程仓库

在 GitHub 网页上点击右上角 +New repository,填写仓库名称,选择 Private 或 Public,建议勾选 Add a README file,然后点击 Create repository

1.2 克隆仓库到本地

# 将远程仓库克隆到本地(HTTPS 方式)
git clone https://github.com/你的用户名/仓库名.git

# SSH 方式(推荐,免密码)
git clone git@github.com:你的用户名/仓库名.git

# 进入项目目录
cd 仓库名

1.3 本地已有项目关联远程仓库

如果本地已经有项目代码,还没有 Git 仓库:

# 初始化本地 Git 仓库
git init

# 关联远程仓库地址
git remote add origin https://github.com/你的用户名/仓库名.git

# 拉取远程仓库内容(如果远程有 README 等文件)
git pull origin main --allow-unrelated-histories

# 添加所有文件到暂存区
git add .

# 提交
git commit -m "init: 初始化项目结构"

# 推送到远程 main 分支
git push -u origin main

1.4 配置用户信息

# 设置全局用户名和邮箱(所有仓库生效)
git config --global user.name "你的名字"
git config --global user.email "你的邮箱"

# 仅对当前仓库设置(优先级高于全局)
git config user.name "你的名字"
git config user.email "你的邮箱"

# 查看当前配置
git config --list

二、分支管理

2.1 分支模型说明

推荐采用以下分支模型:

分支 用途 谁可以合并 生命周期
main 稳定发布版本 仅管理员通过 PR 永久
develop 开发主线,集成所有功能 通过 PR 合并 永久
feature/xxx 单个功能的开发分支 开发者自己维护 功能完成后删除
bugfix/xxx Bug 修复分支 开发者自己维护 修复完成后删除
release/x.x.x 发布准备分支 管理员维护 发布后删除
hotfix/xxx 紧急修复分支(从 main 拉出) 管理员维护 修复后删除

2.2 创建 develop 分支(项目初始化时执行一次)

# 基于 main 创建 develop 分支
git checkout -b develop

# 推送 develop 到远程
git push -u origin develop

2.3 查看分支

# 查看本地分支(*号标记当前分支)
git branch

# 查看远程分支
git branch -r

# 查看所有分支(本地 + 远程)
git branch -a

# 查看每个分支的最后一次提交
git branch -v

2.4 创建功能分支

# 先切换到 develop 分支
git checkout develop

# 拉取最新的 develop 代码(重要!确保基于最新代码开发)
git pull origin develop

# 创建并切换到新的功能分支
git checkout -b feature/ipinput

# 此时你已经在 feature/ipinput 分支上,可以开始开发

分支命名规范:

feature/ipinput        → 新增 IP 输入组件
feature/switchbtn      → 新增开关按钮组件
bugfix/ipinput-crash   → 修复 IP 输入组件崩溃问题
hotfix/theme-loading   → 紧急修复主题加载失败
release/1.0.0          → 1.0.0 版本发布准备

2.5 切换分支

# 切换到已有分支
git checkout develop

# 切换到远程分支(本地没有但远程有的分支)
git fetch origin
git checkout feature/switchbtn
# Git 会自动创建本地分支并跟踪远程分支

2.6 删除分支

# 删除本地分支(必须先切换到其他分支)
git branch -d feature/ipinput

# 强制删除本地分支(未合并的分支需要强制删除)
git branch -D feature/ipinput

# 删除远程分支
git push origin --delete feature/ipinput

三、日常开发流程

3.1 查看文件状态

# 查看当前工作区状态
git status

# 简洁模式查看状态
git status -s

状态说明:

?? 文件名    → 新文件,未被 Git 追踪
M  文件名    → 已修改,已添加到暂存区
 M 文件名    → 已修改,尚未添加到暂存区
A  文件名    → 新文件,已添加到暂存区
D  文件名    → 文件已删除

3.2 添加文件到暂存区

# 添加单个文件
git add src/widgets/ipinput/ipinput.h

# 添加整个目录
git add src/widgets/ipinput/

# 添加所有修改过的文件
git add .

# 添加所有 .cpp 文件
git add *.cpp

# 交互式选择要添加的内容(可以选择文件中的部分修改)
git add -p

3.3 提交

# 提交(会打开编辑器写提交信息)
git commit

# 直接写提交信息
git commit -m "feat: 完成 IpInput 组件基础框架"

# 添加并提交(仅对已追踪的文件有效,新文件无效)
git commit -am "fix: 修复 IpInput 焦点切换逻辑"

提交信息规范(推荐 Conventional Commits):

feat:     新功能
fix:      Bug 修复
docs:     文档变更
style:    代码格式调整(不影响功能)
refactor: 重构(既不是新功能也不是修复)
test:     测试相关
chore:    构建工具、辅助工具相关变更
perf:     性能优化

示例:

feat: 新增 IpInput 组件,支持 IPv4 地址输入和验证
fix: 修复 SwitchButton 在高 DPI 下绘制偏移的问题
docs: 补充 IpInput 组件使用文档和接口说明
refactor: 将 IpInput 的绘制逻辑抽离到独立方法中
chore: CMakeLists 新增 widgets/ipinput 子目录

3.4 查看提交历史

# 查看提交历史
git log

# 简洁模式(一行一条)
git log --oneline

# 显示分支图
git log --oneline --graph --all

# 查看某个文件的修改历史
git log --oneline -- src/widgets/ipinput/ipinput.cpp

# 查看最近 5 条提交
git log -5 --oneline

3.5 查看差异

# 查看工作区与暂存区的差异(未 add 的修改)
git diff

# 查看暂存区与上次提交的差异(已 add 未 commit 的修改)
git diff --cached

# 查看某个文件的差异
git diff src/widgets/ipinput/ipinput.cpp

# 查看两个分支之间的差异
git diff develop..feature/ipinput

# 查看两个分支之间差异的文件列表
git diff develop..feature/ipinput --name-only

四、推送与拉取

4.1 推送到远程

# 首次推送新分支到远程(-u 建立追踪关系)
git push -u origin feature/ipinput

# 后续推送(已建立追踪关系后)
git push

# 推送指定分支
git push origin feature/ipinput

# 强制推送(rebase 之后需要,慎用!仅用于自己的 feature 分支)
git push --force-with-lease

4.2 拉取远程代码

# 拉取并合并(等于 fetch + merge)
git pull origin develop

# 仅拉取,不合并(推荐先 fetch 再决定如何合并)
git fetch origin

# fetch 之后查看远程分支的更新情况
git log origin/develop --oneline -5

# fetch 之后手动合并
git merge origin/develop

4.3 fetch 与 pull 的区别

git fetch 只是把远程的最新数据下载到本地仓库,但不会改动你的工作区。你可以先看看有什么更新,再决定是否合并。git pull 则是直接下载并合并,等于 fetch + merge 一步到位。建议在不确定远程改了什么的时候,先用 fetch 看一看。


五、合并与变基

5.1 merge(合并)

# 将 feature/ipinput 合并到 develop(本地操作)
git checkout develop
git merge feature/ipinput

# 合并时产生一个合并提交(即使可以快进合并也保留合并记录)
git merge --no-ff feature/ipinput -m "merge: 合并 feature/ipinput 到 develop"

5.2 rebase(变基)

# 在 feature 分支上执行,将自己的提交"搬"到 develop 最新提交之后
git checkout feature/ipinput
git fetch origin
git rebase origin/develop

# 如果有冲突,解决后继续
git add .
git rebase --continue

# 放弃本次 rebase
git rebase --abort

5.3 merge 与 rebase 的选择

场景 推荐方式 理由
将 develop 最新代码同步到 feature 分支 rebase 保持线性历史,提交记录干净
将 feature 分支合并到 develop merge --no-ff 保留合并记录,可追溯
多人共同开发同一个 feature 分支 merge rebase 会改写历史,影响他人

核心原则:只对自己的本地分支使用 rebase,不要对已经推送到远程且有他人使用的分支执行 rebase。

5.4 解决冲突

冲突发生时,Git 会在文件中标记冲突区域:

<<<<<<< HEAD
// 当前分支的代码
void IpInput::init() {
    setMaxLength(15);
}
=======
// 要合并进来的分支的代码
void IpInput::init() {
    setMaxLength(15);
    setPlaceholderText("0.0.0.0");
}
>>>>>>> feature/ipinput

解决步骤:

# 1. 打开冲突文件,手动编辑,保留正确的代码,删除冲突标记

# 2. 编辑完成后,将解决好的文件添加到暂存区
git add src/widgets/ipinput/ipinput.cpp

# 3a. 如果是 merge 冲突,执行提交
git commit -m "merge: 解决 ipinput 合并冲突"

# 3b. 如果是 rebase 冲突,执行继续
git rebase --continue

六、Pull Request 工作流(核心)

6.1 什么是 Pull Request

Pull Request(简称 PR)是一种代码合并请求机制。开发者不直接将代码推送到 develop 或 main 分支,而是先推送到自己的 feature 分支,然后在 GitHub 上发起一个请求,由团队成员审核代码后再执行合并。

6.2 为什么必须使用 PR

直接 push 到 develop 的做法存在以下问题:

  • 没有人审核代码,质量无法保证
  • 出了问题难以追溯是谁合并的、为什么合并的
  • 无法利用 CI 自动检查编译和测试
  • 无法在合并前讨论方案
  • 多人同时操作 develop 容易互相覆盖

6.3 完整的 PR 流程(以开发 IpInput 组件为例)

第一步:创建分支并开发

# 切换到 develop,确保是最新的
git checkout develop
git pull origin develop

# 创建功能分支
git checkout -b feature/ipinput

# --- 开发代码 ---

# 查看改动
git status
git diff

# 暂存并提交(可以有多次提交)
git add .
git commit -m "feat: 实现 IpInput 组件基础框架"

# 继续开发...
git add .
git commit -m "feat: IpInput 添加输入验证和焦点切换逻辑"

# 继续开发...
git add .
git commit -m "docs: 补充 IpInput 组件使用说明"

第二步:推送到远程

# 推送功能分支到远程仓库
git push -u origin feature/ipinput

第三步:在 GitHub 上创建 Pull Request

  1. 打开 GitHub 仓库页面,你会看到一个黄色横幅提示"feature/ipinput had recent pushes",点击旁边的 Compare & pull request 按钮
  2. 如果没有看到横幅,点击顶部的 Pull requests 选项卡,再点击右上角绿色的 New pull request 按钮
  3. 设置合并方向:
    • base: develop(目标分支,代码要合并到哪里)
    • compare: feature/ipinput(源分支,你的代码从哪来)
  4. 填写 PR 信息:
    • Title: feat: 新增 IpInput 组件
    • Description: 描述你做了什么、为什么这样做、如何测试的
  5. 在右侧面板设置:
    • Reviewers: 选择审核人
    • Assignees: 选择负责人(通常是自己)
    • Labels: 选择标签(如 enhancementwidget
    • Milestone: 如果有版本规划,选择对应的里程碑
  6. 点击 Create pull request

第四步:代码审核(Code Review)

审核人在 PR 页面的 Files changed 选项卡中查看代码差异,可以对某一行代码点击 + 号添加评论,审核完成后选择以下操作之一:

  • Approve:审核通过,可以合并
  • Request changes:需要修改,打回给开发者
  • Comment:仅评论,不做审核决定

第五步:根据审核意见修改(如果有)

# 在本地 feature/ipinput 分支上修改代码
git checkout feature/ipinput

# 修改代码...

# 提交修改
git add .
git commit -m "fix: 根据审核意见修复 IpInput 输入验证逻辑"

# 推送更新(PR 会自动更新,不需要重新创建 PR)
git push

第六步:合并 PR

审核通过后,在 PR 页面底部点击绿色的 Merge pull request 按钮。GitHub 提供三种合并方式:

方式 说明 适用场景
Create a merge commit 保留所有提交,创建一个合并提交 默认选择,适合大多数场景
Squash and merge 将所有提交压缩为一条,再合并 适合提交很琐碎的情况
Rebase and merge 将提交逐个变基到目标分支上 适合追求线性历史

推荐团队统一使用 Squash and merge,这样 develop 分支的每条提交记录对应一个完整的功能,历史清晰。

第七步:合并后清理

# 切换回 develop
git checkout develop

# 拉取合并后的最新代码
git pull origin develop

# 删除本地功能分支
git branch -d feature/ipinput

# 删除远程功能分支(GitHub 合并时可以勾选自动删除)
git push origin --delete feature/ipinput

6.4 两人并行开发的完整时间线

以 A 开发 feature/ipinput、B 开发 feature/switchbtn 为例:

时间线:

1. A 和 B 各自从 develop 创建分支
   A: git checkout -b feature/ipinput
   B: git checkout -b feature/switchbtn

2. A 和 B 各自开发,互不影响

3. A 先完成,推送并创建 PR
   A: git push -u origin feature/ipinput
   A: 在 GitHub 上创建 PR → develop

4. 团队审核 A 的 PR,审核通过后合并
   此时 develop 已包含 A 的代码

5. B 完成开发,推送前先同步 develop 的最新代码
   B: git fetch origin
   B: git rebase origin/develop
   (如果有冲突,B 在本地解决)
   B: git push -u origin feature/switchbtn

6. B 在 GitHub 上创建 PR → develop
   此时 PR 显示无冲突,可以直接审核合并

7. 团队审核 B 的 PR,审核通过后合并

关键点:谁后合并谁负责同步最新的 develop 并解决冲突。


七、撤销与回退

7.1 撤销工作区的修改(还没有 add)

# 撤销单个文件的修改,恢复到最后一次提交的状态
git checkout -- src/widgets/ipinput/ipinput.cpp

# 撤销所有文件的修改
git checkout -- .

7.2 撤销暂存(已经 add 但还没有 commit)

# 将文件从暂存区移出,但保留工作区的修改
git reset HEAD src/widgets/ipinput/ipinput.cpp

# 撤销所有暂存
git reset HEAD .

7.3 修改最后一次提交

# 修改最后一次提交的信息
git commit --amend -m "feat: 修正提交信息"

# 追加文件到最后一次提交(不改提交信息)
git add 忘记添加的文件.cpp
git commit --amend --no-edit

注意:如果这次提交已经推送到远程,amend 之后需要 force push,仅限自己的 feature 分支使用。

7.4 回退提交

# 回退到某个提交,保留工作区的修改(soft 模式)
git reset --soft HEAD~1

# 回退到某个提交,保留工作区但清除暂存区(mixed 模式,默认)
git reset HEAD~1

# 回退到某个提交,丢弃所有修改(hard 模式,危险!)
git reset --hard HEAD~1

# 回退到指定的提交哈希
git reset --hard abc1234

7.5 安全回退(生成一个新的"撤销"提交)

# 撤销某次提交的内容,但不改变历史(适合已推送到远程的分支)
git revert abc1234

# 撤销最近一次提交
git revert HEAD

revertreset 的区别:reset 是直接删除提交历史,revert 是新建一个提交来抵消之前的改动。对于已经推送到远程的代码,应该用 revert 而不是 reset


八、暂存工作区(stash)

当你正在 feature/ipinput 上开发到一半,突然需要切换到其他分支处理紧急问题时:

# 暂存当前所有未提交的修改
git stash

# 暂存时附带说明信息
git stash save "ipinput: 输入验证逻辑写了一半"

# 查看暂存列表
git stash list

# 现在可以安全切换分支
git checkout develop

# --- 处理完紧急问题后 ---

# 切换回原来的分支
git checkout feature/ipinput

# 恢复暂存的修改(恢复并从暂存列表中删除)
git stash pop

# 恢复暂存的修改(恢复但保留在暂存列表中)
git stash apply

# 恢复指定的暂存
git stash apply stash@{1}

# 删除某个暂存
git stash drop stash@{0}

# 清空所有暂存
git stash clear

九、标签管理(Tag)

标签用于标记版本发布点。

# 创建轻量标签
git tag v1.0.0

# 创建附注标签(推荐,包含更多信息)
git tag -a v1.0.0 -m "release: 组件库 1.0.0 版本发布"

# 给历史提交打标签
git tag -a v0.9.0 abc1234 -m "release: 0.9.0 预览版"

# 查看所有标签
git tag

# 查看标签详细信息
git show v1.0.0

# 推送单个标签到远程
git push origin v1.0.0

# 推送所有标签到远程
git push origin --tags

# 删除本地标签
git tag -d v1.0.0

# 删除远程标签
git push origin --delete v1.0.0

十、.gitignore 配置

在项目根目录创建 .gitignore 文件,告诉 Git 哪些文件不需要跟踪。

Qt/C++ 项目推荐配置:

# 编译输出
build/
cmake-build-*/
out/
*.o
*.obj
*.exe
*.dll
*.so
*.dylib
*.a
*.lib
moc_*
ui_*
qrc_*

# Qt Creator 生成文件
*.pro.user
*.pro.user.*
*.qbs.user
*.qbs.user.*
*.moc
*.qmlc
*.jsc

# IDE 配置
.idea/
.vscode/
*.swp
*.swo
*~

# 系统文件
.DS_Store
Thumbs.db

# CMake 生成文件
CMakeFiles/
CMakeCache.txt
cmake_install.cmake
Makefile
compile_commands.json
# 如果某些文件已经被追踪了,添加到 .gitignore 后需要先清除缓存
git rm -r --cached build/
git commit -m "chore: 清除 build 目录的 Git 追踪"

十一、实用技巧

11.1 查看某一行代码是谁写的

git blame src/widgets/ipinput/ipinput.cpp

11.2 搜索提交历史

# 按提交信息搜索
git log --grep="IpInput"

# 按作者搜索
git log --author="张三"

# 按时间范围搜索
git log --after="2025-01-01" --before="2025-03-01"

11.3 查看某次提交改了什么

# 查看某次提交的详细改动
git show abc1234

# 只看改了哪些文件
git show abc1234 --name-only

11.4 cherry-pick(摘取某个提交)

# 将某个分支上的某次提交应用到当前分支
git cherry-pick abc1234

适用场景:在 feature/ipinput 上修了一个通用 Bug,想把这个修复单独应用到 develop 上。

11.5 清理未追踪的文件

# 查看哪些文件会被清理(预览)
git clean -n

# 清理未追踪的文件
git clean -f

# 清理未追踪的文件和目录
git clean -fd

十二、分支保护设置(管理员操作)

在 GitHub 仓库的 SettingsBranches 中,为 maindevelop 添加保护规则:

推荐配置:

选项 说明 建议
Require a pull request before merging 禁止直接 push,必须走 PR 必须开启
Require approvals PR 必须获得审核通过才能合并 建议至少 1 人
Require status checks to pass CI 检查通过才能合并 建议开启
Require branches to be up to date 合并前必须同步最新代码 建议开启
Do not allow bypassing the above settings 管理员也不能绕过 视情况而定

十三、常见问题处理

13.1 推送被拒绝(远程有新提交)

# 错误信息:! [rejected] ... (non-fast-forward)

# 解决方法一:先拉取再推送
git pull --rebase origin feature/ipinput
git push

# 解决方法二:先 fetch 再 rebase
git fetch origin
git rebase origin/feature/ipinput
git push

13.2 误删分支恢复

# 查看最近的操作记录
git reflog

# 找到删除前的提交哈希,重新创建分支
git checkout -b feature/ipinput abc1234

13.3 合并错了想撤销

# 如果还没有推送,撤销合并
git reset --hard HEAD~1

# 如果已经推送,使用 revert
git revert -m 1 合并提交的哈希

13.4 commit 了不该提交的文件

# 从 Git 追踪中移除,但保留本地文件
git rm --cached 不该提交的文件.txt
git commit -m "chore: 移除误提交的文件"

十四、推荐的日常开发节奏

每天开始工作:
  1. git checkout develop
  2. git pull origin develop
  3. git checkout feature/我的功能分支
  4. git rebase develop(同步最新代码)

开发过程中:
  5. 小步提交,每完成一个小功能点就 commit
  6. 提交信息写清楚改了什么

开发完成时:
  7. git fetch origin
  8. git rebase origin/develop(最后同步一次)
  9. 解决冲突(如果有)
  10. git push -u origin feature/我的功能分支
  11. 在 GitHub 上创建 Pull Request
  12. 等待审核,根据反馈修改
  13. 合并后删除 feature 分支

十五、常用命令速查表

操作 命令
克隆仓库 git clone <url>
查看状态 git status
添加文件 git add <file>
提交 git commit -m "message"
推送 git push
拉取 git pull
创建并切换分支 git checkout -b <branch>
切换分支 git checkout <branch>
查看分支 git branch -a
删除本地分支 git branch -d <branch>
删除远程分支 git push origin --delete <branch>
合并分支 git merge <branch>
变基 git rebase <branch>
暂存工作区 git stash
恢复暂存 git stash pop
查看日志 git log --oneline --graph
查看差异 git diff
撤销工作区修改 git checkout -- <file>
撤销暂存 git reset HEAD <file>
回退提交 git reset --hard HEAD~1
安全回退 git revert <commit>
打标签 git tag -a v1.0.0 -m "message"
摘取提交 git cherry-pick <commit>
posted @ 2026-03-30 10:42  m晴朗  阅读(1)  评论(0)    收藏  举报