前言Git和SVN同为版本管理系统,只是简单比较一下它们命令的区别。下面我们从原理的角度来分析一下4.git和svn命令我们先来回顾一下gitsvn仓库初始化命令的作用gitinitsvncreateclonegitclonesvnco(checkout)addgitadd(.remove.branch-name>svncpdeletebranchgitbranch-dsvnrmbranchmergegitmergesvnmergeworkspacediffgitdiffer(-cached/head)svndiff更新到历史版本gitcheckoutsvnupdate-rswitchtaggitcheckoutsvnswitchswitchbranchgitcheckoutbranchsvnswitchbranch恢复文件gitcheckout-pathsvnrevertpathdeletefilegitrmpathsvnrm移动文件的路径gitmvpathgitmv清除未跟踪文件的路径gitcleansvnstatussed-e1.存储差异想一想为什么我们一般用git做代码管理,用SVN做原型图和高保真管理?1.git是分布式的,有两种版本库,本地和远程。SVN是centralized,只有一个远程版本库;2、git的内容以元数据的形式存储,所有的控制文件都在.git中,svn是按文件处理的。资源控制文件在.svn;3、svn的分支是一个目录,而git不是;4、git没有全局版本号,svn有;5、git的内容存储使用SHA-1哈希算法,可以保证代码的完整性;6个.git有工作区、暂存区、远程仓库。gitadd将代码提交到暂存区,commit到本地版本库,push到远程版本库。svn添加到暂存,commit提交到远程版本库。所以可以很明显的看出,因为原型图和高保真都是基于单个文件,适合SVN管理,而我们的代码是按照行数来的,适合Git2。.svn和.git文件的区别1..svn目录打开一个.svn目录,可以看到结构:如果看不到.svn,windowcomputer-点击查看-勾选隐藏文件;mac直接shift+command+.├──pristine每个版本记录,这个文件一般比较大├──tmp├──entries当前版本号├──格式文本文件,放一个整数,当前版本号├──wc.db二进制文件├──wc.db-journal二进制文件2..git目录结构你可能对这些目录结构比较陌生,没关系,在终端输入githelpgitrepository-layout回车即可,然后你会发现浏览器会打开一个html文件,其实在git的安装下会打开一个html文件├──hooks钩子文件│├──applypatch-msg.sample│├──commit-msg.sample│├──fsmonitor-watchman.sample│├──fsmonitor-watchman.sample│├──pre-applypatch.sample│├──pre-commit.sample提交触发这个钩子│├──pre-push.sample推送触发器│├──pre-rebase.sample│├──pre-receive.sample│├──prepare-commit-msg.sample│├──update.sample更新触发器├──info│├──排除被忽略的文件├──objectgit数据对象,包括commit,trees,binaryobjects,tags等├──COMMIT_EDITMSG最后提交的注释信息├──log每个refs的历史信息├──refs每个分支指向哪个commit├──config本项目配置信息,包括仓库地址,分支,用户账号等├──description项目描述├──HEADCurrent分支的最后一次提交├──index索引文件,里面存放的是gitadd├──packed-refs分支标识文件,可见git在处理代码上比svn强大3.git文件的动态分析3.1Addstage1.执行gitinit会生成一个初始化的.git,你会发现上面没有目录文件,因为在指定命令后会生成一些文件2.新建一个test.txt,随便写点东西,执行gitstatusOnbranchmaster//DefaultAmasterbranchNocommitsyetUntrackedfiles://uncommittedfiles(use"gitadd..."toincludeinwhatwillbecommitted)test.txt没有添加到提交但存在未跟踪文件(使用"gitadd"totrack)runfind.-typef./config./HEAD./info/exclude./description./hooks/commit-msg.sample./hooks/pre-rebase.sample./hooks/pre-commit.sample./hooks/applypatch-msg.sample./hooks/fsmonitor-watchman.sample./hooks/pre-receive.sample./hooks/prepare-commit-msg.sample./hooks/post-update.sample./hooks/pre-applypatch.sample./hooks/pre-push.sample./hooks/update.sample./index3。执行gitaddtext.txt,显示OnbranchmasterNocommitsyetChangestobecommitted:(use"gitrm--cached..."tounstage)newfile:test.txtrunfind。-键入f./config./objects/61/de0edff4ebeeff225da34006cbe6427638fadc#比之前多一个文件./HEAD./info/exclude./description./hooks/commit-msg.sample./hooks/pre-rebase.sample./hooks/pre-commit.sample./hooks/applypatch-msg.sample./hooks/fsmonitor-watchman.sample./hooks/pre-receive.sample./hooks/prepare-commit-msg.sample./hooks/post-update.sample./hooks/pre-applypatch.sample./hooks/pre-push.sample./hooks/update.sample./index4.总结:可以看出test.txt在gitadd之后被标记为staged,对象多了一个61/de0edff文件,所以对象可以存放git仓库的内容,以二进制方式存放。5.我们可以查看文件的来源gitcat-file-p61de0edfprinttest6。git如何管理和归档文件我们常见的文件系统(NTFS、FAT、FAT32)都是根据地址来检索文件,即先给出一个具体的地址,然后从该地址对应的存储单元中读取文件内容number,而git是基于内容检索的,也就是检索整个内容,得到一个真实的存储位置。类似于哈希映射。3.2提交阶段1.执行gitcommit-m'addtest'1filechanged,1insertion(+)createmode100644test.txt2.运行find。-类型f./test.txt./.git/config./.git/objects/61/de0edff4ebeeff225da34006cbe6427638fadc./.git/objects/ed/fd7e903f8f622f9a52542adfa077552608202d./.git/objects/26/ef8e81bc27b4a67f251145a4f83782364fa9fa./.git/HEAD./.git/info/exclude./.git/logs/HEAD./.git/logs/refs/heads/master./.git/description./.git/hooks/commit-msg.sample./.git/hooks/pre-rebase.sample./.git/hooks/pre-commit.sample./.git/hooks/applypatch-msg.sample./.git/hooks/fsmonitor-watchman.sample./.git/hooks/pre-receive.sample./.git/hooks/prepare-commit-msg.sample./.git/hooks/post-update.sample./.git/hooks/pre-applypatch.sample./.git/hooks/pre-push.sample./.git/hooks/update.sample./.git/refs/heads/master./.git/index./.git/COMMIT_EDITMSG可以看出commit后对象在add的基础上多了两个文件ed/fd7e90和26/ef8e8,从文件的归档路径从命名可以看出git使用SHA-1算法校验文件内容,并且多了一个COMMIT_EDITMSG,里面包含了上次提交的注释信息3.使用gitcat-file查看源码gitcat-file-tedfd7e90//终端输出treegitcat-file-t26ef8e8//终端输出commitgitcat-file-pedfd7e90//终端输出100644blob61de0edff4ebeeff225da34006cbe6427638fadctest.txtgitcat-file-p26ef8e8//终端输出treeedfd7e903f8f622f9a52542adfa077552608202dauthor信息1612668900+0800committerauthor信息1612668900+0800ed/fd7e90是commit对象,tree属性指向26/ef8e8,记录文件操作,作者,committer信息;26/ef8e8是树对象,blob属性指向61/de0edf这个blob对象,记录的是文件名;61/de0edf是一个blob对象,记录了文件的内容。三文件关系:那么现在我们知道为什么目标文件很大。3.3branchgitbranch获取分支列表,保存到refs/heads/master3.4下面的git对象模型通过上面3.2的分析,我们知道git系统中有四种对象:1.commit:指向一棵树,记录文件操作、作者、提交者信息;2.tree:对象关系树,管理树与blob的关系;3.blob:保存文件内容;4.tag:标记提交。3.5git生命周期钩子1.钩子初始化:上面提到的钩子都是生命周期脚本,初始化仓库(gitinit)或者gitclone会初始化.git文件;2、hook是本地的,因为不会提交到代码仓库,但是在clone的时候会初始化;3.hook分类:每次gitcommit前都会触发hook名称函数pre-commit,一个很常见的应用是在package.json中结合husky和lint-staged做代码eslint校验prepare-commit-msg在package.json中被调用pre-commit在文本编辑器中生成提交信息。方便修改自动生成的squash和merge提交commit-msg。在标准提交信息的post-commitcommit-msg后执行,并通知gitcommit的结果。结帐后gitcheckout被调用。推送成功后调用post-receivepush,通知用户推送成功。