4

前言

本文旨在帮助没有接触过Git的同学,使用Git以及GitHub的基本功能,适用于初学者。

由于内容比较多,一次写不完,故做成连载,以后还会更新其它内容。

第一期:Git入门(一)——基本操作及理论
第二期:Git入门(二)——团队开发基本流程概述 (本期)

步骤零:把项目跑起来

分为以下两种情况:全新的项目,中途接手的项目

无论哪种情况,都应该先把GitHub仓库clone到本地,有一个区别就是,全新的项目需要先在GitHub上新建仓库。

//作用:把地址中的在线仓库clone到本地的文件夹中
git clone <仓库地址> <本地的文件夹>

请耐心等它跑完。
在本地拥有了代码之后,就开始跑项目了。

如果是已有的旧项目,接下来就是检查开发环境、数据库、Nginx、redis等等,以确保项目能成功的跑起来。
如果是新项目,仓库中只有一个readme.md,就不需要这一步(但需要额外的一步项目初始化,具体如何初始化,取决于开发使用的编程语言)。

步骤一:把本地仓库调整到工作状态

出于安全起见,一个严谨的团队,必然会制定一些合作开发的规范,比如

  • 不能向主分支直接提交代码
  • 不能由旧分支向新分支发起合并请求

因此,在领取一个任务时,我们本地的仓库可能刚刚完成上一个任务,因此需要进行切回主分支、同步远程仓库的代码、建立新分支等等操作。

假设我们领取了新任务,issue的编号是300,而我们本地仓库还处于上次的275分支上,并且刚刚提交完代码:
image.png

这时候需要先切换回主分支:

// 切换到主分支
git checkout master

image.png

然后把远程主分支同步到本地主分支:
(分支关系: origin/master -> master)

// 拉取远程仓库的代码
git pull

image.png

执行上一步以后,我们本地的代码已经和远程仓库完全一致了。
接下来为新领取的任务创建一个分支:

// 创建新分支
git checkout -b <分支号>

// 示例:创建分支编号为300的新分支
git checkout -b 300

image.png

到此为止,我们既更新了本地的代码为最新版本,又为新领取的任务做好了准备,因为新的issue将在300分支上完成开发,因此,在合并代码之前,不会对master分支产生影响。

接下来就开始写代码了。

步骤二、提交代码

假设现在我的代码已经写完了,在完全保存之后,终端中的分支号是黄色的,黄色表示代码有改动,但尚未提交。

我们可以查看代码变更信息(这一步不是必须的):

// 查看代码状态
git status

image.png

从返回的结果来看,有一个文件是modified状态,这说明:
Git发现了一个文件出现更改,但并没有记录这个更改,因此提示信息是红色的。

那么我们怎么让Git记录这些更改呢?

// 记录当前目前的所有文件变更
// 此命令应该在项目根目录执行
git add .

再git status 就可以看到刚刚显示红色的文件已经变成绿色:
image.png

接下来可以提交代码了(也相当于打一个保存点):

// 在本地提交代码变更,最后是备注信息
git commit -m <备注信息>
// 示例
git commit -m issue300已完成

提交完成后,原本黄色的分支号会重新变成绿色:
image.png

接下来就是把本地的代码提交到远程分支上:
(分支关系 300 -> origin/300)

// 把本地的分支推送到远程仓库
git push origin <分支号>

// 示例:把本地的300分支推送到远程的300分支
git push origin 300

image.png

在提示信息中,可以看到,希望用户访问GitHub来建立Pull Request。
至于GitHub的操作步骤,在第一期中已经讲解,本文专注于讲解Git命令。

附录一 解决冲突

冲突产生原因

只要有代码合并就不可避免的产生冲突,冲突的产生,还是要从分支说起。

刚刚我们提到了一条规范:

  • 不能向主分支直接提交代码

基于这个规范,团队的成员们需要分别在自己的分支上编写,最终依次向主分支发起合并。

在提交代码时,Git会以“行”为单位,记录每一行代码的改动情况,比如,在test分支,把某一行的123改成了456,Git会记录下:
123 -> 456
合并代码时,Git会找到master分支上的123这一行,并且改成456:
123 -> 456

我们先看一种情况:

如果A把123改成了456,B更新了A修改之后的代码,又把它改成了789,
image.png
此时是不会有冲突的,因为B是把456改成了789,而不是把123改成了789。

但下面这种情况就不一样了:

A把123改成了456,并且合并到主分支,但B没有更新A的更改,而是直接把123改成了789,那么,再去合并B的分支时,就会显示冲突

image.png
那么Git到底该听谁的?

因此就需要解决冲突了。
这也就是为什么有了第二个规范:

  • 不能由旧分支向新分支发起合并请求
    在合并代码时,当前的改动必须基于最新的主分支

解决冲突

发生冲突时有两种解决办法,一是在线上修改,二是将冲突代码拉下来,在本地修改。

如果冲突发生在本地,合并代码时会提示conflicts,并且会提示具体哪个文件发生冲突:
image.png
示例中是test.txt文件发生冲突,所以打开文件:
image.png
会出现一排<<<<<<<和一排>>>>>>>,中间夹住的,就是冲突的代码。

图中,当前的代码是789,而300分支的成员想改成456。
解决办法:

  • 将冲突的代码删掉一部分,使程序可以正常运行(比如,在示例中,我打算删掉789)
  • 删掉所有的箭头、=等等
  • 未发生冲突的代码不动
  • 保存文件
  • 重新执行git add .
  • 重新执行git commit -m <备注信息>,把合并的结果提交

最终的效果如下:
image.png
image.png

代码只剩一行“456”,终端中重新显示绿色提示符。

附录二 更新代码

刚才说到第二条规范:

  • 不能由旧分支向新分支发起合并请求

比如,当你还在写自己的issue时,其他成员已经成功的向主分支贡献了代码。此时,主分支发生更新,而你的分支还是基于旧的主分支,因此你需要把新的主分支拉取下来。

这个时候,如果直接用git pull,大概率会出问题。

所以需要用到下面的方案:

// 把远程仓库的所有变更同步到本地的origin镜像中
git fetch --all

此时未进行代码合并,所以本地的代码没有变化。

// 把主分支合并到当前工作的分支
git merge origin/master

此时,你当前的工作分支不再基于旧的主分支,由于合并,已经基于新的主分支了。
在合并过程中也可能出现冲突,按照附录一的方法解决即可。

附录三 重置代码

如果你的代码出现了严重错误,想放弃全部更改,重置为最新版本的主分支代码,可以在当前的工作分支上执行:

// 拉取远程仓库的所有更改
git fetch --all
// 把当前工作分支的代码,用最新的master分支完全替换
git reset origin/master

然后,本地的工作分支,就和远程仓库的主分支一模一样了,重新编写代码即可。

总结 一图胜千言

团队合作开发的泳道图大概是这样的:

博客-团队协作时序图.png

成员在领取任务时,是一起进行的,谁也不知道哪个成员先提交代码。就像异步请求一样,谁也不知道哪个请求先返回。

因此,要想顺利的完成合作,有两个关键:

  • 一是具备解决冲突的能力,
  • 二是及时的拉取远程仓库的代码变更。

附录

git pull == git fetch all + git merge origin/branch

版权声明

本文作者:河北工业大学梦云智开发团队 - 刘宇轩

LYX6666
1.6k 声望73 粉丝

一个正在茁壮成长的零基础小白