目录
git工具可以很好的管理我们的项目代码。显然一个大型项目不可能由一个人完成,需要上百人甚至上千人去完成,每个人只完成项目的一个小模块。最后需要将所有的模型合并成最终的项目。在这个过程中必须进行统一管理。如果没有一款管理工具,每个开发人员的想法都不同,这会导致项目的各个子模块乱七八糟的。因此git是一种协助开发人员开发的工具(多人开发)。
一、git概述
git的工作流程:
(1) 每个开发人员的本地仓库都存放着自己所负责的项目子模块代码,开发人员1从本地仓库中checkout出子模块代码到workspace工作区,进行修改代码。
(2)修改完以后,添加到暂存区,然后提交到本地仓库。本地仓库存放着代码不同的历史版本。然后不停的循环。(开发人员一天可能需要提交多次,在第一次提交时需要经过暂存区,后面就不需要了,因为添加到暂存区的目的是让git管理上我们的代码,第一次提交后git已经管理上我们正在操作的代码了,因此后续无需在经过暂存区,直接提交本地仓库即可)
(3)当有别的开发人员(开发人员2)需要用到开发人员1写的子模块时,开发人员1将自己的代码push到远程仓库,开发人员2将代码clone到自己的本地仓库下。然后checkout到自己的workspace。
(4)此时两个开发人员会对同一份代码进行操作。为了保证数据的一致性,开发人员1将自己修改的部分push到远程仓库,开发人员2将其pull下来与自己操作的代码进行合并,然后开发人员2将自己修改的部分push到远程仓库,开发人员1将其pull下来与自己操作的代码进行合并,保证双方数据一致。注意clone是克隆全部代码,pull是只拉取更新的代码
二、git的基本使用方法
1、下载:Git - Downloads
一直点下一步,安装在C盘,因为如果安装在其他盘,后续操作会不方便,安装完成后右键出现:
然后git直接使用不方便可以安装git的客户端:
安装tortoisegit,同样一直点下一步,
如果git安装的是C盘的默认位置,这里不用更改,如果不是默认位置需要手动更改。然后设置自己的用户名与邮箱,方便后续使用git管理项目时,如果git发现某个子模块有问题,git能自动找到负责这个模块的开发人员,并发邮件联系他。(zxy 540664343@qq.com)
安装中文语言包:同样直接点下一步即可,安装完成后,点击鼠标右键:
2、使用git
情形:我们自己是项目负责人,当前的项目完全没有搭建,此时需要使用git创建版本库(搭建环境),版本库就是一个管理仓库(实质就是一个目录),在这个目录下的所有文件都会被git管理起来,每个文件被谁谁谁修改,删除,git都能够跟踪,以便在任何时刻都可以追踪历史或者在将来某个时刻可以“还原/恢复”。git是分布式版本管理工具,不需要联网也具有完整的版本管理能力。
使用git bash创建版本库:在某个目录(工作目录)下右键点击git bash打开命令行,输入git init,此时生成的.git目录就是版本库。
使用TortoiseGit创建版本库:
版本库创建成功,会在此目录下创建一个.git的隐藏目录(这个目录就是版本库,将来所有的项目相关文件都应该在.git目录下受git的管理),与.git目录同级的目录叫工作目录也称工作区workspace(只有工作目录中的文件才能保存到版本库中)。
开发人员1首先从自己电脑的.git目录(本地仓库)中checkout自己负责的子模块代码到workspace,进行修改代码,修改完之后提交到.git目录下。如果开发人员2需要开发人员1的子模块代码,开发人员1将自己.git版本库中的数据push出去,开发人员2将其clone到自己的.git目录下区使用。
将工作区的文件提交到版本库:
(1)在工作区创建一个测试文件mytest.txt(目前该文件与git没有关系,git无法管理),右键将该文件先添加到暂存区(当前文件已经与git有关系了,受git管控)
此时该mytest.txt文件会带有+号标记:
注意可能会存在执行完上述操作没有显示+号标识。解决方法:重启电脑
(2)将该文件提交到版本库:
此时工作区的mytest.txt文件会带有对号标记,说明已经成功提交,工作区的mytest.txt文件与版本库中的mytest.txt文件版本一致。
一旦工作区中的mytest.txt文件有人修改过,会显示!标记,说明git监测到工作区的mytest.txt文件与版本库中的mytest.txt文件不一致了。
此时需要重新提交(不需要暂存区那一步了,因为git已经开启的对该文件的监控)。到这里我们就清楚了,后续所有与项目相关的文件刚开始都是创建在工作区中的,然后将这些文件放到暂存区中开启git对这些文件的管控,然后在提交到版本库,相当于有两份一样的项目一个在工作区中(开发人员操作的),一个在版本库中。后续对每个文件修改了之后进行提交,写好日志即可。如果有别的开发人员要使用我们的代码,我们会将版本库中的那一份代码给他。
补充知识点:对暂存区的理解
Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD:
分支和HEAD的概念我们稍后再讲。上述操作都是建立在TortoiseGit工具上的,所以没有涉及命令的编写,实质上上述做的add操作如果使用原生的git是git add命令,提交是git commit命令。
查看修改历史:
开发人员的每次commit操作,git都会进行日志记录,记录那个用户在什么时间对那个文件进行了什么操作。我们对mytest.txt文件的多次修改提交git都会有记录,我们可以查看历史修改记录:
可以看见上述对该文件的所有历史版本都有记录,此外git还支持对不同版本的记录进行差异比较:
还原修改:
假设我们对项目文件进行了修改,但是发现改的不好,想要进行恢复然后重新修改,此时利用git可以将该文件恢复到离现在最近的提交状态:
删除文件:
需要删除无用的文件时可以使用git提供的删除功能直接将文件从版本库中删除:
假设目前只对版本库中的文件进行了删除,工作区的文件保留。此时git与该文件就没关系了,该文件不受git管理了,+号标记没有了。注意删除操作也是一次修改,同样需要进行提交操作:(注意即使是删除了数据,只要没提交也可以还原到上一次提交状态)
三、案例:将java工程提交到版本库
首先创建一个项目HelloProjet,将其放到工作区中,然后将项目添加到暂存区:
显然这里已经将项目下所有文件或文件夹都添加到暂存区了,git对HelloProjet项目的所有内容都开启了管理。但是实际情况下,并不是所有文件都需要保存到版本库中的例如“.idea”,“out”目录及目录下的文件就可以忽略(“.idea”,“out”,“.iml”都是运行代码后python环境自动生产的一些东西,不能分享。lib与src才是项目所用的jar包和项目代码)。如果直接提交需要手动筛选,每次提交都要手动点一推对勾,很麻烦。
解决方法:在相应的目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件。 如果使用TortoiseGit的话可以使用菜单项直接进行忽略。
完成后在此文件夹内会多出一个.gitignore文件,这个文件就是文件忽略文件,当然也可以手工编辑。其中的内容就是把对应的目录忽略掉:
注意.gitignore文件也需要添加到暂存区, 这样git才知道要忽略那些文件或文件夹
至此,暂存区里有lib,src,和.gitignore。最后提交项目即可。
补充知识:上述操作过程中.gitignore文件是工具自动为我们生产的,当然我们也可以手动的修改.gitignore文件实现对某些文件的忽略:
规则是:
注意上述的所有操作只涉及个人使用,不涉及共享,即远程仓库
四、远程仓库
如果我们想让其他人来协作开发,此时就可以把本地仓库同步到远程仓库,同时还增加了本地仓库的一个备份。 远程仓库一般都是在云上搭建的。常用的远程仓库有
github:GitHub: Let’s build from here · GitHub(国外,开源)
码云: Gitee - 企业级 DevOps 研发效能平台(国内,开源)
默认情况下github与码云上的项目都是开源的,但是它们也支持构建私有项目,需要花钱。这里我们以码云为例来学习远程仓库
1、在码云上创建远程仓库(提前注册码云账号)
注意:一个远程仓库只能存放一个本地仓库
远程仓库就创建好了(git_test.git),接下来需要将自己的本地仓库.git同步到远程仓库:
2、同步
方法一:使用git bash同步(利用命令来实现同步)
git remote add origin 地址 # 只需要执行一次,后续直接push即可
git remote rm origin # 移除已经添加的origin远程仓库
清空远程仓库:(该操作无法恢复,需要进行身份验证才能清空)
注意:远程仓库的地址有两个分别是https和ssh:
不管是GitHub 还是码云, 都支持两种同步方式"https" 和 "ssh",如果使用https地址,则不需要配置就可以使用,但是每次push提交代码和clone下载代码时都需要输入用户名和密码(就是登录码云时的用户名和密码)。如果使用ssh方式就需要客户端先生成一个密钥对,即一个公钥一个私钥。然后还需要把公钥放到githib的服务器上,此时提交和下载代码就不用密码了,例如上述操作就是使用ssh同步的。
配置ssh:
(1)生成本机的ssh公钥密钥
此时本地主机的公钥和密钥就生成了
(2)在远程仓库上进行安全配置,信任那些本地主机
配置好以后,在同步本地仓库代码到远程仓库就可以使用ssh同步方式了,不需要输入密码。
方法二:使用TortoiseGit 工具同步
由于TortoiseGit使用的ssh工具是“PuTTY”git Bash使用的ssh工具是“openSSH”,如果想让TortoiseGit也使用刚才生成的密钥,必须更改TortoiseGit的ssh工具为“openSSH”。
接下来设置远程仓库的地址:
接下来就可以免密同步代码了:
3、从远程仓库克隆
假设开发人员A已经将自己的代码push到远程仓库了,那么开发人员B如何克隆代码呢?我们这里模拟一个开发人员B:
方式一:git bash命令方式
git clone 代码地址
方式二:TortoiseGit工具
注意这里克隆不需要密码,因为这些项目是开源项目。如果不是开源项目使用https需要输入密码,否则需要按上述步骤配置ssh。
接下来双方就不断的进行push,pull操作。注意开发人员B并没有进行任何的ssh等等设置,他只是进行了克隆操作(无需配置)。
4、push与pull过程
开发人员B:
首先,对代码进行了修改:
然后add,commit将修改的内容提交到本地仓库:
其次,进行同步push操作,将新增的内容推送到远程仓库。既然要进行同步操作那么开发人员B也同样需要和上面(2、同步)一样配置ssh才能同步。
开发人员A:
注意:上述模拟的是单方向的,实际生产环境中,开发人员A,B会同时修改代码。这里就不模拟了,假设开发人员B创建了代码bbbb.txt--->add--->commit--->push,远程仓库多了bbbb.txt代码。此时开发人员A并不知道远程仓库多了bbbb.txt文件,没有pull,并且开发人员也创建了cccc.txt文件--->add--->commit--->push(会失败)
出现这种现象的原因是开发人员A的本地仓库与远程仓库的内容版本不一致,开发人员A本地仓库的版本是没有bbbb.txt的版本,而远程仓库是有bbbb.txt的版本,因此在实际生产环境中都是先pull在push。(早上来公司pull,晚上下班之前push)
思考:所有人都是对同一个项目代码进行修改,那很有可能开发人员A,B对同一个文件进行了修改,冲突!!!!,比如A,B对同一个cccc.txt文件进行了修改,此时会出现冲突。
假设开发人员A对cccc.txt已经进行了修改--->commit--->push,在同一时刻开发人员对cccc.txt也进行了修改(修改的位置与A相同)--->commit,但push比开发人员A晚了一步
发现同样无法拉取,这是因为开发人员A,B同时对cccc.txt文件进行了修改,且修改的是同一个位置(开发人员A对cccc.txt代码的2,3行进行了修改,正好开发人员B也是对2,3行进行了修改)。如果修改的位置不同也不会出现冲突。
此时再次打开cccc.txt文件会发现文件的内容也变了
这个时候需要我们开发人员手动解决这个问题:
解决完冲突以后,git并不知道到底解决了没有,此时需要通知一下git冲突解决了:
然后将解决后的cccc.txt--->commit---->push
最后开发人员A在将其pull下就好了,因为已经B已经解决好冲突了。
经验:每天约早push的开发人员往往是最轻松的,反而最后一个push的开发人员可能会面临很多很多很多的冲突,然后加班加班解决完冲突后在push。
五、分支管理
默认情况下git初始化后都会有一个master主分支,后续所有的提交都提交到master分支上,如果当前git只有一个master分支,则开发过程中构建的版本树类似于一条直线,一直向前运行。
如果遇到大型项目的话,只构建一个分支,所有开发人员将自己的代码都提交到同一个分支上,可能会遇到大量的冲突,导致项目无法继续进行,因此我们需要进行分支管理,构建很多分支,每个分支只负责一个小模块:每个分支之间是互不影响的。
1、多分支结构
假设项目经理接手了一个大型项目,此时首先他会创建出git,此时只有master分支,他会在master分支上进行项目的准备工作(初始化):head指针用于标记当前工作的分支,如果head指向了master则后续的所有提交操作会提交到master分支上,如果head指针指向了dev分支,则后续的提交会在dev分支上进行。
项目经理提交了一次操作(项目模板生成),每提交一次相当于生成了一个版本树节点:
基于项目的各个模块,构建不同的分支,在git当中创建分支就是添加一些新的指针。注意master分支主要的目的就是监控项目的进度,以及对各个分支进行合并,形成最后的项目。所有具体的工作都是在其他分支上干的:
开发人员在开发之前,需要将head指针指向dev分支,后续的所有开发的提交都会提交到dev分支下:
同时,测试人员也可以对项目的某些模块进行测试,将head指向test:
假设,开发完成,此时需要将开发dev分支的代码与master分支的代码进行合并:
当test分支的模块代码写完后,同样要和master合并:
此时项目的模块1,模块2完成了如果该项目还有其他模块,我们还可以在次基础上继续在不同的分支上开发,最后合并......。
2、使用TortoiseGit实现分支管理
(1)创建分支
(2)切换head指针(切换分支)
(3)合并分支
随意创建一个文件写一些内容--->add--->commit到dev分支下:
然后切换到master分支下,会发现在dev分支下提交的文件不存在,假设dev分支下开发的模块已经完成,需要与master分支进行合并,完成项目第一阶段的开发(注意分支合并必须切换到master分支下进行):
此时在master分支下就可以看到dev分支下的文件了,因为此时master分支与dev分支指向的是同一个提交节点,head指向master。
然后,如果我们还想接着在dev上开发,首先将head切换到dev分支上,对刚才的文件内容进行修改--->commit:
切换到master后,看不到这个修改,假设我们在master上也对该文件进行了相同位置的修改--->commit到master,然后进行合并,此时会出现冲突:
此时需要手动解决冲突,然后告诉git冲突解决了:并重新提交到master
此时切换到dev,由于上述过程是在master上的操作,因此在dev分支上该文件还是原来的样子,此时在dev分支上合并master分支的数据即可(不需要解决冲突了,因为在master分支上冲突已经解决了)
六、在IDEA中使用git
我们使用pycharm来演示在idea中使用git(所有的其他idea都基本一致),首先在pycharm中创建一个helloworld项目,该项目下随意写一下代码:
(1)创建版本库
接下来在项目的同级目录下创建版本库(使用pycharm来创建),在创建之前要保证pycharm中有git:在pycharm中指定git环境
接下来在helloworld项目的同级目录下创建版本库:
此时helloword项目下的文件变红了,并且pycharm中会新增一些功能:
(2)添加提交到本地仓库
点击--->添加--->提交:
打开项目目录发现有!,这是因为我们只提交了项目的一部分文件,而其他文件并没有设置忽略的缘故。设置将.idea文件忽略掉,然后会生成一个忽略文件,将该文件再次添加-提交即可。
(3)推送push
重新在github或码云上创建一个远程仓库(一个远程仓库只能接收一个本地仓库数据,即一个项目):然后点击推送:
设置推送到哪里,即远程仓库地址:然后点击推送即可。打开远程仓库就可以看到项目了
(4)克隆clone
模拟一个新的开发人员,打开一个新目录git-learn-B,打开pycharm:选择从版本库中获取项目。
然后一直next,.....,finish。接下来就可以双方互相push和pull了