做者: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译站