
1.Git的定位
在我们自己开发项目的过程中,经常会遇到这样的情况,为了防止代码丢失,或者新变更的代码影响到原有的代码功能,为了在失误后能恢复到原来的版本,不得不复制出一个副本,比如:“坦克大战1.0”“坦克大战2.0”“坦克大战-确定版”“坦克大战-验收版”…
虽然每个版本我们都进行了备份,但是每个版本都有自己的内容,随着版本的不断增多,各自版本修改的内容是什么我们就不清楚了。
因此,就需要有一个版本控制器,来记录每次的修改以及版本的迭代信息,比如“坦克大战2.0”在“坦克大战1.0”上变更了Move类中第3行的代码,那么git的作用就会记录此次的变更具体信息,以此来方便我们回滚或者继续开发。
Git可以控制电脑上所有格式的文档,不仅是文本文件,源代码,还可以是二进制文件,比如图片、视频(这类文件无法记录具体的变更,只能记录空间占用的变化,比如100kb–>200kb)
2.Git的安装(Linux-centos)
如果你的平台是centos,安装git如下操作,以我的centos7.6为例:
首先,你可以尝试输入git --version,如果提示类似于git version 1.8.3.1 ,说明你已经安装好了,如果提示-bash: git: command not found,则执行以下命令进行安装sudo yum install git -y,完成安装后,可以再通过命令git --version来检验自己是否安装完成。
3.Git基本操作
3.1创建git本地仓库
只有把文件放在git仓库中,我们才能对文件的版本进行控制,所以我们首先需要创建一个仓库出来。
 先通过mkdir xxx命令创建一个目录,切换到对应目录后,输入命令git init,来创建一个git本地仓库,可以通过tree .git/命令来查看Git仓库的具体细节。
 
 注意,不允许在.git下手动修改
3.2配置git
当安装git以后,首先要做的就是配置你的用户名和Email地址,命令如下:
git config [--global] user.name "Your Name" 
git config [--global] user.email "email@example.com" 
# 把 Your Name 改成你的昵称
# 把 email@example.com 改成邮箱的格式,只要格式正确即可。
其中--global是一个可选项,因为一台机器上可以创建多个Git仓库,通过该选项,就是给所有仓库都进行了配置(全局配置)。如果系统在不同仓库中使用不同的name或e-mail,可以不要--global选项,但要注意,执行命令时必须要在想要操作的仓库中。
 查看配置的命令为:
git config -l
删除对应配置的命令为:
git config [--global] --unset user.name
git config [--global] --unset user.email

3.3认识工作区、暂存区、版本库
我们前边说了,只有把文件放在git仓库中,才能对文件版本进行控制,那么我们在git仓库中通过touch ReadMe,来创建一个ReadMe文件以后,可以对ReadMe文件进行操作吗?
 答案是不行,通过以上命令,列举出来的,就划分为两个区域:
 .git在版本库(仓库中)
 ReadMe在工作区中
 只有将工作区的内容,通过add、commit放入版本库中以后,才能进行文件版本控制。
下图展示了工作区、暂存区和版本库之间的关系:
 
 第一步操作add,就是将工作区中文件的修改内容,添加进版本库中的暂存区中;
修改内容:包含增加、修改、删除
第二步操作commit,就是把暂存区中的内容,提交到版本库中的master分支下;
 走完这两步操作,我们才可以真正意义上来管理ReadMe文件了
版本库中还存在一个对象区——objects,工作区每次的修改内容都会写入到一个git对象中,每次add,都会把这个git对象来交给对象区来维护,那么也就相当于,对象区维护了文件所有的版本。
暂存区存储一个个git对象的索引,master分支下,存储的也是一个个git对象的索引,不存储具体的对象。

 如果文件出现变更,最下边应该还有分支index。
3.4提交文件修改
我们在.git目录下创建了ReadMe文件,如果对ReadMe文件进行修改,需要通过add、commit的方式来进行记录,以下是具体的操作过程。
首先通过vim命令在ReadMe文件中添加一行内容hello git,如下展示,现在我们想要把ReadMe文件的变更记录进行保存,就需要下一步的add操作。
 
- git add [文件名1] [文件名2]:添加一个或者多个文件到暂存区
- git add .:添加当前目录下的所有文件到暂存区
完成add以后,我们紧接着就需要commit操作,来真正意义上把文件变更内容保存到本地仓库中。
- git commit -m "此次变更的具体描述细节":提交暂存区的全部内容到本地仓库
- git commit [文件名1] [文件名2] -m "此此变更的具体描述细节":提交暂存区的指定内容保存到本地仓库中
注意:
git commit后边的-m选项,要跟上本次提交的message,由用户自己完成,这部分内容不可省略,并要好好描述,用于记录此次变更的细节,是给我们自己看的。
整体操作流程如下图所示:
 
我们可以通过git log命令来查看我们的提交记录,该命令可以帮我们打印出来时间由近到远的所有记录,下图中都标红部分,就是该次commit的commit ID,由这个唯一的ID,就可以定位到这次提交。
 
 如果觉得输出的信息太多,可以加上 --pretty=oneline参数
 
3.5查看.git文件
在我们完成上边的提交操作以后,再通过tree .git命令来查看文件目录,如下图所示,多了index目录:

 我们可以通过cat命令来查看不同的目录下的文件.
首先我们来看HEAD指针,通过cat .git/HEAD命令,面板上打印出ref: refs/heads/master(说明HEAD指针指向master分支),再通过命令cat .git/refs/heads/master命令(该命令打印出最新一次提交的commitID),面板上打印出一行commitID,再通过命令git cat-file -p commitID,面板打印如下图结果,打印出了这次commitID提交对应的提交信息。
 
我们可以发现,打印结果中的tree后也跟着一个commitID,打印这个commitID,得到提交文件的commitID,再打印这个commitID,就可以得到文件里具体修改的内容。
 
 总结:
 HEAD指针指向.git/refs/heads/master(master分支),打印该分支,可以得到最新一次提交的commitID,打印这个commitID可以得到该次commit的描述详情,打印结果的tree后还跟着一个commitID,打印这个ID可以得到具体提交的文件的commitID,再打印这个ID,就可以得到文件具体修改的内容。
3.6场景学习

 如上图所示,提交后打印1 file changed, 0 insertions(+), 0 deletions(-),意思是只有一个文件改变了,这是因为我们只将file1提交到暂存区了,commit不会把暂存区以外的东西提交,想要提交file2,就需要再重新add、commit。
3.7修改文件
Git跟踪并管理的是修改,而非文件。
新增、删除或更改都属于修改,甚至创建一个新文件,也算一个修改。
让我们通过vim命令将ReadMe文件进行一次修改,里边增加一行代码hello world。
 
 接着可以通过git status来查看当前仓库的状态:
 
 上面的结果告诉我们,ReadMe文件被修改过了,但还没有完成添加与提交。
 目前,我们只知道文件被修改了,如果想要知道具体哪些地方被修改了,可以通过git diff命令
 
git diff [file]命令用来显示暂存区和工作区文件的差异,显示的格式是Unix通用的diff格式。
我们add文件以后,再通过status命令来查看状态,显示有待提交。
 
 commit文件并带上描述,再通过status命令来查看状态:
 
3.8版本回退
Git能够管理文件的历史版本,如果有一天你发现之前的工作做的出现了很大的问题,需要在某个特定的历史版本重新开始,这个时候,就需要版本回退了。
 执行git reset命令用于回退版本,可以指定退回某一次提交的版本,回退的本质是将版本库中的内容进行回退,工作区或暂存区是否回退由命令参数决定:
 git reset命令语法格式为:git reset [--soft | --mixed | --hard [HEAD]]
- --soft参数对于工作区和暂存区的内容都不变,只是将版本库回退到某个指定版本。
- --mixed为默认选项(使用时可以不带该参数),该参数将暂存区的内容退回为指定提交版本内容,工作区文件保持不变。
- --hard参数将暂存区和工作区都退回到指定版本。该参数需要慎用,因为如果工作区有未提交的代码时,使用该命令工作区会回滚,你没有提交的代码就再也找不回了。
HEAD说明:
- 可直接写成commit ID,表示指定退回的版本
- HEAD 表示当前版本
- HEAD^ 上一个版本
- HEAD^^ 上上一个版本
- 以此类推
可以使用~数字表示:
- HEAD~0 表示当前版本
- HEAD~1 上一个版本
- HEAD~2 上上一个版本
以下是实际操作场景:
 
 通过git reset --hard commit ID回退到指定版本,ReadMe文件里边的内容也发生了回滚。
 如果想要再返回原来的状态,就再找到指定的commit ID进行回滚即可。
 
 只要commit ID我们能找到,我们就可以回退到指定的版本,可以通过git reflog命令来查看所有的commit ID记录(此处我们发现gommit ID很短,但是通过这个短的ID也能够进行正常回退)
 
我们进行版本回退的速度很快,这是因为我们的每个版本都有一个commit ID,git只需要更改指针的指向(HEAD指针指向master,master存储最新一次commit ID)就可以进行版本的回退了。
总结:
 
3.9撤销修改
如果我们在工作区写了很长时间代码,但是后来写的代码质量都很差,想要撤销掉我们的修改,恢复到上一个版本,分以下几种情况来讨论。
- 情况一:工作区的代码没有add
- 情况二:已经add,但没有commit
- 情况三:已经add,并且也commit了
我们还以ReadMe文件作为举例,我们在工作区,给ReadMe文件新增了一行代码xxx code。
 

对应情况一,我们只需要命令git checkout --[filename]即可撤销
 
 对应情况二,我们可以先通过命令git reset HEAD ReadMe(默认参数为--mixed),将暂存区的内容回退到当前版本区的内容(都为空),然后再通过git checkout --[filename]命令来撤销工作区修改的内容。
 
 对于情况三,我们可以通过命令git reset --hard HEAD^将三个区域都回退到上一版本的内容【注意:该情况为commit之后,push之前】
 
 总结:
 
3.10删除文件
在git中,如果我们想要做一个删除操作,只通过在工作区的rm命令是无法完成删除的,还需要add和commit操作才能完成暂存区和工作区的删除
所以我们一般可以直接通过命令git rm可以完成工作区和暂存区的删除,然后再通过git commit -m" ",来完成版本库中的删除。
 
4.Git分支管理
4.1理解分支
分支就是一个复制版本的概念,它与主版本互不干扰,可以在分支上进行操作,防止在主干上直接操作造成失误;在分支上完成开发操作以后,可以再合并分支到主干上。
在版本回退中,每次提交,Git都会把它们串成一条时间线,这条时间线就可以理解为一个分支,如果只有这一条时间线,那么这个分支就叫做主分支,即master分支。
HEAD指针不仅可以指向master,还可以指向其他分支,被指向的分支就是当前正在工作的分支。
4.2创建、切换、合并分支
Git支持我们查看或创建其他分支,在这里我们创建第一个自己的分支dev,对应的命令为:
 
 *表示当前HEAD指向的分支是master分支,并且目前dev和master指向同一个修改。
 
 如果我们想要在dev分支下进行开发工作,就需要将分支切换到dev上来,可以通过git checkout dev命令来完成切换,如下演示:
 
 接下来我们在dev分支下修改ReadMe文件,新增一行内容,并进行一次提交操作:
 
 在dev分支上commit以后,当前仓库的状态如下:
 
如果我们想要在master主分支上看到新的提交,就需要将dev分支合并到master分支,示例如下:
 
 当前仓库的状态如下:
 
 Fast-forward代表“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。
命令:
git branch:查看本地所有分支
git branch -r:查看远程所有分支
git branch -a:查看所有分支
4.3删除分支
合并完成以后,dev分支对我们来说就没用了,那么dev分支就可以被删除掉,注意如果当前正处于某分支下,就不能删除当前分支,需要先切换到master分支下,再来删除dev分支。
git branch -d 分支名
 
 此时的仓库状态如下所示:
 
 因为创建、合并和删除分支非常快,所以更建议使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。
如果我们在分支上开发了新功能,但是产品不要这个新功能了,这时候我们可以通过git branch -D 分支名来强制删除该分支。
4.4合并冲突
在我们合并分支的时候,并不是想合并就能合并成功的,有时候可能会遇到代码冲突的问题。
 比如我们在主分支上的ReadMe文件内容为aaa on dev1,我们创建并切换到新的分支上dev1,将aaa on dev1变更为bbb on dev1,再换回到主分支上,并将aaa on dev1改为ccc on dev1,这时候想要将dev1分支合并到master主分支上,就会产生合并冲突。
 
为了演示这个问题,我们需要创建一个新的分支,并切换到该分支上,可以使用git checkout -b dev1命令,一步完成创建分支并切换到该分支的操作。
 
 接下来在dev1分支上,将aaa on dev1变更为bbb on dev1,并add commit。
 
 然后再切回到主分支上,将aaa on dev1变更为bbb on dev1,并add commit。
 
 此时仓库中的状态就如下图所示:
 
 如果想要将dev1分支合并到master分支上,就会有以下合并冲突的提示:
 
 修改冲突内容并提交
 
 
 此时合并冲突就修改了,仓库的状态如下图所示,我们也可以通过命令git log --graph --pretty=oneline --abbrev-commit,来查看仓库的状态
 
 
4.5 分支管理策略
通常合并分支时,如果可能,Git会采用Fast forward模式。那么形成的合并结果将如下图所示:
 
 在这种Fast forward模式下,删除分支以后,查看历史分支时,会丢掉分支信息,看不出来最新提交到底是merge进来的还是正常提交的。
 但在合并冲突部分,我们也看到通过解决冲突问题,会再进行一次新的提交,得到的最终状态为:
 
 那么这就不是Fast forward模式了,这样的好处是,从分支历史上就可以看出分支信息。比如我们现在已经删除了在合并冲突部分创建的dev分支,但依旧能看到master其实是由其他分支合并得到的。
Git支持我们强制禁用Fast forward模式,那么就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
下面是实战示例:
 首先,创建新的分支dev,并切换至新的分支:
 
 修改ReadMe文件,并提交一个新的commit:
 
 切回master分支,开始合并:
 
 --no-ff参数,表示禁用Fast forward模式,禁用Fast forward模式后合并会创建一个新的commit,所以加上-m参数,把描述写进去。
 合并后,查看分支历史:
 
 可以看到,不使用Fast forward模式,merge后就像下图状态:
 
所以在合并分支时,加上--no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾今做过合并,而fast forwad合并就看不出来曾经做过合并。
分支策略
在实际开发中,我们应该遵循几个基本原则来进行分支管理;
 master分支是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
 而干活平时应该在dev分支上,每个人都在dev分支上干活,且每个人都有自己的分支,时不时往dev分支上合并就可以了,然后再把dev分支合并到master分支上;
 
 所以团队合作的分支看起来就像下图:
 
4.6 bug分支
假如我们现在正在dev分支上进行开发,开发到一半,突然发现master分支上面有bug,需要解决。在Git中,每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。
 如果我们现在在dev分支上开发了一部分,还无法提交,这时候需要使用git stash命令,来将当前的工作区信息进行储藏(只存储被git追踪的文件),被储藏的内容可以在将来某个时刻恢复出来。
 
 我们用git status命令查看工作区,是干净的,因此可以放心地创建分支来修复bug。
 储藏dev分支的工作区以后,由于我们要基于master分支修复bug,所以需要切回master分支,再新建临时分支来修复bug,示例如下:
 
 修复完成后,切换到master分支,并完成合并,最后删除fix_bug分支。
 
 这时,我们已经完成了bug的修复,要继续回到dev分支上进行开发,切回dev分支,使用git stash list可以看到我们存储的工作现场版本,使用git stash pop命令恢复现场:
 
 然后我们可以继续开发,开发完成后提交:
 
 此时git仓库的状态如下所示:
 
 master分支目前最新的提交,是要领先于dev基于master分支时提交的,我们最终想要让master分支合并dev分支,但如果切回master分支直接合并,有可能存在dev和fix_bug分支上的冲突,而代码冲突需要我们手动解决(在master上解决),直接在master分支上变更,是有一定风险的,这时更好的做法时,切回dev分支,将master分支合并到dev分支上,并在dev分支上解决代码冲突,解决冲突以后,再将dev分支合并到master分支上,此时的状态为:
 
 
 实操如下:
 
5.远程操作
5.1 分布式版本控制系统
我们之前所介绍到的所有内容(工作区、暂存区、版本库等等),都是在本地,也就是在你的笔记本或者计算机上。而我们的Git其实是分布式版本控制系统。
可以简单理解为,我们每个人的电脑上都是一个完整的版本库,大家可以在多台电脑上进行修改,然后可以把自己的修改推送到中央服务器上,其他同学可以通过拉取中央服务器上的代码来获取到最新的修改;中央服务器的作用就是方便“交换”大家的修改。
 
5.2 远程仓库
Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上,有一台电脑充当服务器的角色,每天24h开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交。
网站GitHub或者gitee都是提供Git仓库托管服务的,下面我们来使用一下gitee(码云)远程仓库。
新建远程仓库

 
 创建成功:
 
 并且在刚创建好的仓库中,有且只有一个默认分支master
 
克隆远程仓库
克隆/下载远端仓库到本地,需要使用git clone命令,后面跟上我们的远端仓库链接:
 
 SSH协议和HTTPS协议是Git最常使用的两种传输协议。SSH协议使用了公钥加密和公钥登录机制,体现了其实用性和安全性,使用此协议需要将我们的公钥放上服务器,由Git服务器进行管理。使用HTTPS方式时,没有要求,可以直接克隆下来。
- 使用HTTPS方式:
  
- 使用SSH方式:
 SSH方式直接使用git clone命令是不能够将远程仓库克隆到本地的,需要我们将公钥添加到远端仓库中,才能够将仓库克隆下来。
第一步:创建SSH Key;在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可以直接跳到下一步。如果没有,需要创建SSH Key:
注意此处要输入自己的邮箱,然后一路回车,使用默认值即可。

 第二步:添加自己的公钥到远端仓库
再次打开ssh目录,查看公钥id_rsa.pub,将公钥复制,粘贴到gitee上。
 
 
 然后再输入git clone命令就可以完成克隆操作了。
完成克隆以后,仓库的状态如下图所示:
 
向远程仓库推送
在向远程仓库推送时,需要注意设置的name和Email需要和gitee上配置的用户名和邮箱保持一致,否则会报错。
 
配置好以后,我们就可以向远程仓库推送了
 推送的命令格式如下:
git push <远程主机名> <本地分支名> :<远程分支名>
# 如果本地分支名与远程分支名相同,则可以省略冒号后的内容
git push <远程主机名> <本地分支名>
具体的推送操作如下:
 
整个推送的流程如下图所示:

拉取远程仓库
如果其他同学向远端仓库push内容,那么远端仓库的代码是新于你本地的代码的,所以就需要通过命令来拉取远程仓库上最新的代码,代码格式如下:
git pull <远程主机名> <远程分支名>:<本地分支名>
# 如果远程分支是与当前分支合并,则冒号后面的部分可以省略
git pull <远程主机名> <远程分支名>
该命令会完成拉取并合并分支两步操作。
命令git pull,后面不加其他内容,可以完成两种类型的拉取,一种是拉取对应分支下的内容【这种需要通过本地分支与远程分支建立连接】,另一种是拉取仓库的内容【即拉取远程最新的分支情况】
通过以下两种方式可以将本地分支与远程分支建立连接:
git checkout -b [branch-name] [origin/branch-name]【该方法在新建分支时建立连接】
git branch --set-upstream-to=origin/branch-name branch-name【该方法在建立好分支以后建立连接】
5.3 配置git
忽略特殊文件
在日常开发中,我们有些文件不想或者不应该提交到远端(比如说保存了数据库密码的配置文件),就需要在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件了。
.gitignore文件可以在gitee创建仓库时默认勾选生成,也可以由我们自己来创建,效果相同;
 假如我们想要忽略以.so和.ini结尾的所有文件,.gitignore的内容如下所示:
# 忽略以.so和.ini结尾的所有文件
*.so
*.ini
如果某个以.so或者.ini结尾的文件又想要提交,可以在.gitignore文件中添加文件名,比如想要提交a.so,那么.gitignore的内容如下所示:
# 忽略以.so和.ini结尾的所有文件
*.so
*.ini
!a.so # 排除a.so文件
如果.gitignore文件里维护的代码太多了,而此时我们又新建了个文件(比如文件d.so),没有被git追踪管理,我们可以通过命令git check-ignore -v d.so 来查看被忽略的原因。
最后,配置好.gitignore文件以后,记得把.gitignore文件也提交到远端,就完成了。
给命令配置别名
在我们使用Git期间,可以通过配置,来将命令简化。
比如我们想要将git status命令简化为git st,对应的命令为(--global是全局参数):
 git config --global alias.st status
将git log --pretty=oneline --abbrev-commit命令简化为git lpa,对应的命令为:
 git config --global alias.lpa 'log --pretty=oneline --abbrev-commit'
使用效果如下所示:
 
6.标签管理
标签tag,可以简单的理解为是对某次commit的一个标识,相当于起了一个别名。例如,在项目发布某个版本的时候,针对最后一次commit起一个v1.0这样的标签来标识里程碑的意义,相较于难以记住的commit ID,tag可以很好的解决这个问题,因为其便于记忆且有意义,所以当我们需要回退到某个重要版本是,直接使用标签就能很快定位到。
6.1 操作标签
创建标签:
git tag v1.0给最新的一次commit打标
git tag -a[name] -m "xxx" [commit_id]
Git提供的带有说明的标签,用-a指定标签名,-m指定说明文字
如果想要给指定的commit打标签,找到历史提交的commit id,然后打标即可,如下命令
 git tag v0.9 a009936
git tag:查看所有标签(按时间排序)
 git show [tagname]:查看标签信息
 git tag -d [tagname]:删除标签
6.2 推送标签
因为创建的标签都只保存在本地,不会自动推送到远程,如果想要推送某个标签到远程,使用命令git push origin <tagname>;
如果你本地有很多的标签,也可以通过命令git push origin --tags,将所有标签一次性的全部推送到远端。
如果标签已经推送到远程,要删除远程标签,就需要两步操作,第一步先从本地删除,第二步再从远程删除。
 git tag -d [tagname] #删除本地标签
 git push origin :[tagname] #删除远程标签
7.多人协作
7.1 场景一:多人同一分支
现在我们有这样一个场景:
目标:在远程的
master分支下的file.txt文件,新增代码aaa、bbb实现:由开发者1新增
aaa,由开发者2新增bbb
条件:在一个分支下协作完成
为了模拟实现以上场景,我们分别在linux和Windows上针对同项目进行协作开发。
目前,我们的远程仓库中只有一个master主分支,但在实际的项目开发中,在任何情况下其实都是不允许直接在master分支上修改代码的,这是为了保证主分支的稳定。所以在开发新功能是,常常会新建其他分支,供开发时进行迭代使用。
那么首先我们在gitee上新建dev远程分支供我们使用:
 
 然后分别在linux和windows上更新最新的分支及代码情况
将仓库克隆到本地以后,分支情况如下图,因为我们需要在本地分支上做修改,所以需要在本地新建分支dev,并与远程分支dev建立连接,通过命令git checkout -b dev origin/dev来实现。
 
还可以通过命令
git branch --set-upstream-to=origin/<远程分支名> <本地分支名>,来将本地分支与远程分支建立连接。
我们还可以通过git branch -vv命令来查看分支的连接情况,通过将本地分支与远程分支建立连接,在使用git push或者git pull命令时,就不用在指定分支了,直接就是两个连接分支之间的推送和拉取操作。
接下来我们在linux系统下,完成新增aaa的操作,并将新增操作推送到远程的仓库中。
 
然后再windows系统下,完成新增bbb的操作
 
 并将新增bbb的操作变更,也推送到远程仓库中
 
 但如果当我们输入git push命令推送时,由于远程仓库中file.txt文件新增了aaa代码,windows中的仓库并没有感知,所以如果直接推送会产生代码冲突,需要先通过git pull命令将远程仓库中的代码拉到本地,解决冲突以后再进行推送
 
 
完成远程分支的推送后,我们还需要将远程分支dev合并进远程分支master,才算完成了整个链路。
 一般在远程仓库中进行合并操作时,需要在远程仓库中提交Pull Requests合并请求工单,将远程的dev分支合并到master分支上,工单会被审核员或者管理员审批,审批通过才能完成合并,这也是在公司经常用的合并提交代码的方式。
 
 总结一下,在同一分支下进行多人协作的工作模式通常是这样的:
- 首先,可以试图用git push推送自己的修改;
- 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
- 如果合并有冲突,则解决冲突,并在本地提交;
- 没有冲突或者解决掉冲突以后,再用git push推送就能成功;
- 功能开发完毕,将远程分支merge进master,然后将临时分支删除
7.2 场景二:多人不同分支
现有场景2:
目标:远程
master分支下新增function1和function2文件
实现:由开发者1新增function1,由开发者2新增function2
条件:在不同分支下协作完成,各自让某一个功能私有某一个分支
基于以上场景的分支创建,我们有两种方式来实现:
 1、在远程仓库基于master创建分支,然后本地拉取该分支进行功能开发
这种方式比较建议,因为基于远程的
master分支创建新的分支,得到的是最新的代码
2、基于本地分支创建新分支,完成代码开发后进行git push操作
这种方式需要注意的是,本地的
master分支可能不是最新的代码,需要先通过git pull操作,拉取到最新的master分支,然后再基于该分支创建新的分支进行开发。
下边我们用第二种方式来做演示:
首先在linux系统下的仓库,完成开发者1的工作:
 
 然后在windows系统下,完成开发者2的工作:
 
 至此我们发现,远程仓库的分支情况符合我们的预期:(新建了两个分支,并新增了对应的功能)
 
 接下来就可以通过提交PR,来完成分支合并的请求了。
如果将临时分支,合并到master分支上时,产生了冲突,就需要先将master分支合并到临时分支上,在临时分支上解决了冲突,再将临时分支合并到master分支上,该场景就如下图所示【先完成了分支feature-2的合并,然后在合并feature-1分支时,产生了冲突】:
 

 本地解决完冲突并push以后,可以接着提交PR来完成合并分支的请求及操作了。
7.3 处理远程已经删除的分支
如果我们已经在远程仓库中删除了某些分支,但是我们通过git branch -a命令还是会看到这些被删除的分支
 
 
 如果想处理掉这些在远程已经删除的分支,可以通过命令git remote show origin来查看这些分支的详情,并会提示你用git remote prune origin来删除这些在远程仓库中已经被删除的分支。
 
8.企业开发运用
当今企业,经常使用的软件迭代开发、维护的工具,是DevOps,在Devops的软件开发过程包含计划、编码、构建、测试、预发布、发布、运维、监控,由此可见DevOps的强大。
8.1系统开发环境
在系统开发中,有以下几个环境需要我们必须了解:
 1、开发环境:开发环境是开发者们专门用于日常开发的服务器。
 2、测试环境:一个程序在测试环境中是不稳定的,该环境是开发环境到生产环境的过渡环境。
 3、预发布环境:该环境是为避免因测试环境和线上环境的差异带来的缺陷漏测而设立的一套环境。其配置等基本和生产环境一致,目的是能让我们发正式环境时更有把握!所以预发布环境是产品质量的最后一道防线,因为下一步项目就要上线了,要注意预发布环境服务器不在线上集成服务器范围之内,为单独的一些机器。
 4、生产环境:是指正式提供对外服务的线上环境,例如我们目前在移动端或PC端能访问到的APP都是生产环境。
这几个环境也可以说是系统开发的三个重要阶段:开发–》测试–》上线。

8.2 Git分支管理规范
对于开发人员来说,一般会针对不同的环境来设计不同的分支,例如:
| 分支 | 名称 | 适用环境 | 
|---|---|---|
| master | 主分支 | 生产环境 | 
| release | 预发布分支 | 预发布/测试环境 | 
| develop | 开发分支 | 开发环境 | 
| feature | 需求开发分支 | 本地 | 
| hotfix | 紧急修复分支 | 本地 | 
master分支
- master为主分支,该分支为只读且唯一分支。用于部署到正式发布环境,一般由合并- release分支得到。
- 主分支作为稳定的唯一代码库,任何情况下不允许直接在master分支上修改代码。
- 产品的功能全部实现以后,最终在master分支对外发布,另外所有在master分支的推送应该打标签(tag)做记录,方便追溯。
- master分支不可删除
release分支
- release为预发布分支,基于本次上线所有的- feature分支合并到- develop分支以后,基于- develop分支创建。可以部署到测试或预发布集群。
- 命名以release/开头,建议命名的规则:release/version_publishtime
- release分支主要用于提交给测试人员进行功能测试。发布提测阶段,会以- release分支代码为基准进行提测。
- 如果在release分支测试出问题,需要回归验证develop分支看是否存在此问题。
- release分支属于临时分支,产品上线后可选删除。
develop分支
- develop为开发分支,基于- master分支创建的只读且唯一分支,始终保持最新完成以及bug修复后的代码。可部署到开发环境对应集群。
- 可根据需求大小程度确定是由feature分支合并,还是直接在上面开发(不建议)。
feature分支
- feature分支通常为新功能或新特性开发分支,以- develop分支为基础创建- feature分支
- 命名以feature/开头,建议的命名规则:feature/user_createtime_feature
- 新特性或新功能开发完成后,开发人员需要合到develop分支。
- 一旦该需求发布上线,便将其删除。
hotfix分支
- hotfix分支为线上bug修复分支或叫补丁分支,主要用于对线上的版本进行bug修复,当线上出现紧急问题需要马上修复时,需要基于- master分支创建- hotfix分支。
- 命名以hotfix/开头,建议的命名规则:hotfix/user_createtime_hotfix
- 当问题修复完成后,需要合并到master分支和develop分支并推送远程。一旦修复上线,便将其删除。
用一张图来总结:
 
8.3 DevOps开发实战
【Gitee企业版】
 
准备工作
创建项目
 
 创建仓库
 
 
 添加成员
 
实战演练
现有一个订单管理的新需求需要开发,首先可以基于develop分支创建一个feature/ldj_order_20231024分支。
 
 1.需求在feature/ldj_order_20231024分支开发完毕,这时研发人员可以将代码合并到develop分支,将其部署在开发环境的服务器中,方便开发人员进行测试和调试。
 a.开发者在feature分支下发起请求评审(PR)
 b.审核员审查代码
 c.审查通过,合并分支
 d.合并通过,查看结果
2.在develop下开发人员自测通过后,先确定下develop不存在未测试完毕的需求,然后研发人员可基于develop分支创建一个release/xxx分支出来,可交由测试人员进行测试。
3.测试人员测试release通过后(包含测试环境和预发布环境的测试),就可将代码合并入master。
 4.测试人员在master(正式环境)测试通过后,便可删除feature/xxx分支。
修复bug
修复测试环境bug
 在develop测试出现了Bug,建议大家直接在feature分支上进行修复。修复后的提测上线流程与新需求加入的流程一致。
修改预发布环境Bug
 在release测试出现了Bug,首先要回归下develop分支是否同样存在这个问题。如果存在,修复流程与修复测试环境Bug流程一致。
 如果不存在,这种可能性较少,大部分时数据兼容问题,环境配置问题等。
修改正式环境Bug
 在master测试出现了Bug,首先要回归下release和develop分支是否同样存在这个问题。
 如果存在,修复流程与修复测试环境Bug流程一致。
 如果不存在,这种可能性也比较少,大部分是数据兼容问题,环境配置问题等。
紧急修复正式环境Bug
 需求在测试环节未测试出Bug,上线运行一段时候出现了Bug,需要紧急修复的。
 可基于master创建hotfix/xxx分支,修复完毕后发布到master验证,验证完毕后,将master代码合并到develop分支,同时删除hotfix/xxx分支。



















