git简介
Git是目前世界上最骚,最先进的分布式版本控制系统,说到分布式管理系统那就不得先提下集中式管理系统,最典型的当属我们常用的svn。
-
什么是集中式管理系统
集中式版本管理系统版本库是集中存放在中央服务器的(例如公司的一台svn远程服务器),而我们开发的时候,用的都是自己的电脑,所以开发前要先从中央服务器取得最新的版本,然后开始编码,干完活了,再把自己的代码推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。
-
什么是分布式管理系统
分布式的版本控制就是每个人都可以创建一个独立的代码仓库用于管理,各种版本控制的操作都可以在本地完成。分布式版本控制系统根本没有"中央服务器",每个人的电脑上都是一个完整的版本库,这样你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上,我们每次提交都只需要先提交到本地就行。当多人协作开发时。可以将自己的修改推送给对方(当然实际开发中是没得傻帽这样做的)。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。
-
分布式管理系统PK集中式管理系统
-
集中式管理系统(举例svn)的优缺点
优点:-
管理方便,逻辑明确,符合一般人思维习惯。
-
易于管理,集中式服务器更能保证安全性。
-
代码一致性非常高。
-
适合开发人数不多的项目开发。
缺点:
-
必须联网才能工作,网络不好的时候很难受。
-
服务器一旦宕机风险极大。
-
svn按文件存储,服务器压力太大,按照原始文件存储,体积较大。
-
分支是一个完整的目录,且这个目录拥有完整的实际文件,创建新的分支则所有的人都会拥有和你一样的分支,一下载就是整个目录的代码,不能安安静静的做个美男子。
-
-
分布式管理系统(举例git)的优缺点:
优点:
-
每一个开发人员的电脑上都有一个仓库,没有网络也可以commit,查看历史版本记录,创建项目分支,等网络再次连接上Push到远程服务器,而svn网络不好或者没网了啥也干不了。
-
git按照元数据方式存储,体积很小,“.git”目录是处于你的机器上的一个克隆版的版本库,它拥有中心版本库上所有的东西,例如标签、分支、版本记录等。
-
可以任意在自己的本地版本库开启无限个分支,别人并看不到,可以安安静静做个美男子,等到所有的做完了再推送到远程服务器,并且这个不需要这个分支时从本地版本库删除这个分支即可。
-
代码提交速度快、灵活,提交到本地仓库比本地复制还快,与svn不同的是git是先提交到本地仓库(其实已完成了提交),推送到远程仓库其实是在执行同步操作。
缺点::
-
学习周期相对而言比较长。
-
不符合常规思维。
-
代码保密性差,一旦开发者把整个库克隆下来就可以完全公开所有代码和版本信息。
-
-
安装git
主要基于windows系统上的安装简单说明(用Linux的大神和Mac的土豪略过)
在Windows上使用Git,可以从Git官网(https://git-scm.com/downloads)直接下载安装程序,(网速慢的同学请移步国内镜像),然后按默认选项安装即可。 安装完成后,在开始菜单里找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明Git安装成功!
因为Git是分布式版本控制系统,所以,每个机器都必须自报家门:你的名字和Email地址,我们需要在gitBash中配置自己在姓名和邮箱(例如gitlab上面的用户名和邮箱)。
$ git config --global user.name “zhengzhao”
$ git config --global user.email "zhengzhao@dtinsure.com"
注意git config命令的–global参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址,做法是在项目根目录下进行单独配置,不加–global。
$ git config user.name “zhengzhao”
$ git config user.email "zhengzhao@dtinsure.com"
创建版本库
生成本地仓库
第一步、在本地创建一个空目录,windows系统上确保目录名(包括父目录)不包含中文。
第二步、通过git init命令把这个目录变成Git可以管理的仓库。
.git目录
主要包含HEAD,config,description文件和branches、hooks、info、objects、refs五个文件夹。
- hooks存放一些钩子脚本。
- info文件夹是全局性排除文件,它和.gitignore是互补的。里面就一个exclude文件。
- objects存放所有数据。
- refs 提交对象的指针。
- 其中config是项目特有的Git配置文件。
- description但是GitWeb专用的文件。
- HEAD记录当前被checkout的分支。
git提交文件到版本库
- 在git仓库下新建一个本地文件test1.txt。
- 用命令过git add 文件名告诉git,把文件添加到仓库暂存区(后面细讲),然后git commit,将文件提交到仓库,- m后面输入的是本次提交的说明。用命令提交必须先add在commit,使用工具tortoisegit可以直接commit(应该是工具做了优化,commit时必须写提交信息)。
- 用add可反复多次使用,添加多个文件,再使用commit全部提交。
版本管理
版本回退
版本管理这块的讲解就不用命令去说了,对于我们小白来说大部分还是用工具来完成的,主要讲讲用工具去回退,命令回退这块大家可以去廖雪峰老师的博客上看看
- 右键项目,选择TortoiseGit,然后点击 show log。
- 选中需要回退到的代码版本。
- 选择 “Reset "master to this”。
- 选择hard 。
最后我们打开log会看到head指向的是第四次提交,第五次提交没了,head指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭。
工作区和暂存区
工作区
电脑中存放文件的目录,例如我电脑中的E:\gittest目录,.git目录不是工作区,因此我们不要在里面工作,它是我们的版本库。
暂存区
Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。
我们把文件往Git版本库里添加的时候,是分两步执行的:
第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。
简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
底层实际实际操作(用命令执行)上面必须先add到缓存区然后commit到版本库,add代表的意思不是新增的文件而是一个将工作区内容add到暂存区,因此底层上哪怕修改的文件也要先add,我们平时使用的工具例如TortoiseGit一般是直接可以commit,这是由于它内部先执行了add操作。所以,git add命令实际上就是把要提交的所有修改放到暂存区(Stage),然后,执行git commit就可以一次性把暂存区的所有修改提交到分支。
分支管理
分支的创建、合并及解决冲突
在我们创建git仓库的时候我们处于git的主分支即master分支,在远程服务器gitlab上创建项目同样也是默认在主分支master。最开始的时候master分支是一条线,git用master指向最新的提交,在用HEAD指向master,即可确定当前分支。上面有说道在git中用HEAD表示当前版本,即最新的提交,它是一个指针。
每次提交,master都会向前移动,然后HEAD指向当前分支中最新的版本。
大家可能会觉得那我新建一个分支呢,是不是有两个HEAD呢?不是,当我们创建新得分支develop,这时候develop指向master相同的提交,我们切换到develop分支,这时候HEAD会指向develop,就表示当前分支在develop上面,所以git中创建分支非常快速方便,只是增加了一个develop的指针改变了HEAD的指向,工作区的文件没有发生任何变化,不像svn那样每建一个分支都是要重新建一个目录,然后将文件全拷贝到新的分支目录中,所以git中鼓励大量使用分支。
当我们切换到develop分支后,对工作区的修改和提交就是针对develop分支了,没新提交一次,develop指针往前移动一步而master指针不变
当我们在develop分支上完成了工作,就可以把develop分支合并到master上面来了,先切换到master,这时候HEAD指向哪里?(坐等大家回答),我们在master上面合并develop,并没有把develop的文件改动合并到master,这是为什么?很简单,不要局限于分布式管理系统的思维,它是将指针从master主分支最后提交那个位置指向到了develop的当前的提交,因此git的合并只是改改指针,非常快速方便。
下面我们开始用工具tortoisegit实战演练:
-
在master主分支下创建文件,并提交,此处就不展示图形了,新建文件test1.txt后直接用工具commit就行。
-
创建分支develop,右击选择Create Branch。
-
切换到develop分支,右击选择Switch/CheckOut,然后选择develop分支即可。
-
我们对文件test1.txt进行修改并commit,再切回到master分支,master分支中test1.txt是空的。
-
我们此时在master分支开始合并,git的合并规则是在当前分支上合并其他分支,我们此时在master主分支上面,右击选择Merge,并选中要合并的分支develop,点击ok,那么我们合并成功,在master分支中可以看到test1.txt文件中有了修改。
-
说道合并就不能不说说解决冲突,大家都绕不过去的坎,我们在master分支上将test1.txt文件修改下,并提交,再切换到develop分支上修改文件并提交,再切换到master上面合并develop分支,这时候test1.txt文件就报冲突了。
-
如何解决呢?选中冲突的文件右击选择edit conficts处理完冲突后选择mark as resolved标记此文件冲突已解决,然后提交。
###分支管理策略
此处推荐一片文章,实际工作中的分支使用讲的贼好,我就偷个懒
https://blog.csdn.net/shusheng0007/article/details/80791849
远程仓库
创建远程仓库
上面说过git严格意义上是没有中央服务器的,每个个体本地电脑上都有一个仓库,但是一方面为了整体的管理(集中式的优点),另一方面也是照顾大家正常逻辑的使用习惯,一般都会在远程服务器上托管,比较常见的例如全球最大同性交友网站github,码云(国内版的github),gitlab(github被微软收购后崛起),以下我们就以gitlab为例简单说明下。
-
注册并登陆gitlab(此处略过~)。
-
新建项目,不过为了方便管理我们新建项目之前一般都要新建群组,群组你可以理解为一个可以设置用户访问权限的文件夹。
-
群组的管理,我们进入群组在成员列表可以邀请成员并分配权限,权限说明如下:
-
在群组中创建项目,创建成功后会展示如下,下面是我建的项目地址testgroup是群组,testproject是项目名,项目地址有HTTP和SSH两种方式,可发送给开发人员下载和初始化项目。(提示:通过SSH方式拉取推送项目代码必须要导入SSH key,这个稍后再介绍)
HTTPS:https://git.dtinsure.com/testgroup/testproject.git
SSH:git@git.dtinsure.com:testgroup/testproject.git
-
生成SSH key并且配置到gitlab上
-
此时远程仓库默认的是主分支master,在远程仓库gitlab上面创建分支
-
配置用户名和邮箱
git config --global user.name “zhengzhao”
git config --global user.email "zhengzhao@dtinsure.com"
-
将远程仓库clone到本地,进入本地的一个文件夹,用工具tortoisegit右击 git clone,或者骚一点用命令去clone
git clone https://git.dtinsure.com/testgroup/testproject.git
-
唉,这是后你会发现一直要你输密码,你输账户登录密码还是会报错,我也不太清楚这个到底该输那个密码,别急我们有更好的免密方式,生成秘钥配置上去,直接用命令就不用tortoisegit(工具生成秘钥要麻烦很多)了,右击打开git bash输入以下命令,然后一直enter。
ssh-keygen -t rsa -C "zhengzhao.email@dtinsure.com" -b 4096
-
成功后显示如下图,然后我们将生成的公钥配到gitlab上。
-
我们再次重复步骤7去clone即可将远程仓库clone到本地。
-
这时候我们本地仓库和远程仓库都是空的,因此我们新建一个文件推送(push)到远程仓库,注意流程是先add到暂存区(用工具省略这一步),然后commit到本地仓库,然后push到远程仓库。
注意:在push到远程服务器时一定要先从远程服务器pull或者fetch。 -
pull(拉取)和fetch(获取)的区别,若是中文版的tortoisegit工具一定要注意这点,尽量按装英文版的工具。
- pull(拉取),从远程服务器上拉取分支并直接合并到当前分支上,这个类似svn的update。
- fetch(获取),从服务器上获取分支在本地生成一个新的分支FETCH-HEAD,不会自动合并,需要手动将master和FETCH-HEAD分支合并。
fetch相对而言要安全些,但是繁琐一些,我们一般采用pull(拉取)即可。
-
远程仓库创建新的分支develop,如何将远程分支develop同步到本地仓库呢?这时候我们不能用步骤7去clone,因为clone的是整个仓库而不是某一个分支,我们在本地仓库同样根据本地master主分支创建一个分支develop,并且在master上pull(拉取)远程master,就可以将远程仓库branch信息拉取到本地,这样我们本地仓库master和远程仓库master,本地分支develop和远程分支develop就一一对应上了。