当前位置: 首页 > 后端技术 > Node.js

【前端漫谈】Git内部原理-Git对象

时间:2023-04-03 12:26:32 Node.js

###简介本文是对GitPro10.2Git内部原理-Git对象章节的解读和改造。主要介绍两件事:1)使用Git底层命令完成commit,2)尝试使用NodeJS(文中提供的Ruby)解析Git对象。###0x001初始化一个本地仓库:$mkdirgit-test$cdgit-test$gitinitInitializedemptyGitrepositoryin...查看文件结构:+git-test+.git+branches-config-description-HEAD+hooks+info+objects+info+pack+refs暂时不关注其他的,只关注objects,此时只有info和pack两个文件夹,我们不关注,我们只关注注意除info和pack之外的对象下的变化。0x002hash-object此命令用于计算文件的对象ID,并可能创建blob文件。这里有两层意思:1)计算对象ID,对象ID是什么?2)什么是blob文件?为什么可能?接下来会给出答案。执行命令:$echo'测试内容'|githash-object-w--stdind670460b4b4aece5915caf5c68d12f560a9fe3e4-w指示hash-object存储数据对象,如果不指定则返回计算出来的objectId。--stdin表示从标准输入中读取内容,即测试内容作为内容计算。当我们执行这个命令时,它会返回一个40个字符的SHA1哈希值。d670460b4b4aece5915caf5c68d12f560a9fe3e4,由于制定了-w,git会存储这次的计算,查看objects下的文件:+objects+d6-70460b4b4aece5915caf5c68d12f560a9fe3e4会发现,多了一个文件夹d6,而d6中有一个文件70460b4b4aece5915caf5c68d12f560a9fe3e4,这两者拼接ItlooksexactlyliketheobjectIDjustgenerated.Ifweexecutethiscommandmultipletimes,wewillfindthatthefilehasnotchangedbecauseitalreadyexists,whichisthereasonwhyitmaybegeneratedasmentionedearlier.Ifwechangethecontent,anewobjectIDandanewblobfilewillbegenerated.0x003cat-fileWehavealreadyfiguredouthowtostorefiles,sohowtoreadthem?可以使用cat-file$gitcat-file-pd670460b4b4aece5915caf5c68d12f560a9fe3e4testcontent0x004文件存储和版本恢复接下来我们使用文件,而不直接使用内容$echo'version1'>test.txt$githash-object-wtest.txt83baae61804e65cc73a7201a7252750c76066a30然后更新这个文件并存储$echo'version2'>test.txt$githash-object-wtest.txt1f7a7a472abf3dd9643fd615f6da379c4acb3e3a此时的objects+objects+1f-7a7a472abf3dd9643fd615f6da379c4acb3e3a+83-baae61804e65cc73a7201a7252750c76066a30+d6-70460b4b4aece5915caf5c68d12f560a9fe3e4然后吧文件内容恢复到第一个版本$gitcat-file-p83baae61804e65cc73a7201a7252750c76066a30>test.txt$cattest.txtversion1或者第二个版本$gitcat-file-p1f7a7a472abf3dd9643fd615f6da379c4acb3e3a>test.txt$cattest.txtversion20x005树对象和write-treeAddfilestothecache$gitupdate-index--add--cacheinfo100644\83baae61804e65cc73a7201a7252750c76066a30test.txtWritethecontentsofthecachetothetreeobject$gitwrite-treed8329fc1cc938780ffdd9f94e0d365e79ea74fcat-file-pd8329fc1cc938780ffdd9f94e0d364e0ea74f579100644blob83baae61804e65cc73a7201a7252750c76066a30test.txtCreateanewdataobjectcontainingthesecondversionoftest.txtandanewfile:$echo-xdate>$'newfilecacheinfo100644\1f7a7a472abf3dd9643fd615f6da379c4acb3e3atest.txt$gitupdate-index--addnew.txt$gitwrite-tree0155eb4229851634a0f03eb265b69f5a2d56f341$gitcat-file-p0155eb4229851634a0f03eb265b69f5a2d56f341100644blobfa49b077972391ad58037050f2a75f74e3671e92new.txt100644blob1f7a7a472abf3dd9643fd615f6da379c4acb3e3atest.txt0x006提交commit和commit-tree有了树对象之后,就可以提交该树对象,生成一个commit$echo'firstcommit'|gitcommit-treed8329fb51096bf62fa145c0b95ce18dc3020daa1f2556e查看这个commit$gitcat-file-pb51096bf62fa145c0b95ce18dc3020daa1f2556etreed8329fc1cc938780ffdd9f94e0d364e0ea74f579authorScottChacon1243040974-0700committerScottChacon1243040974-0700firstcommitthencommitthesecondtreeobjectanduse-p指定这个提交的上一个commit$echo'secondcommit'|gitcommit-tree0155eb4229851634a0f03eb265b69f5a2d56f341-pb51096bf62fa145c0b95ce18dc3020daa1f2556ebf41fa3700a67914b3b45eefced02fffcdaf4464使用gitlog查看记录commitbf41fa3700a67914b3b45eefced02fffcdaf4464Author:lyxxxxDate:SunNov1722:14:36??2019+0800secondcommitnew.txt|1+测试.txt|2+-2个文件更改,2个插入(+),1个删除(-)提交b51096bf62fa145c0b95ce18dc3020daa1f2556e作者:lyxxxx日期:2Sun2Nov17:012019+0800firstcommittest.txt|1+1filechanged,1insertion(+)以上,是使用底层命令创建Gitcommithistory的过程,主要涉及5个命令:hash-object:计算objectID,创建blob文件cat-file:读取产生的object文件update-index:更新暂存区文件write-tree:将暂存区文件写入树文件commit-tree:提交树文件0x007objectfiletypeobject文件类型一共有三种:blob:generatedbyhash-object,表示一个文件树:由write-tree生成,表示缓存中的文件列表commit:由commit-tree生成,表示本次提交的文件列表。他们的关系是:commitcontainsatreeobjectThetreecontainsmultipleblobobjectsandtreeobjects0x008objectID是如何生成的接下来用NodeJS演示如何生成objectID,假设我们要存储的内容是什么,博士?constcontent='怎么了,医生?consttype='blob'object对象存储格式为:conststore=`${type}${content.length}\0${content}`然后计算sh1值:constcrypto=require('crypto');consthash=crypto.createHash('sha1');hash.update(store);constobjectID=hash.digest('hex');最终的计算结果为:bd9dbf5aae1a3862dd1526723246b20206e5fc37接着进行存储。存储时,会在存储前进行压缩:constzlib=require('zlib');constresult=zlib.deflateSync(Buffer.from(store))然后根据objectID划分存放到objects文件夹中:+objects+bd-9dbf5aae1a3862dd1526723246b20206e5fc37完整源码:constzlib=require('zlib');constfs=require('fs');constBuffer=require('buffer').Bufferconstcrypto=require('crypto');consttype='blob'constcontent=process.argv[2]conststore=`${type}${content.length}\0${content}`consthash=crypto.createHash('sha1');哈希。update(store)constobjectID=hash.digest('hex')constresult=zlib.deflateSync(Buffer.from(store))constpath='.git/objects'const[a,b,...文件]=objectIDconstdirPath=`${path}/${a}${b}`constfilePath=`${dirPath}/${file.join('')}`fs.mkdirSync(dirPath)fs.writeFileSync(filePath)0x009Resource官方文Git原理介绍-阮一峰本章源码:我会继续维护这个项目,慢慢尝试用NodeJS写一个miniGit来玩玩。一个非凡的React微场景编辑器。