哇欧,我才读了 git 的快速入门指南就觉得它简直酷毙了,现在使用起 git 来感觉超舒服,妈妈再也不担心我会捅出什么篓子了。”—— 某位无名英雄曾曰过
新人刚使用 git 的时候,就像去到一个既不识当地文字也不会说当地语言的陌生的国家。只要你知道你在什么地方、要去哪里,一切都 OK,而一旦你迷路,麻烦就来了。
网上已经有许多关于学习基本的 git 命令的文章,但是本文不属于这一类,而是尝试另辟蹊径。
新手总是被 git 吓到,事实上也很难不被吓到。可以肯定的是 git 是很强大的工具但还不够友好。大量的新概念,有些命令用文件做参数和不用文件做参数各自执行的动作截然不同,还有隐晦的回馈等…
我以为克服第一道难关的方法就是不仅仅是使用 git commit/push 就完了。如果我们花点时间去真正了解到底git是由什么构造的,那将会省去不少麻烦。
初探 .git
那么我们开始吧。当你创建一个仓库的时候,使用 git init 指令, git 将会创建一个神奇的目录:.git。这个目录下包含了所有 git 正常工作所需要的信息。说白一点,如果你想从你的项目中删除 git 但是又要保留项目文件,只需要删除 .git 文件夹就可以了。但是,你确定要辣么做?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
├── HEAD ├── branches ├── config ├── description ├── hooks │ ├── pre-commit.sample │ ├── pre-push.sample │ └── ... ├── info │ └── exclude ├── objects │ ├── info │ └── pack └── refs ├── heads └── tags |
这就是你第一次提交之前 .git 目录的样子:
- 这个我们稍后会讨论
- 这个文件包含你仓库的设置信息。例如这里会放你远程仓库的 URL,你的 email 地址,你的用户名等…。 每次你在控制台使用“git config…”指令时,修改的就是这里。
- gitweb(可以说是 github 的前身)用来显示仓库的描述。
- 这是一个有意思的特性。Git 提供了一系列的脚本,你可以在 git 每一个有实质意义的阶段让它们自动运行。这些脚本就是 hooks,可以在 commit/rebase/pull…. 的前后运行。脚本的名字表示它什么时候被运行。例如一个有用的预推送 hook 可能会测试关于保持远程仓库一致性的式样原则。
- 你可以把你不想让 git 处理的文件放到 .gitignore 文件里。那么,exclude 文件也有同样的作用,不同的地方是它不会被共享,比如当你不想跟踪你的自定义的 IDE 相关的配置文件时,即使通常情况下 .gitignore 就足够了(如果你用到了这个请在评论中告诉我)。
commit 的真相
每一次你创建一个文件并跟踪它会发现,git 会对其进行压缩然后以 git 自己的数据结构形式来存储。这个压缩的对象会有一个唯一的名字,即一个哈希值,这个值存放在 object 目录下。
在探索 object 目录前,我们先要问自己 commit 到底是何方神圣。commit 大致可以视为你工作目录的快照,但是它又不仅仅只是一种快照。
实际上,当你提交的时候,为创建你工作目录的快照 git 只做了两件事:
- 如果这个文件没有改变,git 仅仅只把压缩文件的名字(就是哈希值)放入快照。
- 如果文件发生了变化,git 会压缩它,然后把压缩后的文件存入 object 目录。最后再把压缩文件的名字(哈希值)放入快照。
这里只是简单介绍,整个过程有一点复杂,以后的博客里会作说明的。
一旦快照创建好,其本身也会被压缩并且以一个哈希值命名。那么所有的压缩对象都放在哪里呢?答案是object 目录。
1
2
3
4
5
6
7
8
|
├── 4c │ └── f44f1e3fe4fb7f8aa42138c324f63f5ac85828 // hash ├── 86 │ └── 550c31847e518e1927f95991c949fc14efc711 // hash ├── e6 │ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391 // hash ├── info // let's ignore that └── pack // let's ignore that too |
这就是我创建一个空文件 file_1.txt 并提交后 object 目录看起来的样子。请注意如果你的文件的哈希值是“89faaee…”,git 会把这个文件存在 “89” 目录下然后命名这个文件为 “faaee…”。
你会看到3个哈希。一个对应 file_1.txt ,另一个对应在提交时所创建的快照。那么第三个是什么呢?其实是因为 commit 本身也是一个对象并且也被压缩存放在 object 目录下。
现在,你需要记住的是一个 commit 包含四个部分:
- 工作目录快照的哈希
- 提交的说明信息
- 提交者的信息
- 父提交的哈希值
如果我们解压缩一个提交,你自己可以看看到底是什么:
1
2
3
4
|
// by looking at the history you can easily find your commit hash // you also don't have to paste the whole hash, only enough // characters to make the hash unique git cat-file -p 4cf44f1e3fe4fb7f8aa42138c324f63f5ac85828 |
这是我看到的
1
2
3
4
|
tree 86550c31847e518e1927f95991c949fc14efc711 author Pierre De Wulf <test@gmail.com> 1455775173 -0500 committer Pierre De Wulf <test@gmail.com> 1455775173 -0500 commit A |
如你所见我们得到了所期望看到的的:快照的哈希,作者,提交信息。这里有两样东西很重要:
- 正如预料的一样,快照的哈希 “86550…” 也是一个对象并且能在object目录下找到。
- 因为这是我的第一个提交,所以没有父提交。
那我的快照里面到底是些什么呢?
1
2
|
git cat-file -p 86550c31847e518e1927f95991c949fc14efc711 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file_1.txt |
到这里我们看到的最后一个对象是我们先前提到的唯一会存在于快照中的对象。它是一个 blob(二进制文件),这里就不作深究了。
分支,标签,HEAD 都是一家人
那么现在你知道 git 的每一个对象都有一个正确的哈希值。现在我们来看看 HEAD 吧!那么,在 HEAD 里又有什么呢?
1
2
|
cat HEAD ref: refs/heads/master |
这看起来 HEAD 不是一个hash,倒是容易理解,因为 HEAD 可以看作一个你目前所在分支的指针。如果我们看看 refs/heads/master,就会发现这些:
1
2
|
cat refs/heads/master 4cf44f1e3fe4fb7f8aa42138c324f63f5ac85828 |
是不是很熟悉?是的,这和我们第一个提交的哈希完全一样。由此表明分支和标签就是一个提交的指针。明白这一点你就可以删除所有你想删除的分支和标签,而他们指向的提交依然在那里。只是有点难以被访问到。如果你想对这部分了解更多,请参考git book。
尾声
到目前为止你应该了解到, git 所做的事就是当你提交的时候“压缩”当前的工作目录,同时将其和其他一些信息一并存入 objects 目录。但是如果你足够了解 git 的话,你就能完全控制提交时哪些文件应该放进去而哪些不应该放。
我的意思是,一个提交并非真正意义上是一个你当前工作目录的快照,而是一个你想提交的文件的快照。在提交之前 git 把你想提交的文件放在哪里? git 把他们放在 index 文件里。我们现在不会去深入探究 index,同时如果你确实好奇你可以参考这里。
鸣谢
我希望通过本文你更好的理解了 git 的核心概念。如果你有任何问题和评论,请毫不犹豫的告诉我,你也可以在 twitter 上粉我。
我会写一些有关受欢迎的语言我认为会误解或不为人所知的功能的文章并且做到深入浅出。如果你喜欢 JS 你可以看看下面的链接:
- Things you should know about JS events 2,4k read
下一次我们谈谈 git 的变基(rebase),下次见,祝愉快。
相关推荐
Git-explorer 是一个基于 JavaScript 的工具,用于帮助开发者更深入地理解并探索 Git 仓库中的 `.git` 目录。`.git` 目录是 Git 版本控制系统的核心部分,它存储了所有关于项目版本历史、提交信息以及分支状态的数据...
在本文中,我们将深入探讨Git的基本概念、安装过程以及常用命令,帮助你更好地理解和使用这款强大的工具。 首先,Git的核心功能是追踪对文件和目录的修改,使团队协作变得更加高效。它通过记录每次修改的历史,允许...
Git是世界上最流行的分布式版本控制系统,尤其在软件开发...不过,为了更好地利用Git的强大功能,学习和理解Git的工作原理和命令是必不可少的。通过不断实践和探索,你会发现Git是管理代码版本、协同开发的强大工具。
Git是世界上最流行的分布式版本控制系统,它由Linus Torvalds为Linux内核开发而创建,因其高效、灵活和强大的特性,被广泛应用于软件...这将使你能够亲身体验和探索Git-2.18.0的所有新特性,并在实际项目中应用它们。
Git是分布式版本控制系统,它的设计思想独特且强大,被广泛应用于软件开发和...尽管现在已经有了更先进的版本,但理解并掌握早期版本的Git可以帮助我们更好地理解其发展历程,以及它如何演变成当今如此广泛使用的工具。
Git是一款分布式版本控制系统...理解并熟练掌握这些Git操作,能让你在团队协作中游刃有余,有效地管理和协同开发项目。不断实践和探索,你会发现在Git的帮助下,即使面对复杂的项目,也能保持代码的整洁和历史的清晰。
通过深入理解和熟练运用以上Git命令,你可以更高效地进行团队协作,确保代码的版本管理和维护。Git的学习并不止于此,还包括钩子(hooks)、子模块、rebasing等高级特性,不断探索和实践,将使你在开发过程中...
Git是世界上最流行的分布式版本控制系统,它允许开发人员协作并...通过理解和掌握这些基本知识,你可以开始使用Git有效地管理你的代码项目,并参与到团队的协作中。不断实践和探索,你会发现Git的强大之处远不止于此。
在 Git 面世之前, Linux 内核开发多年来一直使用专有版本...目的方法,就让这本书来激发你释放 Git 的全部潜能,为你的工作提供支持吧。 Johannes Schindelin 博士 Windows 端 Git 维护者 2015 年 8 月于德国科隆市
在本文中,我们将深入探讨Git实战中的常用命令,帮助你更好地理解和运用Git。 #### 起步 1. **添加远程仓库**:使用`git remote add`命令将本地仓库与远程仓库关联,例如: ```bash git remote add origin git@...
在深入探讨这些内容之前,让我们先理解一下Git的基本概念。Git的核心特性包括分支管理、合并、提交历史查看、差异比较以及远程仓库的交互。它的分布式性质意味着每个开发者的本地机器上都有一个完整的项目副本,这...
这份"Git原理详解及实用指南"将帮助你深入理解Git的工作机制,并提供实际操作的指导。 Git的核心原理主要围绕三个概念:工作区、暂存区和版本库。工作区是你平常编辑代码的地方,暂存区则是你准备提交到版本库的...
Git 是一个分布式版本控制系统,由Linus Torvalds在2005年为Linux内核开发而创建。它被广泛应用于软件开发和其他需要版本管理的项目,因其高效、灵活...在实际工作中,不断实践和探索,才能真正熟练运用Git的强大功能。
在本教程中,我们将深入探讨Gitblit的安装配置以及日常使用,帮助你更好地理解和掌握这一强大的Git服务器。 1. **Gitblit简介** Gitblit以其简洁的界面和易用性赢得了用户的喜爱。它不仅支持本地运行,还可以作为...
Git是世界上最流行的分布式版本控制系统,尤其在软件开发领域,它被广泛...随着对Git的深入理解和实践,你还可以探索更多高级特性,如rebasing、cherry-picking和interactive staging等,进一步提升你的代码管理效率。
本资源是专为CentOS设计的Git工具,版本为2.9.5,其包含了Git的手册页,帮助用户更好地理解和使用Git。 Git是一个分布式版本控制系统,由Linus Torvalds开发,旨在提高软件开发中的版本管理和协作效率。在Git 2.9.5...
Git 是一款强大的分布式版本控制系统,它使得开发者能够追踪和管理代码变更,同时支持多人协作开发。在日常工作中,了解并熟练...为了成为一个熟练的 Git 用户,建议通过实践不断加深理解,并探索适合自己的工作流。
Git是世界上最流行的分布式版本控制系统,广泛应用于软件开发和项目...随着熟练度的提高,可以进一步探索更高级的Git操作,如子模块、工作流模式(如Git Flow、GitHub Flow)以及钩子脚本等,以实现更高效的工作流程。