> For the complete documentation index, see [llms.txt](https://cfangxu-2.gitbook.io/front-end-basics/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cfangxu-2.gitbook.io/front-end-basics/gong-ju-lei/git/theory.md).

# 基础和原理

## 基础

### 保存的是文件的完整快照，而不是差异变化或者文件补丁

其它大部分系统以文件变更列表的方式存储信息。 这类系统（CVS、Subversion、Perforce、Bazaar 等等）将它们保存的信息看作是一组基本文件和每个文件随时间逐步累积的差异。\
Git 更像是把数据看作是对小型文件系统的一组快照。 每次你提交更新，或在 Git 中保存项目状态时，它主要对当时的全部文件制作一个快照并保存这个快照的索引。

> 疑问：如果我的项目大小是10M，那Git占用的空间是不是随着提交次数的增加线性增加呢？我提交（commit）了10次，占用空间是不是100M呢？\
> 很显然不是， 为了高效，如果文件没有修改，Git 不再重新存储该文件，它只会保存一个指向上一个版本的文件的指针，即，对于一个特定版本的文件，Git只会保存一个副本，但可以有多个指向该文件的指针。

### 近乎所有的操作都是本地执行

举个例子，要浏览项目的历史，Git 不需外连到服务器去获取历史，然后再显示出来——它只需直接从本地数据库中读取。\
这也意味着你离线时，几乎可以进行任何操作。 如你在飞机或火车上想做些工作，你能愉快地提交，直到有网络连接时再上传

### 三种状态

1. 已修改（modified）    表示修改了某个文件，但还没有提交保存；
2. 已暂存（staged）    表示把已修改的文件放在下次提交时要保存的清单中，即暂存区域；
3. 已提交（committed）    表示该文件已经被安全地保存在本地版本库中了。

### 三个工作区域

1.工作区\
就是你在电脑上看到的目录，或者以后需要再新建的目录文件等等都属于工作区范畴。

2.暂存区\
运行git add命令后文件保存的区域，也是下次提交将要保存的文件

**注意： Git 提交实际读取的是暂存区域的内容，而与工作区域的文件无关，这也是当你修改了文件之后，如果没有添加git add到暂存区域，并不会保存到版本库的原因**

> 作用:\
> 作为过渡层\
> 避免误操作\
> 保护工作区和版本区\
> 分支处理

3、版本区（本地仓库）\
工作区有一个隐藏目录.git,这个不属于工作区，这是版本库。其中版本库里面存了很多东西，其中最重要的就是stage(暂存区)，还有Git为我们自动创建了第一个分支master,以及指向master的一个指针HEAD。

## 原理

### SHA-1校验和

Git 是一套内容寻址文件系统。意思就是Git 从核心上来看不过是简单地存储键值对（key-value），value是文件的内容，而key是文件内容与文件头信息的 40个字符长度的 SHA-1 校验和。\
例如：5453545dccd33565a585ffe5f53fda3e067b84d8。Git使用该校验和不是为了加密，而是为了数据的完整性，它可以保证，在很多年后，你重新checkout某个commit时，一定是它多年前的当时的状态，完全一摸一样。当你对文件进行了哪怕一丁点儿的修改，也会计算出完全不同的 SHA-1 校验和，这种现象叫做“雪崩效应”（Avalanche effect）。

### 文件(blob)对象，树(tree)对象，提交(commit)对象

简单来说，blob对象保存文件的内容；tree对象类似文件夹，保存blob对象和其它tree对象；commit对象保存tree对象，提交信息，作者，邮箱以及上一次的提交对象的ID（第一次提交没有）。而Git就是通过组织和管理这些对象的状态以及复杂的关系实现的版本控制以及以及其他功能如分支。\
具体可以参考<http://blog.codingplayboy.com/2017/03/23/git_internal/>

### Git的引用

如果我们想要看某个提交记录之前的完整历史，就必须记住这个提交ID，但提交ID是一个40位的 SHA-1 校验和，难记。所以**引用就是SHA-1 校验和的别名，存储在.git/refs文件夹中**。\
最常见的引用也许就是master了，因为这是Git默认创建的（可以修改，但一般不修改），它始终指向你项目主分支的最后一次提交记录。存放位置`.git/refs/heads/master`

### Git的tag

标签从某种意义上像是一个引用， 它指向一个 commit 对象而不是一个 tree，包含一个标签，一组数据，一个消息和一个commit 对象的指针。但是区别就是引用随着项目进行，它的值在不断向前推进变化，但是标签不会变化——永远指向同一个 commit，仅仅是提供一个更加友好的名字。

### Git的分支

Git保存文件的最基本的对象是blob对象，Git本质上只是一棵巨大的文件树，树的每一个节点就是blob对象，而分支只是树的一个分叉。说白了，分支就是一个有名字的引用，它包含一个提交对象的的40位校验和，所以创建分支就是向一个文件写入 41 个字节（外加一个换行符）那么简单，所以自然就快了，而且与项目的复杂程度无关。

在做一个新功能的时候，最好是在一个独立的区域上开发，通常称之为分支。分支之间相互独立，并且拥有自己的历史记录。\
优点：

* 稳定版本的代码不会被破坏
* 不同的功能可以由不同开发者同时开发。
* 开发者可以专注于自己的分支，不用担心被其他人破坏了环境
* 在不确定之前，同一个特性可以拥有几个版本，便于比较

**创建分支**\
Git的默认分支是master，存储在`.git\refs\heads\master`文件中，假设你在master分支运行`git branch dev`创建了一个名字为dev的分支，那么git所做的实际操作是：

1. 在.git\refs\heads文件夹下新建一个文件名为dev（没有扩展名）的文本文件。
2. 将HEAD指向的当前分支（当前为master）的40位SHA-1 校验和外加一个换行符写入dev文件。
3. 结束。

**切换分支的实际操作**\
1\. 修改.git文件下的HEAD文件为ref: refs/heads/<分支名称>。 2. 按照分支指向的提交记录将工作区的文件恢复至一模一样。 3. 结束。

### 推荐资料

* [Git的核心概念](https://lufficc.com/blog/the-core-conception-of-git)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://cfangxu-2.gitbook.io/front-end-basics/gong-ju-lei/git/theory.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
