一、版本控制
1.1 团队开发问题
企业项目一般以团队形式实施开发,那团队开发中会出现哪些问题呢?
- 小明负责的模块就要完成了,就在即将Release之前的一瞬间,电脑突然蓝屏,硬盘光荣牺牲!几个月来的努力付之东流——需求之一:备份!
- 这个项目中需要一个很复杂的功能,老王摸索了一个星期终于有眉目了,可是这被改得面目全非的代码已经回不到从前了。什么地方能买到哆啦A梦的时光机啊?需求之二:代码还原!
- 小刚和小强先后从文件服务器上下载了同一个文件:
Analysis.java
。小刚在Analysis.java
文件中的第30行声明了一个方法,叫count()
,先保存到了文件服务器上;小强在Analysis.java
文件中的第50行声明了一个方法,叫sum()
,也随后保存到了文件服务器上,于是,count()
方法就只存在于小刚的记忆中了——需求之三:协同修改! - 老许是一位项目经理,他需要把每一个版本的项目都保存一份, 而且这些工程里其实有很多文件都是重复的,导致电脑空间经常不足 , 要找某个版本的时候也很麻烦——需求之四:多版本项目文件管理!
- 老王是另一位项目经理,每次因为项目进度挨骂之后,他都不知道该扣哪个程序员的工资!就拿这次来说吧,有个该死的
Bug
调试了30多个小时才知道是因为相关属性没有在应用初始化时赋值!可是小强、小明、小刚和小军都不承认是自己干的!——需求之五:追溯问题代码的编写人和编写时间! - 小温这两天幸福的如同掉进了蜜罐里,因为他成功的得到了前台MM丽丽的芳心,可他郁闷的是这几天总是收到
QA
小组的邮件,要求他修正程序中存在的Bug
,可他自己本地电脑上是没有这些Bug的,“难道我的代码被哪个孙子给改了?”。是的,小温没来的时候,丽丽是QA
小组小郑的女朋友啊!——需求之六:权限控制!
1.2 版本控制思想
要解决上面问题,需要引入新的思想:版本控制思想
版本控制: 版本控制(Revision control
)是维护工程蓝图的标准做法,能追踪工程蓝图从诞生一直到定案的过程。是一种记录若干文件内容变化过程,以便将来查阅特定版本修订情况的系统。
版本控制深入程序员在团队配合中,如果你的项目没有版本控制:
一、 代码管理混乱。
二、 解决代码冲突困难。
三、 在代码整合期间引发BUG。
四、 无法对代码的拥有者进行权限控制。
五、 项目不同版本发布困难。
…
1.2.1 版本工具
集中式版本控制(SVN)
SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以首先要从中央服务器哪里得到最新的版本,然后干活,干完后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,如果在局域网还可以,带宽够大,速度够快,如果在互联网下,如果网速慢的话,就郁闷了。
下图就是标准的集中式版本控制工具管理方式:
集中管理方式在一定程度上看到其他开发人员在干什么,而管理员也可以很轻松掌握每个人的开发权限。
但是相较于其优点而言,集中式版本控制工具缺点很明显:
- 服务器单点故障
- 容错性差
分布式版本控制(Git)
Git是分布式版本控制系统,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上。然后团队协作再通过远程仓库进行协作。
当然,Git
的优势不单是不必联网这么简单,后面我们还会看到Git
极其强大的分支管理,把SVN
等远远抛在了后面。
二、Git简介
2.1 简介
很多人都知道,Linus
在1991年创建了开源的Linux,从此,Linux
系统不断发展,已经成为最大的服务器系统软件了。
Linus
虽然创建了Linux
,但Linux
的壮大是靠全世界热心的志愿者参与的,这么多人在世界各地为Linux
编写代码,那Linux
的代码是如何管理的呢?
事实是,在2002年以前,世界各地的志愿者把源代码文件通过 diff 的方式发给Linus
,然后由Linus
本人通过手工方式合并代码!
你也许会想,为什么Linus
不把Linux
代码放到版本控制系统里呢?不是有CVS
、SVN
这些免费的版本控制系统吗?因为Linus
坚定地反对CVS
和SVN
,这些集中式的版本控制系统不但速度慢,而且必须联网才能使用。有一些商用的版本控制系统,虽然比CVS
、SVN
好用,但那是付费的,和Linux
的开源精神不符。
不过,到了2002年,Linux
系统已经发展了十年了,代码库之大让Linus
很难继续通过手工方式管理了,社区的弟兄们也对这种方式表达了强烈不满,于是Linus
选择了一个商业的版本控制系统BitKeeper
,BitKeeper
的东家BitMover
公司出于人道主义精神,授权Linux
社区免费使用这个版本控制系统。
安定团结的大好局面在2005年就被打破了,原因是Linux
社区牛人聚集,不免沾染了一些梁山好汉的江湖习气。开发Samba
的Andrew
试图破解BitKeeper
的协议(这么干的其实也不只他一个),被BitMover
公司发现了(监控工作做得不错!),于是BitMover
公司怒了,要收回Linux
社区的免费使用权。
Linus
可以向BitMover
公司道个歉,保证以后严格管教弟兄们,嗯,这是不可能的。实际情况是这样的:
Linus
花了两周时间自己用C写了一个分布式版本控制系统,这就是Git
!一个月之内,Linux
系统的源码已经全部交由Git
管理了!牛是怎么定义的呢?大家可以体会一下。
Git
迅速成为最流行的分布式版本控制系统,尤其是2008年,GitHub
网站上线了,它为开源项目免费提供Git
存储,无数开源项目开始迁移至GitHub
,包括jQuery
,PHP
,Ruby
等等。
历史就是这么偶然,如果不是当年BitMover
公司威胁Linux
社区,可能现在我们就没有免费而超级好用的Git
了。
2.2 Git环境的搭建
2.2.1 Git的下载
https://git-scm.com/download
我们使用Windows系统,所以安装Windows 版本的git软件。
一路“Next”使用默认选项即可,安装说明详情见 《git安装.docx》安装完成后,可以在任意文件夹点右键,看到如下菜单:
2.2.2 Git可视化客户端
TortoiseGit是一款开源的Git图形界面工具,使用TortoiseGit可以简化Git相关的操作(本质上还是执行的Git相关命令)。TortoiseGit下载地址: https://tortoisegit.org/download/
安装说明详情见资料下的《TortoiseGit安装》,基本上也是一路“Next”使用默认选项直到Finish完成。安装完毕后在系统右键菜单中会出现TortoiseGit的菜单项。
扩展操作
TortoiseGit 客户端可以让git文件图标根据不同状态显示不同效果,安装成功后,重启一下电脑就可以。
部分win7 win8 win10 系统即使重启,也显示不同,原因是系统图标显示与TortoiseGit 图标显示冲突导致的。
修复方式:https://blog.csdn.net/Aaron_King/article/details/126153694
三、Git 命令操作
3.1 初始化仓库
Git操作前需要初始化仓库,用于存储版本管理的项目代码,目前仓库有2种类型:
- 本地仓库:是在开发人员自己电脑上的仓库
- 远程仓库:是在远程服务器上的仓库(跟团队其他成员共用)
配置自己名称与邮箱账户,在公司一般是自己名称拼音与公司邮箱
git config --global user.name "Your Name"
git config --global user.email "email@example.com"
初始化本地仓库
git init
命令执行后,会在当前目录下多了一个.git
的目录,这个目录是Git
本地仓库,用于跟踪与管理代码(文件),没事别手动修改这个目录里面的文件,容易改乱了,导致Git
仓库给蹦了。
这里要注意,部分同学电脑没勾选 隐藏项目 选项,会看不见 .git 目录
3.2 添加文件
仓库初始化好了,怎么将文件添加到仓库,并管理起来呢?
步骤1:创建一个普通文本文件
步骤2:将文件添加到暂存区
git add readme.txt
步骤3:将文件添加到版本库
git commit -m "添加了readme.txt文件"
简单解释一下git commit
命令,-m
后面输入的是本次提交的说明,可以输入任意内容,当然最好是有意义的,这样你就能从历史记录里方便地找到改动记录。
git commit
命令执行成功后会告诉你,1个文件被改动(我们新添加的readme.txt文件)
扩展
如果后续添加文件多了,可以使用下面命令
git add file1.txt
git add file2.txt file3.txt
git add . 当前文件夹下所有文件
git commit -m "add 3 files."
3.3 Git 流程全景图
3.4 Git工作流程
3.5 工作区和暂存区
在Git中进行 crud 操作时都需要执行 git add 文件这个操作,底层操作将操作文件添加一个叫缓存区区域中缓存,当操作完毕之后,使用 git commit 操作,进行统一提交,将编辑文件统一同步版本中
3.6 查看文件状态
**问题:**如何查看项目目前的状态?我在电脑前写了一段时间代码,用Git管理,中途上厕所,然后又去吃了个苹果,继续回来工作,不记得之前用Git干了些什么了?
git status # 查看当前git版本库的状态(查看缓存区中的文件内容)
3.7 查看提交日志
实际工作中,我们脑子里怎么可能记得一个几千行的文件每次都改了什么内容,不然要版本控制系统干什么。版本控制系统肯定有某个命令可以告诉我们历史记录,在Git
中,我们用git log
命令查看
git log
git log
命令显示从最近到最远的提交日志,如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline
参数:
git log --pretty=oneline
黄色长长的字符串是本次提交的commit id, 是Git
使用SHA-1
算法产生唯一标识符,能保证全球唯一。
3.8 查看差异
如果一个文件知道被人修改了,但如果能看看具体修改了什么内容,自然是更好的
比如你休假两周从国外回来,第一天上班时,已经记不清上次怎么修改的readme.txt
,所以,需要用git diff
这个命令看看:
git diff # 查看不同版本之间的文件差异
3.9 版本回退
我们不断修改文件,不断的往版本库中提交文件。就好比玩RPG
游戏时,每通过一关就会自动把游戏状态存盘,如果某一关没过去,你还可以选择读取前一关的状态。有些时候,在打Boss
之前,你会手动存盘,以便万一打Boss
失败了,可以从最近的地方重新开始。Git
也是一样,每当你觉得文件修改到一定程度的时候,就可以**“保存一个快照”**,这个快照在Git
中被称为 commit
。一旦你把文件改乱了,或者误删了文件,还可以从最近的一个commit
恢复,然后继续工作,而不是把几个月的工作成果全部丢失。
如果想回到上一个版本,应该怎么做呢?
Git
必须知道当前版本是哪个版本,在Git
中,用HEAD
表示当前版本,上一个版本就是HEAD^
,上上一个版本就是HEAD^^
,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100
。
git reset --hard HEAD^
回到指定版本
git reset --hard <commit id>
拓展需求: 如何回退到最新版本
3.10 管理修改
使用Git修改文件,存在一个需要探讨的问题:二次修改
操作方式1:
第一次修改 -> git add -> 第二次修改 -> git commit
操作方式2:推荐使用
第一次修改 -> git add -> 第二次修改 -> git add -> git commit
注意:建议在每次 commit 之前先检查是否有文件没有被 add
3.11 修改撤销
git checkout – filename`可以丢弃工作区的修改:– 后面是一个空格
命令 git checkout -- readme.txt
意思就是,把 readme.txt
文件在工作区的修改全部撤销,这里有两种情况:
一:readme.txt
自修改后还没有被放到暂存区(git add
),现在,撤销修改就回到和版本库一模一样的状态;
二:readme.txt
已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
总之,就是让这个文件回到最近一次 git commit
或 git add
时的状态。
注意:
git checkout -- file
命令中的 --
很重要,没有 --
,就变成了**“切换到另一个分支”**的命令,我们在后面的分支管理中会再次遇到 git checkout
命令
3.12 删除文件
一般情况下,你通常直接在文件管理器中把没用的文件删了,或者用rm
命令删了:
git rm test.txt
这个时候,Git
知道你删除了文件,因此,工作区和版本库就不一致了,git status
命令会立刻告诉你哪些文件被删除了:
删除完成后需要 commit
如果删除了想恢复,可以使用 reset
版本恢复
步骤1:本地删除没用的文件(查看状态)
步骤2:先 add 以下(查看状态与步骤1进行比较)
步骤3:提交删除文件
3.13 分支管理
分支管理的是Git灵魂,开发必不可少基本操作,必须掌握。
为啥存在分支?因为项目成品经过这几个流程: 开发, 测试,上线,bug修改,多版本发布等。同一个项目不同版本同时开发,同时测试,同时上线,怎么确保在这种复杂情况下让项目能独立,又能相关关联执行下去呢?Git给出解决方案是分支管理, 每一个阶段就是一个分支,即可以相互独立,又可以相互合并。
3.13.1 查看分支
git branch
3.13.2 创建分支
git branch <name>
3.13.3 切换分支
git checkout <name>
3.13.4 创建 + 切换分支
git checkout -b <name>
3.13.5 合并分支
将某分支合并到当前分支
git merge <name>
3.13.6 删除分支
git branch -d <name>
项目分支使用简化版
项目分支使用完整版
master分支:用于版本的更新,当比较大的功能开发完成或者更新之后会有一次集体的发版,就会将所有的代码都合到master(有的公司也会用release分支发版,原理都是一样);
develop分支:一般是开发测试分支,在项目发版上线之前都会现在dev分支上统一进行测试,确保功能达标没有bug之后再推到master分支;
feature分支:用来做分模块功能开发,建议命名为feature-xxx,模块完成之后,会合并到 dev 分支;
hotfix/fixbug分支:是用来做线上的紧急 bug 修复的分支,建议命名为 hotfix-xxx。当线上某个版本出现了问题,将检出对应版本的代码,创建 Hotfix 分支,问题修复后,合并回 dev和master ,这里注意,合并到 master 的时候,一般要打上修复后的版本标签。
扩展阅读:https://blog.csdn.net/langfeiyes/article/details/126068779
3.14 文件冲突
分支1中有个文件跟其他分支文件一样,如果同时发生修改了,进行合并,就出现文件冲突问题。
四、Git可视化操作
上面使用bash命令操作, 接下来,使用TortoiseGit可视化工具再操作一遍Git命令。
4.1 初始化仓库
设置用户名与邮箱
创建空白目录,右键
初始化仓库
空白目录,右键
4.2 添加文件
新建readme.txt文件,执行 add 操作
接着执行commit
操作成功
4.3 查看文件状态
修改一下readme.txt文件, 借助图标观察变化
修改未提交:
修改已提交:
4.4 查看提交日志
选中文件
4.5 查看差异
再修改readme.txt文件,添加:hello git
查看与版本的差异
4.6 版本回退
保存并提交readme.txt改动的数据,此时先回退到没有保存前的版本。
使用show log 查看版本日志
现在想回退到,“修改readme.txt” 版本
选择硬回退
操作完之后,master分支版本就回到上一个版本, show log是看不到当前版本之后日志,只能通过 show reflog才行
4.7 删除文件
删除有2种模式,一种删除版本库,留下工作区的,一个是全删除
工作区删除成功之后,必须提交一次,保证版本库中文件同步删除
4.8 分支管理
创建test.txt文件, 并提交,方便分支创建观察效果。
4.8.1 创建分支
4.8.2 切换分支
4.8.3 查看分支
4.8.4 合并分支
切换到dev分支并创建dev.txt文件,执行add 跟 commit 命令,注意合并前必须提交,保证工作区与版本库一致,否则会出现莫名其妙的问题。
需求: 将dev分支的dev.txt文件合并到master分支中
步骤1:切换到master分支,此时master分支没有dev.txt文件
步骤2:在master分支执行合并
步骤3:合并成功
4.9 文件冲突
步骤1:在master分支修改dev.txt文件,注意: 先修改, 在add, 最后commit, 保证跟版本库一致
步骤2:切换到dev分支修改dev.txt文件,注意: 先修改, 在add, 最后commit, 保证跟版本库一致
步骤3:切换到master分支,将dev分支改动后数据合并到master分支中
合并冲突了
步骤4:解决冲突
五、远程仓库
5.1 远程仓库介绍
到目前为止,我们已经学会了如何在本机利用git进行文件版本管理,但是如果要想进行多人协作,我们就必须使用远程仓库。将本地仓库的数据同步到远程仓库,实现多人协作开发。
一般我们有可能接触到比较多的几种 Git 远程仓库平台:
GitHub:国外/免费创建公有仓库/私有仓库需要收费,在国际上来说 GitHub 是最活跃的开源社区
GitLab:国外/国内免费创建公有仓库/私有仓库需要收费,不过 GitLab 提供了开源版本的企业版本,企业可以部署一套 GitLab 的私服在自己的服务器中
Gitee:国内/免费创建公有|私有仓库/私有仓库限制成员不得超过5人
5.2 Gitee(码云)的使用
GitHub虽然好,在国外的使用率也很高,但毕竟是国外的。在网速上效率还是比较低,经常会出现访问页面变得很慢,下载项目很慢的情况,于是国内慢慢发展起了一个类似
GitHub的
Git` 开源平台 Gitee。官网:https://gitee.com/
5.2.1 注册与登录
要使用 Gitee,首先还是需要创建一个账户,有账户后,直接登录,进入主页
5.2.2 创建项目
5.3.3 项目初始化
项目初始化就是在本地搭建好项目基本功能(比如脚手架),现在需要将该项目推送到远程仓库, 保证团队能共享该项目,这个过程就是项目初始化。简单理解:将本地项目丢到远程仓库
步骤1:初始化git本地仓库
首先进入到你需要进行初始化的项目根目录,并按照如下步骤进行操作:
git config --global user.name "码云上的名称"
git config --global user.email "码云上面注册邮箱"
git init
步骤2:设置提交忽略文件
在项目根目录下创建文件: .gitignore
这一步的意义是为了避免项目中有些本地环境特有的文件被传入到远程仓库,这些文件每个人的电脑都有可能不一致,如果提交到远程仓库,可能会导致出现频繁冲突的问题
# Created by .ignore support plugin (hsz.mobi)
# Operating System Files
*.DS_Store
Thumbs.db
*.sw?
.#*
*#
*~
*.sublime-*
# Build Artifacts
.gradle/
build/
target/
bin/
dependency-reduced-pom.xml
# Eclipse Project Files
.classpath
.project
.settings/
# IntelliJ IDEA Files
*.iml
*.ipr
*.iws
*.idea
步骤3:本地仓库初始化
git add .
git commit -m “项目初始化”
步骤4:配置远程仓库路径(注意是自己建仓库路径)
git remote add origin 你在马云上创建的仓库地址(注意https/ssh方式区别)
步骤5:将本地仓库项目推送到远程仓库
git push -u origin master
步骤6:查看推送结果
重点注意点:存在一部分人https方式无法正常提交,可以参考扩展视频: SSH方式如何进行项目初始化
5.3.4 添加团队成员
创建好项目以后,就可以添加团队成员了,公司的项目通常都是私有仓库,大部分公司会利用类似 Gitlab 的开源平台搭建公司专属的 Git 远程仓库,其配置也基本都差不多,即进入项目管理/设置页面,找到成员管理并邀请成员,为其设置权限等等操作即可
5.3 使用SSH方式操作
进入账号设置页面
左边选择
点击生成公钥
按照操作步骤生成公钥
复制生成后的 ssh key,通过仓库主页 「账号设置」->「SSH公钥」 ,添加生成的 public key 添加到仓库中。
六、IDEA中操作Git
6.1 配置IDEA
6.2 项目克隆
通常来说,进入公司以后会发给你一个远程 Git 仓库的账号密码,以及仓库地址,当你得到仓库地址后,即可在开发工具当中将该仓库下载到本地
注意:在微服务开发或者按模块开发的情况下,因为一个仓库下可能包含多个项目文件,因此建议使用命令 git clone 先将远程仓库克隆到本地,然后再将仓库中的项目一个个导入到 idea
6.3 文件状态识别
在 idea 中,使用不同的颜色来标识文件的不同状态。
通常情况下,有这样几种颜色:
**棕色:**色代表未被 Git 管理(未添加到暂存区)
**绿色:**代表新增的文件且已经被加入到暂存区了
**蓝色:**代表该文件已经提交到远程且该文件被编辑过了
**黑色:**代表该文件在当前版本与远程是一致的
**灰色:**表示该文件之前被提交到仓库过(不管是远程还是本地),但是他已经被删除了
**红色:**表示该文件的内容出现了冲突
创建新文件时,idea 会弹出一个提示框,确认是否要添加到 git 暂存区
6.4 Git操作
6.41 git add–添加暂存区
方式一
方式二
6.4.2 git commit–提交本地仓库
本地提交
方式一
方式二
方式三
点击提交之后
6.4.3 git push–推送远程仓库
远程推送
方式一
方式二
6.4.4 git pull–更新本地仓库
方式一
方式二
方式三
6.5 完整开发流程
步骤1:克隆项目
步骤2:创建自己开发分支
团队开发中有约定, 不能在master分支进行代码编写, 包括自己本地分支,所以开发时需要拉出自己开发分支。
在idea右下角,创建
创建成功之后,会默认切换到新建的分支。
步骤3:在自己本地分支编码
一个需求开发,一般都是自己拉一条分支, 在这个分支中实现自己负责的需求。当开发完成部分独立需求(比如实现某个完整逻辑),可以自己单元测试, 测试通过之后,git add git commit 提交本地自己分支。
这里要注意,必须将自己分支代码,commit之后才能执行步骤4
步骤4:切换到本地master分支
在自己本地分支开发完之后, 测试无bug之后, 保证已经commit之后,切换到master分支
步骤5:将自己分支代码合并到master分支
当自己分支代码ok之后,合并到master分支
步骤6:将本地master的分支推送到远程仓库master分支
注意:自己分支合并到master分支后,需要对自己代码进行测试,测试ok后,如果改动了代码,需要再次commit,然后推送到远程仓库的master分支中。
步骤7:模拟同事合并代码进入远程仓库
公司项目以团队形式进行,你提交的代码,你同事一样提交代码,使用码云仓库控制台模拟同事合并代码进入远程仓库。
编写类名
写好备注
添加成功
步骤8:拉取远程仓库master最新代码到本地master分支
远程仓库代码已经更新,新一天编码开始前,先拉取远程仓库最新代码。注意,最新代码在远程master分支,拉取最新代码应该切换到本地的master分支,然后再执行git pull命令。
步骤9:切换到自己本地分支,合并master,然后继续开发
还是那句,开发只能在自己分支中进行, 步骤8中本地master已经拉取到最新代码,马上切换到自己本地分支,将最新代码合并进来,继续开发。
步骤10:来回重复步骤5到步骤9
后续开发就是步骤5到步骤9的重复啦。
步骤11:本地自己分支远程备份
除了可以将本地master分支推送到远程master分支外,本地自己分支也可以推送一份到远程仓库自己的分支。
自己本地分支推送到远程分支好处:
1>备份
2>天选打工人, 公司没干完活,回家从远程仓库下代码继续开发。
步骤12:最后的注意
为了操作简便性,上课使用master分支存放日常开发成员提交的代码,真实开发不能这么玩,master分支一般存放的都是一些要发布的,或者已经发布的项目版本,不是这些没有经过正规专业测试开发代码。
真实开发使用develop先来存放日常开发代码。所以,到公司之后,必须问清楚开发分支是哪一条。
上面步骤1到步骤11,将master改成develop就可以啦
6.6 文件冲突
Git 文件冲突在2种情况下回出现
1>本地分支间相互合并
2>本地分支与远程分支相互合并
这里演示一下第二种情况。
步骤1:在本地master分支,A.java文件写上下面代码, 然后add, 并commit
步骤2:切换到码云控制台,在远程master分支,改动A.java文件,模拟同事同时修改了该文件
修改文件
步骤3:切换到idea,将本地master分支push到远程分支
解决完冲突之后,再一次push ,将最新代码合并入远程master分支。