转发学习的啦。

似乎很少有人在读某个git快速教程的时候会说:“这个关于git的快速教程太酷了!读完了用起git来超级舒服,并且我一点也不怕自己会破坏什么东西。”

对git的初学者来说,刚接触git时就像进入了一个他不会听/说当地语言的陌生国度。如果你知道自己在哪里并且知道怎么走,那就很好。但是如果你迷路了,那麻烦就大了。

市面上已经有很多关于学习git基本指令的文章,因此这篇文章不讲这个。这里我们将试着从不同的角度来理解。

新手们通常都很害怕git,的确,git确实是一个很强大的工具,但它对使用者并不友好。大量的新概念,一个指令在不同的情况下做完全不同的事情,各种隐含的反馈……

我认为克服这个困难的一个可行方法就是在git的日常commit/puah之外再多做一点工作,如果花点时间来理解一下git是如何产生的,能帮我们避免很多麻烦。

 理解.git

当你建立了一个git repo,使用git init,git便创建了一个奇妙的目录:.git

这个文件夹里包含了git工作时所需要的所有信息。需要明确的是,如果想从你的项目中移除git,但保留项目文件,只需要删除.git文件夹即可。但是,为什么要这样做呢?

|── HEAD

|── branches

|── config

|── description

|── hooks

| |── pre-commit.sample

| |── pre-push.sample

| └── ...

|── info

| └── exclude

|── objects

| |── info

| └── pack

└── refs

|── heads

└── tags

这是你第一次commit之前.git文件夹的样子。

HEAD:这个我们稍后再说。

config:这个文件夹里是你的保存设置,这里将写入远程URL,比如你的邮箱、用户名等。每一次在控制端使用“git config”,它都会在这里结束。

description:被gitweb (Github的原型)用来显示对repo的描述。

hooks:这里有一个有趣的特性。Git有一套可以自动运行在任何一个有意义的git阶段下的脚本,叫做hooks。hooks可以运行在commit/rebase/pull等等状态的之前或之后。脚本的名称决定了它什么时候被执行。一个有用的pre-push脚本的例子将会被运行以测试控制器(远程控制)中的所有样式规则保持一致。

info - exclude:可以将你不想被git处理的文件放到.gitignore文件夹里。被排除的文件可以做到相同的事情,除了它不能被共享。如果你不想将你的自定义IDE关联到congif文件里,就可以使用这个。虽然大部分情况下,.gitignore就足够了。

 commit的内部是什么?

每次你创建了一个文件并跟踪它,git都会将其压缩并存储到自己的数据结构中。这个压缩对象有一个独特的名字、一个哈希码,存储在对象目录下。

在研究对象目录前,我们要问一个问题,什么是commit。这里commit可以看做是工作目录的一种快照,但不仅仅是快照。

实际上当你commit时,git只做两件事情来创造你工作目录的快照:

  1. 如果文件没有修改,git仅仅增加压缩文件的名字(hash)到快照中。

  2. 如果文件被修改过,git就将其压缩,再将压缩后的文件存储到对象文件夹中。然后再添加这个压缩文件的文件名(hash)到快照中去。

这是一个简化的描述,实际整个过程会复杂一点。

一旦快照文件被建立,它也会被压缩并用hash文件命名。那么这些压缩文件在什么地方呢?答案:对象文件夹。

|── 4c

| └── f44f1e3fe4fb7f8aa42138c324f63f5ac85828 // hash

|── 86

| └── 550c31847e518e1927f95991c949fc14efc711 // hash

|── e6

| └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391 // hash

|── info

└── pack

当我创建了一个名为file_1.txt的空文件并commit之后,对象目录应该是如上所看到的样子。请注意如果你的文件的哈希码是“89faaee…”,git将会吧这个文件储存在名为“89”的子目录下,并且命名这个文件为“faaee…”。

你看到右边有3个hash字样。一个对应的是我的file_1.txt文件,另一个对应的是我commit时所创建的快照文件。那么第三个呢?这是因为commit本身也是一个对象,它也会被压缩并被存储在对象文件夹中。

记住,一个commit指令实际上包含4件事:

  • 工作目录的快照文件的名称(哈希码)

  • 注释

  • 提交者信息

  • Parent commit的哈希码

然后,你们可以自己看一下如果不压缩commit文件时会发生什么:

// 查看历史,你会很容易就找到你的commit哈希码

// 你也不必粘贴全部的哈希码,只要足够就可以了

// 创造了独特哈希码的字符串

git cat-file -p 4cf44f1e3fe4fb7f8aa42138c324f63f5ac85828

得到结果:

tree 86550c31847e518e1927f95991c949fc14efc711

author Pierre De Wulf <test@gmail.com> 1455775173 -0500

committer Pierre De Wulf <test@gmail.com> 1455775173 -0500

commit A

你看,正如我们所期望的,我们得到了快照文件的哈希码、作者信息、和我的commit信息。

这里有两件很重要的事情:

  • 正如所期望的,那个名为“86550…”的快照哈希文件也是一个对象,并且能够在对象文件夹中被找到。

  • 因为这是我的第一个commit,所以没有Parent。

快照文件本质上是什么呢?

git cat-file -p 86550c31847e518e1927f95991c949fc14efc711

100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file_1.txt

这里,我们找到我们对象存储器中之前存储的最后一个对象,我们快照文件中仅有的对象。这是一个blob,但不是我们今天要讲的。

分支、标签、HEAD,它们都一样。

所以,现在你明白了git中的任何事情都可以用一个正确的hash来得到。现在,让我们来看一看HEAD。那么,HEAD中又有什么呢?

cat HEAD

ref: refs/heads/master

这不是一个哈希码,但它有价值,因为HEAD可以被认为是一个指向你正在使用的分支的指针。现在,我们看一下refs/heads/master内部,我们会看到如下信息:

cat refs/heads/master

4cf44f1e3fe4fb7f8aa42138c324f63f5ac85828

是不是很眼熟?是的,这和我们第一次commit时的哈希码是完全一样的。这说明 branches和tags无非就是一个指向commit的指针。

这意味着你可以删除所有你想删除的branches和tags,而它们所指向的 commit会仍然保留在这里。仅仅是访问commit更困难一点。

现在你应该明白,当你用一堆其它的指令来命令“压缩”你目前的工作目录并储存在对象文件夹时,git实际上都做了些什么。如果你对这些工具足够熟悉,你就应该完全知道哪些文件应该包含在commit中,而哪些文件不应该。

我的意思是commit并不真的是你工作目录的快照,而是你想要commit的文件的快照。那么在你保存你想要commit的文件之前,git将它们保存在哪里呢?它将这些文件保存在索引文件。这里我们就不继续往下深究了,感兴趣的读者请继续研究。

深入理解git,从研究git目录开始的更多相关文章

  1. [转发]深入理解git,从研究git目录开始

    转发学习的啦. 似乎很少有人在读某个git快速教程的时候会说:“这个关于git的快速教程太酷了!读完了用起git来超级舒服,并且我一点也不怕自己会破坏什么东西.” 对git的初学者来说,刚接触git时 ...

  2. 从git中删除 .idea 目录

    将.idea目录加入ignore清单: $ echo '.idea' >> .gitignore   从git中删除idea: $ git rm —cached -r .idea 3 将. ...

  3. Apache通过配置.htaccess文件禁止访问.git、.svn等目录

    如果你用过Git.SVN等代码版本控制工具的话,那肯定会知道,如果你需要拉去最新的代码到本地时,会自动生成一个.git或者.svn文件夹,里面包含一些项目相关的信息,如果在部署项目是,把这些文件公开暴 ...

  4. Git只获取部分目录的内容

    Git只获取部分目录的内容 Git的克隆,默认是直接拉取整个远程仓库,如果项目比较大,大量和自己无关的内容也会拉到本地,占用很多硬盘空间.Git在1.7版本后,已经支持只Checkout部分内容,这个 ...

  5. git删除远程.idea目录

    git删除远程.idea目录 1. 登录 Administrator@USER-20180708AB MINGW32 / (master) $ git config --global user.nam ...

  6. git初步研究2

    $git init Git 使用 git init 命令来初始化一个 Git 仓库,Git 的很多命令都需要在 Git 的仓库中运行,所以 git init 是使用 Git 的第一个命令. 在执行完成 ...

  7. 关于安装Git后,项目目录右键菜单无Git Bash Here命令的选项

    修改注册表配置 1.第一步,window + R,输入regedit回车进入注册表 2.依次进入HKEY_CLASSES_ROOT --> Directory -->Background ...

  8. The Git Parable:Git传说(转)

    The Git Parable:Git传说 -------- 毛球子好为人师 原文地址:http://tom.preston-werner.com/2009/05/19/the-git-parable ...

  9. [.net 面向对象程序设计进阶] (26) 团队开发利器(五)分布式版本控制系统Git——图形化Git客户端工具TortoiseGit

    [.net 面向对象程序设计进阶] (26) 团队开发利器(五)分布式版本控制系统Git——图形化Git客户端工具TortoiseGit 读前必备: 接上篇: 分布式版本控制系统Git——使用GitS ...

随机推荐

  1. mysql GROUP_CONCAT+ GROUP BY + substring_index获取分组的前几名

    mysql方法来源于:http://www.cnblogs.com/jjcc/p/5896588.html ###在网上看到一篇,非常赞的方法### 比如说要获取班级的前3名,mysql就可以用GRO ...

  2. PB-日志-系统函数2.13.7Match()、MatchW()

    ---恢复内容开始--- Match() 功 能:确定字符串中是否包含指定模式的字符. 语 法:Match ( string, textpattern ) 参 数:string:string类型,指定 ...

  3. html5本地存储(localStorage)使用介绍

    1.html5几种存储形式 本地存储(localStorage && sessionStorage) 离线缓存(application cache) indexedDB 和 webSQ ...

  4. 今天学的是 HTML基本元素、基本语法元素特点等,就发图片吧。

    现在我们新手用的软件是:Adobe Dreamweaver CS6 按照下面格式来改,以后点HTML5直接就改过来了. 可以敲敲这些代码,大家一起学习. <!doctype html>&l ...

  5. 聊聊 virtualenv 和 virtualenvwrapper 实践

    各位 Python 的小伙伴肯定多多少少接触过 virtualenv.本文将介绍 virtualenv 以及如何更科学更优雅地使用 virtualenv. virtualenv 首先来聊一下 virt ...

  6. 韩国手机游戏Elf Defense角色场景

    ! [复制链接] CG窝微博 签到天数: 36 天 连续签到: 1 天 [LV.5]常住居民I 22 主题 0 精华 2729 窝币 超级版主 积分 2546 收听TA 发消息 电梯直达 楼主     ...

  7. Solr内置的字段类型

    字段类型在org.apache.solr.schema包下 Class 描述 BCDIntField 二进制整形字段 BCDLongField 二进制长整形字段 BCDStrField 二进制字符型字 ...

  8. HANA SQLScript

    数据类型 日期时间类型 DATE(日期) DATE 数据类型由年.月.日信息组成,表示一个日期值. DATA 类型的默认格式为‘YYYY-MM-DD’. YYYY 表示年, MM 表示月而 DD 表示 ...

  9. js设计模式总结-单例模式

    单例模式 解决的问题 保证实例只有一个,避免多个实现,从全局来看,这个实例的状态是唯一的. 实现原理 设置一个变量来记录实例,通过检测该变量是否为空来决定是否创建实例 非透明单例 所谓非透明就是用户在 ...

  10. Jenkins 在windows下的安装与配置

    1. 安装Jenkins war包安装:启动Jenkins命令,打开cmd至Jenkins安装目录下,运行命令 java -jar jenkins.war 如果改变默认端口,则指定端口例如端口号108 ...