1、Git诞生的历史
-
Git的定义
- Git是当下最先进的开源分布式版本控制系统,可以高效便捷地管理大大小小的项目版本
- 所谓的分布式,按我的理解就是主要专注于分字,分开,分离,把某些事物分开布置在各个角落上,分布式版本控制系统不把相应的版本项目集中在一个电脑/服务器/中央服务器上,而是每个人的电脑都保存着一个完整的版本项目。
- 所谓的版本控制系统,通俗地说就是对一个或若干个文件的内容改动情况按照特定的版本号进行保存,以便将来浏览者快速清晰了解文件的改动信息(内容变化信息,内容改动时间,作者等)
-
Git的缔造者(father)
- 名称:Linus Torvalds 林纳斯 托瓦兹 芬兰人 现受聘于开放源代码开发实验(OSDL:Open Source Development Labs, Inc)
- 他的自传《乐者为王》just for fun 都说一般吊炸天的大牛之牛,脾气都有些古怪,哈哈
-
Git的诞生史
- 1991年,Linus创建可谓统治服务器的操作系统-Linux系统,由于它的快速发展Linux的代码管理成为一个大难题
- 2002年以前,Linus其实都是通过手工方式合并世界各地开发者提交的源代码
- 2002年,名为BitMover的这家公司出于人道主义精神免费提供BitKeeper商业版的版本控制系统的使用权
- 2005年,但由于Linux秀儿众多,开发Samba的Andrew试图Crack BitKeeper的协议,被BitMover公司发现了,于是BitMover公司怒了,要收回Linux社区的免费使用权
- 不让用便自己搞一个,Linus便花费10天的时间用C语言开发了Git,往后时间,Linux的源码都是用Git管理。
- 2008年GitHub网站上线,为开源的项目免费提供Git存储。
2、Git的版本控制系统
-
本地版本控制系统
-
第一代版本控制系统被称为本地版本控制系统。通过加锁将并发执行转换成顺序执行。 一次只能有一个人处理文件。具体流程如下:首先,应该把文件放在一个服务器上,方便使用者上传或下载文件;其次,任何人想对文件修改时,需要先把这个文件加锁,通过checkout指令,使得其他人无法修改;最后,当修改完成之后,需要释放锁,通过checkin指令,形成一个新的版本,存放到服务器端。第一代版本控制系统主要有 RCS( Revision Control System )、SCCS。
-
在硬盘上(本地,local computer)保存补丁集(文件修订前后的变化),通过所有的补丁,可以计算出各个版本的文件内容,大多都是采用某种简单的数据库来记录文件的历次更新差异。
-
-
集中式版本控制系统
-
第二代版本控制系统被称为集中式版本控制系统(Centralized Version Control Systems,CVCS),其对同步修改更加宽容,但有一个明显的限制,用户必须在允许提交之前将当前修订合并到他们的工作中。不便之处就是要联网,若中央服务器发生单机故障,宕机了,那么在这宕机期间谁都无法提交更新,也就无法协同工作,还有中央服务器丢失数据的可能等。
-
由下图可看到,在集中式版本控制系统中,如果服务器嗝屁了,那么所有的开发者就只能干瞪眼了!因为,SVN 对于项目的管理是依赖于服务器中的中心仓库的!我们的更改必须要提交到服务器中的中心仓库。第二代版本控制系统主要有 CVS、Subversion、SourceSafe、Team Foundation Server、SVK。
-
-
分布式版本控制系统
-
第三代版本控制系统被称为分布式式版本控制系统(Distributed Version Control Systems,DVCS),其允许合并和提交分开。在每个使用者电脑上就有一个完整的数据仓库,没有网络依然可以使用。
-
由下图可看到,分布式版本控制系统也可以有个服务器端的仓库,用来同步各开发者的私有仓库。在分布式版本控制系统中,每个参与者的本地也会有一个完整的仓库。及时服务器端崩溃,我们仍然可以使用 Git(仅在本地仓库管理我们的代码),在网络具备时,再和服务器进行同步即可!第三代版本控制系统主要有 Bazaar、Git、Mercurial、BitKeeper、Monotone。
-
思考:
- 怎么理解分布式与集中式?(廖雪峰老师给出的理解)
- 集中式:版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。
- 分布式:分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。
-
SVN与GIT的特性对比:
特性 SVN GIT 架构模式 集中式 分布式 安全性 较差,定期备份 高,开发者本地电脑就是一个完整的版本库 适用性 文档管理, 代码管理, 易用性 简单上手,对新手友好 上手困难,学习成本高但效率搞 灵活性 较低,易发生单点故障,拉取分支 高,单机本地操作,多个备份,本地新建分支 权限管理 拥有严格的权限管理 尚无严格权限管理,有账号角色划分
3、Git与Github、Gitlab
-
GitHub
- GitHub是什么?
- 百度百科上的定义是:面向开源以及私有软件项目的代码托管平台,只支持git 作为唯一的版本库格式进行托管,故名GitHub。
- GitHub是一个代码托管云服务网站,帮助开发者存储和管理其项目源代码,且能够追踪、记录并控制用户对其代码的修改。甚至可以把它当作存储代码等的网盘,用来存储任何东西。
- Github与Git的关系?
- GitHub不等同于Git,二者完全是不同物,不能搞混,类似地,捋一捋java与javascript、周杰与周杰伦的关系,或许你能从中领悟到一些真谛。
- Git只是一个命令行工具,一个分布式版本控制系统。正是它在背后管理和跟踪你的代码历史版本,好比一个时光机,让你在代码出错时不至于手忙脚乱,能快速回退之前的历史版本。
- GitHub是一个代码托管网站,背后使用Git作为版本管理工具(而非svn)。主要服务是将你的项目代码托管到云服务器上,而非存储在自己本地硬盘上。
- GitHub能做什么?
- 托管代码,管理项目的历史版本
- 查找查看开源项目的介绍及源码等
- 使用GitHub Pages更能,能够搭建属于自己的个人博客
- 分享技术心得、项目等,在线交流,提升自己的影响力
- GitHub是什么?
-
Gitlab
- Gitlab是什么?
- GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务(在线代码仓库管理软件)。
- Gitlab与GitHub的区别?查看对比
- GitHub上存放的项目是面向世界开源的,若想存放私人仓库,得交钱,交钱使你的项目变得更隐私
- GitHub是在线代码仓库,全世界只有GitHub一家,大家把代码存储在人家的服务器上
- GitLab比较私密,用于企业、学校或者个人的代码托管库
- Gitlab相当于小型的GitHub,你可以在本地搭建一个属于你自己的类似GitHub仓库,让小伙伴把代码存储在上面,这样代码只有你们几个人能看见,但是你要存在GitHub上,全世界都能看见
- Gitlab能为我们做什么?
- Git仓库管理、代码审查、问题跟踪、动态订阅、wiki等功能,GitHUb能做的Gitlab也能做(99%)。
- Gitlab是什么?
-
国内代码托管平台
4、Git的工作原理
我们使用Git来记录每一次文件内容的变更,版本的更新,清晰地比较出不同版本的内容差异;可以使用Git在项目的历史版本自如地进行切换;还可以使用Git从当前项目的更改中撤销一些操作,可以新建分支,合并分支甚至关联远程服务器仓库等,这一切的背后都是怎么实现的?了解Git的思想以及基本原理这些操作也就略知一二了。
-
Git的分区
- workspace: 工作区 直接编辑的地方,开发者可见具体的项目,可以直接操作项目文件
- index(stage): 暂存区 数据暂存的地方
- repository: 本地仓库 存放已提交的数据
- remote: 远程仓库 在远程服务器上存放本地仓库的数据
-
.git文件夹
-
.git下的文件夹
- hooks 文件夹则存放项目的客户端或服务端钩子脚本
-
info 文件夹下的exclude文件包含项目全局忽略匹配模式,与.gitignore文件互补
- exculd 文件
- logs 保存所有更新的引用记录
- refs
- HEAD # 最后一次的提交信息
- objects 文件夹存储着Git数据库的所有内容,存储所有Git的对象
- info 记录对象存储的附加信息
- pack 以压缩形式(.pack)存储许多对象的文件,附带索引文件(.idx)以允许它们被随机访问
- refs 文件夹存储着所有分支指向各自提交对象的指针;本地分支,远端分支,标签等
- heads 记录commit分支的树根
- master 标识了本地项目中的master分支指向的当前commit的哈希值
- remotes 记录从远程仓库copy来的commit分支的树根(只读)
- origin
- HEAD
- master 标识了远端项目中的master分支指向的当前commit的哈希值。
- origin
- tags 记录任何对象名称(不一定是提交对象或指向提交对象的标签对象)
- heads 记录commit分支的树根
-
.git下的文件
-
HEAD 文件指向当前分支, 包含了一个分支的引用,通过这个文件Git可以得到下一次commit的parent,可以理解为指针
-
index 文件存储着暂存区的内容信息
-
config 文件包含项目的配置信息
-
description 存储着仓库的描述信息,主要给gitweb等git托管系统使用
-
packed-refs 打包标头和标签以便高效的存储库访问
-
FETCH_HEAD 是一个版本链接,指向着目前已经从远程仓库取下来的分支的末端版本
-
ORIG_HEAD 记录的是在进行危险(drastic)操作(如合并merge,回退reset等)时,此操作之前HEAD所指向的位置,便于我们在发生毁灭性失误时进行回退
-
COMMIT_EDITMSG 保存最新的commit message,Git系统不会用到这个文件,只是给用户一个参考
-
-
-
Git数据库
-
Git本质上是一个内容寻址文件系统(就是根据文件内容的hash码来定位文件。 这就意味着同样内容的文件,在这个文件系统中会指向同一个位置,不会重复存储。)Git 的核心部分是一个简单的键值对数据库,可以向该数据库插入任意类型的内容,它会返回一个键值,通过该键值可以在任意时刻再次检索(retrieve)该内容
-
Git 保存的不是文件的变化或者差异,而是一系列不同时刻的文件快照。在进行提交操作时,Git 会保存一个提交对象(commit object)。该提交对象会包含一个指向暂存内容快照的指针。 但不仅仅是这样,该提交对象还包含了作者的姓名和邮箱、提交时输入的信息以及指向它的父对象的指针。
-
git通过一种安全散列算法1(SHA-1)可以得到任意文件的SHA-1哈希值(40位的字符),也就是commit ID,然后通过文件哈希值存取数据,存取的数据都位于objects目录,SHA-1哈希值的前两个字符作为子目录名称,后 38 个字符则作为子目录内文件的名称。
-
Git的数据存储原理
-
Git对象
- 数据对象(blob object) 存储的是一个文件的具体内容
- 树对象(tree object) 存储的文件的目录,一大坨指针,指向子级tree,或者blob
- 提交对象(commit object) 存储作者信息,提交者信息,注释,指向一个 big tree 的指针
- 标签对象(tag object)它包含一个标签创建者信息、一个日期、一段注释信息,以及一个指针。
-
Git的底层命令、高层命令
-
Git常用命令共有30多个,可运行
git help
查看;但Git总共有130多个命令,可以通过git help -a
查看,这些命令可以分为高层命令和底层命令,底层命令被设计成unix风格,不常用- 往Git数据库存入数据
- 往Git数据库取出数据
- 首次提交 testA.txt文件
- 第二次提交,修改了test.txt文件内容
- 第三次提交,增加一个新文件 testB.txt ,一个新目录 lib ,lib 里增加一个文件 testC.txt
- 第四次提交,新建一个分支 branchB,并且在新分支中做了一次 commit
- 第五次提交, 合并一分支
-
-
Git的引用(reference或refs)
浏览完整的提交历史,但为了能遍历那段历史从而找到所有相关对象,需要记住最后提交的SHA-1值。我们需要一个文件来保存 SHA-1 值,并给文件起一个简单的名字,然后用这个名字指针来替代原始的 SHA-1 值。文件被称为“引用(references,或缩写为 refs)”,使用
git branch (branchname)
这样的命令时,Git 实际上会运行update-ref
命令,取得当前所在分支最新提交对应的 SHA-1 值,并将其加入你想要创建的任何新引用中。- HEAD引用
- 分支和标签都是指向提交对象的指针,所有的本地分支都存储在
git/refs/heads
目录下,每一个分支对应一个文件 - Git 分支的本质:一个指向某一系列提交之首的指针或引用
- 分支和标签都是指向提交对象的指针,所有的本地分支都存储在
- 远程引用
- 如果你添加了一个远程版本库并对其执行过推送操作,Git 会记录下最近一次推送操作时每一个分支所对应的值,并保存在
refs/remotes
目录下
- 如果你添加了一个远程版本库并对其执行过推送操作,Git 会记录下最近一次推送操作时每一个分支所对应的值,并保存在
- 标签引用
- HEAD引用
-
-
5. Gitflow工作流
-
Gitflow工作流约定使用的分支简介
-
master分支为项目的核心分支,也是最终对外发布的分支,唯一且稳定。仅提供可读,不可在该分支上直接修改代
-
develop分支是项目的开发主干分支,唯一。仅提供可读,不可在该分支上直接修改代码。新功能的开发需从该分支拉取新的分支展开。develop分支应该包含项目完整的全部历史记录。
-
featrue分支项是目的需求开发分支,可多个,从develop分支或其他featrue分支拉取。程序员的多人分工协作即通过featrue来实现,是代码具体实现的一线程序员接触最多的分支。需求开发完成后,要合并回develop分支。
-
release分支为预发布分支,通常被叫做测试分支,主要用于开发阶段的测试及bug修复。当feature分支开发完毕后会合并回develop分支,然后再从develop分支拉取release分支提测。测试并修复后的release分支要合并回develop分支以及master分支,并打上合适的tag标记(包含必要的releaseNote)。
-
hotfix分支为紧急线上修复分支,即当对外发布的master分支出现重大bug,影响线上使用时,从master分支拉取hotfix分支进行紧急修复。修复后的hotfix分支要合并回master分支和develop分支。
-
-
GitFlow工作流程
然后,开发团队中的其他人克隆中央仓库的develop分支到本地,形成全体成员统一的唯一的develop分支轨迹。之后,按照需求及成员各自的分工,各个成员可以从develop分支拉取出各自的featrue分支(步骤②)进行独立的开发;若涉及到多人合作开发同一分支,拉取的分支要及时推送至服务器,便于各成员共享。
当各成员完成各自的功能开发后,需将完成后的代码提交到featrue分支,然后合并到develop分支(步骤③)。代码合并后,featrue分支可以不再保留。
功能累积足够且稳定或到达约定的提测周期时,项目负责人应当从develop分支拉取出release分支(步骤④),打包提交相应的版本给测试人员进行部署测试,测试中提交的bug全部在该release分支完成修改。
测试结束并完成bug修复后,release分支应该合并回develop分支和master分支(步骤⑤),代码合并后,release分支可以不再保留。合并后的master分支,应由项目负责人及时推送到中央仓库(步骤⑥)。同时全体成员要及时同步自己develop分支。
有上线需求时,直接从master分支打包提交应用版本进行部署。当线上版本出现重大bug,项目负责人需从master分支拉取hotfix分支(步骤⑦),进行线上的紧急修复。
最后,修复后的hotfix分支要合并回develop分支和master分支(步骤⑧)。并推送到中央仓库(步骤⑨)。
6、Git常用命令
-
配置Git-SSH
- 配置Git的user name以及Git要关联的邮箱email
git config --global user.name 'your name'
git config --global user.email 'your email' - 生成密钥
$ ssh-keygen -t rsa -C "your email" 复制代码
- 按三个回车,跳过设置密码,一般我们使用Git不需要设置密码,最终生成id_rsa和id_rsa.pub这两个文件,(若之前就已经生成过这个两个文件,就直接overwrite进行覆盖)
- 登录Github或者Gitlab,添加ssh
打开在windows(c盘)/用户/xxx/.ssh文件夹下的id_rsa.pub文件,复制里面的内容;粘贴在GitHub或Gitlab的setting的ssh key
- 配置Git的user name以及Git要关联的邮箱email
-
简单命令
-
高级命令
-
HEAD
- 总是指向当前分支最新的一次提交commit
- git diff HEAD 显示工作区与当前最新commit之间的差异
-
commit
- git commit --amend -m [message] 修改上一次提交
-
branch
- git branch --track remote-branch 新建一个分支,与指定的远程分支建立追踪关系
- git branch --set-upstream-to=origin/[remote branch] 将remote设置为当前分支的上游分支
-
merge 合并指定分支
-
git merge branch 合并其他分支到当前分支
-
-
rebase 衍合指定分支
-
reset 重置
-
revert 撤销,回滚到指定的特定版本
-
cherry-pick 选择合并某次提交的commit到当前分支
-
reflog 查看HEAD的所有移动轨迹
-
思考:
git merge 与 git rebase 的区别是?
- rebase会合并该分支与其他分支的commit history,可能会得到一个新的commit history
- rebase得到更简洁的项目历史,去掉了merge commi,如果合并出现代码问题不容易定位,因为re-write了commit history
- merge会创建新的commit,包括每个分支的commit 详情
- 每次merge会自动产生一个merge commit,特别是commit比较频繁时,看到分支很杂乱。
- 想要得到一个干净的,没有merge commit的线性commit历史记录,选择git rebase
- 想要得到一个完整的commit历史记录,且想避重写commit历史记录的风险,选择git merge
git reset 与 git rebase的区别?
- git revert会生成一个新的提交来撤销某次提交,此次提交之前的commit都会被保留,也就是说对于项目的版本历史来说是往前走的。
- git reset 则是回到某次提交,类似于穿越时空。
附前端全站书籍PDF文档下载链接:juejin.im/post/5d7216… (要书籍资源的请在下面留言,网盘收集了前后端时髦的书籍电子版)