本文将分场景详细讲述如何通过 GitHub 实现多人队伍协同开发
下面以一个二人队伍为例(队长 A 和队员 B),多人队伍的话其他队员操作同队员 B
以队长 A 的仓库为基准,首先队员 B Fork 队长 A 的项目仓库,队长 A 和队员 B 的仓库结构如下所示:
队长 A:
┌── master :最终的可上线版本分支
│
└── dev :队长 A 本人开发分支
队员 B:
┌── master :队员 B 经过开发、具有一部分新功能的分支,用于向队长 A 提出 PR
│
└── dev :队员 B 本人开发分支
其中,队长 A 的 master 分支是经过充分测试、最终可以部署上线的版本分支,队员 B 的 master 分支是其本人经过开发,完成了一个子功能或子模块并经过简单测试之后,用于向队长 A 提出 PR(Pull Resquest) 的分支
队伍成员职责如下:
- 队长 A:除分配开发任务、负责开发工作外,更重要的工作是 检查队内成员开发成果,解决合并时的错误,完成项目上线等
- 队员 B:主要负责开发工作
假设仓库初始状态为:
队长 A(主仓):
── master ── project.txt(内容为 "module 1")
队员 B(Fork 主仓):
── master ── project.txt(内容为 "module 1")
场景一:队员与主仓版本保持同步
假设队长 A 经过一轮合并、添加了子模块,并将项目上线为版本 2,此时主仓内容为:
── master ── project.txt(内容为 "module 1, module 2")
由于是以队长 A 的仓库为主仓,所以队员在开发新的功能时,须先拉取当前最新版本,以便保持同步
队员 B clone 自己的远程仓库至本地
git clone https://github.com/member_b/project.git
添加主仓的远程仓库地址
git remote add upstream https://github.com/captain/project.git
查看当前仓库所连接的远程仓库
git remote -v
此时,当前仓库所连接的远程仓库为:
origin https://github.com/member_b/project.git (fetch)
origin https://github.com/member_b/project.git (push)
upstream https://github.com/captain/project.git (fetch)
upstream https://github.com/captain/project.git (push)
拉取主仓文件
git fetch upstream
切换到 master 分支
git checkout master
合并
git merge upstream/master
至此,新版本的项目文件已经更新到了 master 分支,下一步需要将它合并到 dev 分支,以便后续在 dev 分支上开发
如未创建 dev 分支,则创建并切换
git checkout -b dev
合并
git merge master
队员 B 就可以在 dev 分支下工作了
场景二:队员与主仓版本合并
当队员 B 完成了新模块并经过测试 push 到远程仓库的 master 分支后,需向队长 A 提出合并请求,即 Pull Resquest
假设队员 B 向 project.txt
中添加了 “module 3”
队员 B 在自己的 GitHub 仓库中新建 Pull Resquest,如图
选择分支,这里选择向主仓的 dev 分支提出 PR
填写相关信息后,点击「Create Pull Resquest」,队员 B 任务完成
队长 A 在主仓中查看 Pull Resquest,Commits
标签下显示队员 B 的提交记录,Files changed
标签下显示文件内容变动情况
经过检查后就可以选择合并或拒绝合并(即 Close PR)
其中,Merge Pull Resquest 有三个选项
Create a merge commit
:表示把这个 PR 作为一个分支合并,并保留分支上的所有提交记录Squash and merge
:表示只为这次合并保留一个提交记录Rebase and merge
:找到两个分支共同的祖先,然后在当前分支上合并从共同祖先到现在的所有 commit
对比
Create a merge commit
:不能保持 master 分支干净,但是保留了所有的 commit history,当 PR 中 commit 次数较多时不推荐此方式Squash and merge
:也可以保持 master 分支干净,但是 master 中 author 都是 maintainer,而不是原 authorRebase and merge
:可以尽可能保持 master 分支干净整洁,并且易于识别 author
此时,队长 A 的 dev 分支就加入了队员 B 的新模块。随着不断向 dev 分支合并,等到完成一个可上线版本时,队长 A 就可以将 dev 分支合并到 master 分支部署上线了
场景三:合并时出现冲突
出现冲突的情况有很多,比如队员 B 偷懒好几天没工作,当他拉取主仓最新版本文件到 master 分支后,发现其他队友们修改了内容并替他修复了 bug,导致队员 B 在合并时产生冲突
对于合并时产生的冲突,需要手动修改、消除冲突
假设仓库状态如下:
队长 A(主仓):
┌── master ── project.txt(内容为 "module 1, module 2.5, module 3")
│
└── dev ── project.txt(内容为 "module 1, module 2.5, module 3")
队员 B(fetch upstream 前):
┌── master ── project.txt(内容为 "module 1, module 2, module 3")
│
└── dev ── project.txt(内容为 "module 1, module 2, module 3")
当队员 B fetch 后尝试与 master 合并时,产生冲突
使用 VS Code 查看 project.txt
=======
上方的是当前分支的内容,下方的是进行合并的分支要传入的内容。此时,须以主仓版本为准,所以需要手动删除其他内容,或点击「采用传入的更改」,修改为:
module 1, module 2.5, module 3
之后,还需要
git add project.txt
git commit -m "fix conflict"
这时就消除了冲突,再与 dev 分支合并就可以进行后续工作了