Git 是一个强大的工具,但是使用起来却不是很友好。如果程序员们能够真正花时间去理解 Git 的构成,将会避免很多不必要的麻烦。
以下为译文:
初学 Git 就像一个不懂当地语言的人来到一个陌生的国家——如果你知道自己在哪,该去哪里,那还好。一旦你迷路了,那麻烦就大了。
网上有很多学习 Git 基本命令的文章,但是本文并不属于这一类文章。我在此处将尝试提供一个不同的学习思路。
初学者一般都很害怕 Git,很难不怕。毫无疑问,Git 是一个强大的工具,但是使用起来却不是很友好。使用 Git 要理解很多新的概念,将文件作为命令参数和不作为参数两者的含义大相径庭。
我认为要想克服这些困难,不仅要学习 Git 的 commit 和 push 的用法。如果我们能够真正花时间去理解 Git 的构成,将会避免很多不必要的麻烦。
当你通过
git init
创建 git 仓库时, git 就会创建 .git 目录。
该目录包含让 git 能够正常工作所需的所有信息。
直白点说,如果你不想在项目中继续使用 git ,直接将 .git 目录删除只保留项目文件即可。
但是为什么这样做就可以呢?
├── HEAD
├── branches
├── config
├── description
├── hooks
│ ├── pre-commit.sample
│ ├── pre-push.sample
│ └── ...
├── info
│ └── exclude
├── objects
│ ├── info
│ └── pack
└── refs
├── heads
└── tags
-
-
该文件包含你的仓库配置,比如远程的 url ,你的邮箱和用户名等。
每次你在控制台使用
git config...
都会对这里产生影响。
-
供 gitweb ( github 的一种前身) 使用,显示仓库的描述。
-
这是一个有趣的特性。
Git 提供了一套脚本,可以在每个有意义的 Git 阶段自动运行。
这些被称为钩子的脚本可以在提交 (commit)、变基 (rebase)、拉取 ( pull ) 操作的前后运行。
脚本命预示着它的执行时机。
如我们可以编写 pre-push 的作为钩子,进行推送代码前的检查。
-
你可以将不想被 git 管理的文件记录到 .gitignore 文件中。
排除文件的意思是不想共享这个文件。
例如你不想共享你的 IDE 自定义配置,将其添加到 .gitignore 文件中即可。
每次你创建一个文件,并追踪它,git 都将把文件进行压缩并存储在自己的数据结构中。
被压缩的对象将具有唯一的名称和 hash 值,并将存储到对象 (object) 目录中。
在研究对象目录之前,我们必须明白一次提交的含义是什么。你可能会说,一次提交就是当前工作目录的一个快照,但事实远不止如此。
实际上,当你提交时,git 通过下面两个步骤对你的工作目录创建快照:
这里给出一个简化的过程,实际上整个过程有点复杂,将在以后的文章中给出详细的介绍。
一旦快照被创建出来,它将会被压缩,以哈希值命名。
那么这些压缩的对象存在哪里呢?
他们被存在 object 文件夹中。
├── 4c
│ └── f44f1e3fe4fb7f8aa42138c324f63f5ac85828 // hash
├── 86
│ └── 550c31847e518e1927f95991c949fc14efc711 // hash
├── e6
│ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391 // hash
├── info // let's ignore that
└── pack // let's ignore that too
这是我创建了一个空的文件 1.txt 并提交后 object 文件夹的样子。
请注意,如果你的文件哈希值为 "4cf44f1e…",git 会将其存储到 "4c"子目录中,并将其命名为"f44f1…"。
这个小技巧,将
/objects
目录的数量减少到 255 个以内。
-
-
-
-
// 通过查看提交历史,你可以轻松地查询到提交的哈希值
// 你都不需要复制完整的哈希值字符串,
// 复制能够保证哈希值的唯一性的前面一段即可。
git cat-file -p 4cf44f1e3fe4fb7f8aa42138c324f63f5ac85828
tree 86550c31847e518e1927f95991c949fc14efc711
author Pierre De Wulf <test[@gmail.com](mailto:pierredewulf31@gmail.com)> 1455775173 -0500
committer Pierre De Wulf <[test@gmail.com](mailto:pierredewulf31@gmail.com)> 1455775173 -0500
commit A
正如预想的一样,我们看到了快照的哈希值、作者信息和提交的注释。
git cat-file -p 86550c31847e518e1927f95991c949fc14efc711
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file_1.txt
我们找到之前存储的最后一个对象,也是我们快照中的唯一的一个对象。
它是一个 blob 对象,这是另外的知识点,不在这里讨论。
你现在已经了解到,git 中的所有内容都可以通过正确的哈希值来获取到。
现在让我们聚焦于 HEAD。
那么什么是 HEAD?
cat HEAD
ref: refs/heads/master
HEAD 不是一个哈希,HEAD 可以理解为指向你正在使用的分支的顶端的指针。
我们接下来看下 refs/heads/master:
cat refs/heads/master
4cf44f1e3fe4fb7f8aa42138c324f63f5ac85828
看起来眼熟吗?
这和我们第一次提交的哈希值相同。
这表明分支 ( branch) 和标签 (tag) 只不过是一个指向提交的指针。
这就意味着,即使你删掉了你要删除的分支和标签,他们指向的提交依然还在那里,只不过删除后难获取这些提交更困难一些。
如果你想了解更详细的内容,可以通过
git book
来学习。
所以学到这里,你应该明白 git 提交就是把你当前工作目录的文件“压缩”,然后将其和其他信息一起存储到对象文件夹中。
如果你对 git 足够熟悉,你就会知道哪些文件会包含在提交中,哪些文件不会被提交。
我这里说的提交,并不是指你的工作目录快照,而是指你要提交的文件快照。
在实际执行之前,git 会在哪里存储你要提交的文件?
它将他们存储到索引文件中。
不过,我们暂时不打算深入研究它。
如果你真的感兴趣,可以通过
这里(https://github.com/git/git/blob/master/Documentation/technical/index-format.txt)
深入学习。
感谢阅读!
希望通过阅读本文,你能够学到有价值的内容。
希望本文能够帮你更轻松地使用 git。
原文:https://www.daolf.com/posts/git-series-part-1/
译者:明明如月,知名互联网公司 Java 高级开发工程师,CSDN 博客专家。