<p>自從小學(xué)妹學(xué)完定時(shí)任務(wù)后(詳情請(qǐng)看上篇文章),對(duì)我那是百般仰慕,遇到問(wèn)題第一時(shí)間就會(huì)想到我(是的,要的就是這種效果)。這不,小學(xué)妹今天又找我了,今天的問(wèn)題是什么呢?聽我細(xì)細(xì)道來(lái)...</p><p>原來(lái)小學(xué)妹在公司中,用的是 Git的代碼管理工具(還不知道這個(gè)軟件的要面壁啦~)。有一天不知道發(fā)生什么了,文件夾中所有代碼都被刪掉了,但是只留下本地一個(gè) .git文件夾,這可把小學(xué)妹急壞了,剛寫完一個(gè)大功能,還沒(méi)來(lái)得急提交到遠(yuǎn)程服務(wù)器,明天就要開始內(nèi)測(cè)了,重寫已經(jīng)來(lái)不及了...</p><p>聽完小學(xué)妹的訴求后,我慢悠悠的跟她說(shuō):小事兒一樁,交給學(xué)長(zhǎng),一秒鐘搞定!</p><p>你想知道怎么搞定的?先來(lái)了解下 Git底層代碼存儲(chǔ)原理吧!</p><h2>一、?git工作流程原理分析:</h2><p>假定現(xiàn)在我們有一個(gè) git倉(cāng)庫(kù),在這個(gè) git倉(cāng)庫(kù)中已經(jīng)添加了兩個(gè)文件分別叫做 file1和 file2,兩個(gè)文件中的內(nèi)容分別是 foo和 bar。并且都做了 commit操作。這時(shí)候的圖如下:</p><p><img src="https://upload-images.jianshu.io/upload_images/6620012-c5951aeb8d868612.jpeg" class="uploaded-img" width="auto" height="auto"></p><p>在 Git中,從理解上來(lái)講是分成三種區(qū),分別是<strong>工作目錄</strong>、<strong>暫存區(qū)</strong>以及<strong>Git倉(cāng)庫(kù)</strong>。其中<strong>工作目錄</strong>是我們寫代碼的文件,<strong>暫存區(qū)</strong>是已經(jīng)把代碼進(jìn)行了 add操作,但是并沒(méi)有進(jìn)行 commit操作。<strong>Git倉(cāng)庫(kù)</strong>則是已經(jīng)把代碼提交到倉(cāng)庫(kù)中了,只要倉(cāng)庫(kù)不丟失,代碼是不會(huì)丟失的了。</p><p>再來(lái)理解下 add操作和 commit操作分別做了什么事。用上圖的例子來(lái)說(shuō),工作目錄中包含了 file1和 file2,然后在做 add操作的時(shí)候,理解上來(lái)講是說(shuō)把代碼提交到了暫存區(qū),實(shí)際上 Git是將代碼修改了的部分進(jìn)行了記錄,然后進(jìn)行 SHA1操作,生成了一個(gè) blob對(duì)象( blob是一個(gè)類似文件對(duì)象的二進(jìn)制數(shù)據(jù),不懂可以理解為一個(gè)快照),把存儲(chǔ)到倉(cāng)庫(kù)中了(<strong>注意,此時(shí)代碼快照實(shí)際上已經(jīng)存儲(chǔ)到倉(cāng)庫(kù)中了</strong>),但是并沒(méi)有在目錄樹上進(jìn)行映射,而是在一個(gè)索引文件中進(jìn)行了映射。此后如果我們?cè)賵?zhí)行 commit操作,才會(huì)把索引中的映射,真正更改到對(duì)象樹中,對(duì)象樹會(huì)記錄所有的 commitid與 blob的映射。這樣就實(shí)現(xiàn)了根據(jù) commitid就可以找到對(duì)應(yīng)代碼的功能了。</p><p>來(lái),我們繼續(xù)用圖來(lái)講解一下。</p><p>然后我們現(xiàn)在對(duì) file1文件內(nèi)容進(jìn)行修改,從 foo變成 quux。圖將發(fā)生如下的改變:</p><p><img src="https://upload-images.jianshu.io/upload_images/6620012-6b8005313009a06f.jpeg" class="uploaded-img" width="auto" height="auto"></p><p>我們?cè)賵?zhí)行 git add操作的時(shí)候,圖將變成如下:</p><p><img src="https://upload-images.jianshu.io/upload_images/6620012-7e235a6c3ee780d2.jpeg" class="uploaded-img" width="auto" height="auto"></p><p>在執(zhí)行 git add操作的時(shí)候,會(huì)在倉(cāng)庫(kù)對(duì)象中生成一個(gè) blob對(duì)象,這個(gè)對(duì)象記錄的是與之前文件相比發(fā)生的改變。但是此時(shí)并沒(méi)有生成 commit操作,而是在索引文件中對(duì)其進(jìn)行了索引。</p><p>此時(shí)如果我們?cè)賵?zhí)行 commit操作,那么將變成如下:</p><p><img src="https://upload-images.jianshu.io/upload_images/6620012-25b96fba07b9a010.jpeg" class="uploaded-img" width="auto" height="auto"></p><p>因?yàn)檫M(jìn)行了 commit操作,所以現(xiàn)在生成了一個(gè)新的 commit,這個(gè) commit指向原來(lái)的 commit,并且還指向了新生成的 blob對(duì)象。因?yàn)?file2文件沒(méi)有發(fā)生改變,所以依然還是會(huì)指向原來(lái)的 bar那個(gè)blob對(duì)象。并且做完提交后,當(dāng)前的分支 HEAD指針會(huì)移動(dòng)到現(xiàn)在的 commit。</p><h2>二、?Git倉(cāng)庫(kù)介紹:</h2><p>在了解了 Git的一個(gè)存儲(chǔ)機(jī)制后,我們?cè)賮?lái)看下 .git文件夾中各個(gè)文件夾和文件的作用。</p><p><img src="https://upload-images.jianshu.io/upload_images/6620012-dc4d496127602791.jpeg" class="uploaded-img" width="auto" height="auto"></p><h3>1.?.git/index:</h3><p>索引文件。每當(dāng)我們執(zhí)行 git add操作的時(shí)候, git會(huì)給添加的每個(gè)文件的內(nèi)容創(chuàng)建一個(gè)對(duì)象,然后把這個(gè)文件的路徑和生成的對(duì)象進(jìn)行映射,存放到 .git/index文件中。等到后期新的命令(比如:git add、 git rm或者 git mv)執(zhí)行的時(shí)候,又會(huì)重新更新索引。</p><h3>2.?.git/HEAD:</h3><p>表示當(dāng)前指向的是哪個(gè)分支。</p><h3>3.?.git/config:</h3><p>當(dāng)前 git倉(cāng)庫(kù)的配置文件。保存這 git倉(cāng)庫(kù)的遠(yuǎn)程地址,遠(yuǎn)程倉(cāng)庫(kù)分支等。</p><h3>4.?.git/objects:</h3><p>真正保存代碼的地方。其中分成兩種類型的文件,一種是 pack,另外的是 blob文件。其中 pack是根據(jù)定位內(nèi)容非常相似的全部文件,然后為他們之一存儲(chǔ)整個(gè)內(nèi)容。之后計(jì)算相似文件之間的差異并且只存儲(chǔ)差異。而 blob文件就是記錄差異。blob是“二進(jìn)制大對(duì)象”( binary largeobject)的簡(jiǎn)寫,是計(jì)算機(jī)領(lǐng)域常用術(shù)語(yǔ),用來(lái)指代某些可以包含任意數(shù)據(jù)的變量或文件。</p><h3>5.?.git/logs:</h3><p>這個(gè)地方是記錄分支上做的 commit操作的日志。我們通過(guò) git log命令就可以查看到這個(gè)里面的內(nèi)容。</p><p>我們?cè)诹私馔?Git底層代碼存儲(chǔ)原理后,就不難發(fā)現(xiàn),小學(xué)妹的那個(gè)問(wèn)題,真的不是什么問(wèn)題,只要 .git目錄在,我們的代碼快照、 commit操作, HEAD指針指向,分支等數(shù)據(jù)全都在,這些數(shù)據(jù)都在,我們只要將 HEAD指針重新指向最新的 commit就可以把代碼進(jìn)行恢復(fù)啦。那么答案來(lái)了:</p><ol><li><p>$ git reset --hard HEAD</p></li></ol><p>一行命令搞定,是不是很簡(jiǎn)單?</p><p>吶,如果你覺得 git難用,經(jīng)常會(huì)出現(xiàn)莫名其妙代碼不見了,不知道怎么寫 .gitignore文件,不知道怎么用 git和別人協(xié)作,產(chǎn)生沖突不知道如何解決,經(jīng)常挨領(lǐng)導(dǎo)的批評(píng),那是因?yàn)槟銢](méi)有掌握 Git的正確的用法。作為一個(gè)程序員,不管是做什么開發(fā), Git都是我們工作一項(xiàng)隨身的技能了。如果你不想因?yàn)?Git不會(huì)用而被同事看不起,那么可以來(lái)參加下我們的《4天3晚征服Git》封閉訓(xùn)練營(yíng),只要4天的時(shí)間,讓你的同事刮目相看!</p><p>《4天3晚征服Git》在6月1號(hào)晚上8點(diǎn)30正式開課,其中<strong>3個(gè)晚上全程直播</strong>,4天時(shí)間內(nèi)和課程相關(guān)的問(wèn)題有問(wèn)必答!有美女班主任的花式催作業(yè),同桌學(xué)習(xí)模式,互相監(jiān)督,互相打氣,讓你體驗(yàn)到線下學(xué)習(xí)的氛圍。<img src="https://upload-images.jianshu.io/upload_images/6620012-8b9ee3e83254eea5.png" class="uploaded-img" width="auto" height="auto"><img src="https://upload-images.jianshu.io/upload_images/6620012-1834ac2d8c6a7c85.png" class="uploaded-img" width="auto" height="auto"><img src="https://upload-images.jianshu.io/upload_images/6620012-027264f875ddd49e.png" class="uploaded-img" width="auto" height="auto"><img src="https://upload-images.jianshu.io/upload_images/6620012-c58eb3924d04e5e6.jpeg" class="uploaded-img" width="auto" height="auto"></p>
圖文并茂,詳細(xì)講解Git底層存儲(chǔ)原理
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。