做者:Maxence Poutord
來源:dev.to
翻譯:1024譯站git
現在大多數項目都使用 Git 做爲版本控制系統,這意味着大多數項目都有一個.git
文件夾。可是,你有沒有嘗試過打開它?shell
我試過一次……而後在一分鐘內就關掉了!bash
「這是GIT。它經過一個漂亮的分佈式圖論模型跟蹤項目中的協做工做。」
「哇,好酷!怎麼用的呢?」
「母雞。只需記住這些 shell 命令並輸入它們來同步。若是出現錯誤,那就把代碼保存到其餘地方,刪掉項目,再下載一份新的。」app
直到一年前。我對這種知其然、不知其因此然的作法感到厭倦。最後我找到了機會,開始學習它。 我看了《Pro Git》這本書,並進行了大量實驗。我發現它並不像看起來那麼複雜!分佈式
所以,若是你:學習
.git
文件夾裏有什麼這篇文章就是爲你寫的!fetch
爲了便於理解,我會從一個基礎項目開始(有2個文件: index.js
and README.md
)。ui
git init
echo "console.log('hi')" >> index.js
echo "# Cool project" >> README.md
git add . && git commit -m "First commit"
如今咱們來看看.git
文件夾裏的內容:spa
$ tree .git/objects
.git/objects
├── 2d
│ └── 1a41ebd2d32cb426b6d32e61e063f330aa1af8
├── 66
│ └── 87898e2a0fe2da282efab6b5f7f38b7f788f56
├── c2
│ └── 43f24fb294ebc954b0a7ee6020589245f78315
├── c3
│ └── 0500babf488d06033e8d039cbf64be3edbd089
├── info
└── pack
6 個目錄,4 個文件
複製代碼
Git 建立了4個文件。爲了不一個文件夾包含太多文件,git 會自動截取前兩個字符做爲文件夾名。要檢索一個 git 對象,必須將文件夾名+文件名拼接起來。
因爲這些文件不具有可讀性,你能夠用命令git cat-file <sha-1> -p
查看裏面的內容(或者用 -t
參數查看類型)。順便提一下,只能用前 8 個字符。
Git 對象模型有 4 種不一樣類型:
請注意,blob 不存儲文件名(和位置)。這就是爲何當你更改文件位置時 git 會丟失歷史記錄的緣由之一。
🤔若是你在本機運行,可能會獲得不一樣的 hash 值(做者和日期不同)!
如今咱們要更新 index.js
,給文件再添加一行:
echo "console.log('world')" >> index.js
git add . && git commit -m "Second commit"
因而又多了 3 個 對象:
$ tree .git/objects
.git/objects
├── 11
│ └── 75e42a41f75f4b25bab53db36d581f72387aa9
├── 2d
│ └── 1a41ebd2d32cb426b6d32e61e063f330aa1af8
├── 66
│ └── 87898e2a0fe2da282efab6b5f7f38b7f788f56
├── c2
│ └── 43f24fb294ebc954b0a7ee6020589245f78315
├── c3
│ └── 0500babf488d06033e8d039cbf64be3edbd089
├── ee
│ └── c2cd5e0b771793e03bbd5f8614c567af964a4e
├── fc
│ └── 512af17ca7ec04be6958047648b32629e4b5a5
├── info
└── pack
9 個目錄,7 個文件
複製代碼
這裏有意思了:Git 並無存儲文件之間的差別!幸好有packfiles (位於 .git/objects/pack
),Git 在硬盤上保留了一個合理的位置。
在最後一步,咱們將添加一個提交。而後,咱們將回到過去以「刪除此提交」。
echo "console.log('')" >> index.js
git add . && git commit -m "Third commit"
你可能猜到了,git 建立了3個新文件。結構跟第二步的相似。
.git/objects
├── 00
│ └── ee8c50f8d74eaf1d3a4160e9d9c9eb1c683132
├── 09
│ └── f760de83890e3c363a38e6dc0700b76e782bc1
├── cf
│ └── 81d6f570911938726cff95b62acbf198fd3510
└── ...
12 個目錄, 10 個文件
複製代碼
如今,咱們僞裝想回退一個提交(git reset HEAD~1 --hard
)。
如今你可能會認爲,你搞砸了一切,提交記錄再也找不到了。是否是?
多是。讓咱們看看還有多少個 git 對象……
$ tree .git/objects
.git/objects
└── ...
12 個目錄, 10 個文件
複製代碼
看到沒,咱們還有10個文件!沒有被刪!你猜怎麼着?若是我用命令git cat-file cf81d6f570911938726cff95b62acbf198fd3510 -p
,我還能查看第三次提交的 index.js 文件內容。
"在 git 裏你不可能丟失代碼。"
——魯迅
比這更嚴重的是,我天天使用git push --force
,git rebase
和git reset --hard
,但我歷來沒有丟失任何東西。可是,咱們是人類,人類是容易犯錯的。
別擔憂,若是你想回滾,不用丟棄全部文件。接下來就是見證奇蹟的時刻!
若是你嘗試使用git log
檢索歷史記錄,則不會看到「Third commit」 這個提交。可是,若是加了參數-g
(表明 --walk-reflogs
),就會看到第三個提交。
爲了讓結果更好看,你能夠用 git log -g --abbrev-commit --pretty=oneline
。
這個超有用的命令有個別名:git reflog
❤️
$ git reflog
eec2cd5 (HEAD -> master) HEAD@{0}: reset: moving to HEAD~1
00ee8c5 HEAD@{1}: commit: Third commit
eec2cd5 (HEAD -> master) HEAD@{2}: commit: Second commit
c30500b HEAD@{3}: commit (initial): First commit
複製代碼
(注意:在 .git/logs/HEAD
裏能夠看到相似的結果)
如今,你有了第三個提交的指紋: 00ee8c5
。你能夠用 git reset 00ee8c5 --hard
來撤銷以前的重置。
注意事項:
在某些狀況下,git reflog
對你沒有幫助:
git gc
清理掉了 )。我不知道大家的狀況,反正我連一個月前作了啥都不記得了。因此記錄保存3個月應該足夠了。另外,若是你像 ctrl + s
同樣使用 git commit,就可能很容易犯迷糊。很抱歉,除了建議你閱讀個人那篇有關 conventional commits 的文章外,我也無能爲力。我認爲這是使用 git 最乾淨的方法。
commit
,tree
,blob
和tag
blob
並不存儲文件名(這就是爲何移動文件後會丟失歷史)git reflog
能幫到你。獲取更多技術趨勢和資源,歡迎關注微信公衆號:1024譯站