【原理】Git内部原理揭秘:从文件变化到版本控制


阿里云特惠 - 新用户专享

Git内部原理揭秘

Git不仅是工具,更是一个内容寻址文件系统.理解其内部原理,能让你在使用时更加得心应手.

Git的核心数据结构

Git用四种对象存储所有数据:

# Git对象类型:
# 1. blob - 文件内容
# 2. tree - 目录结构  
# 3. commit - 提交信息
# 4. tag - 标签

# 查看.git目录结构
$ ls -la .git/
# objects/  - 存储所有对象
# refs/     - 存储分支和标签引用
# HEAD      - 当前分支指针
# index     - 暂存区

Blob对象:存储文件内容

# Git用SHA-1哈希作为文件名存储内容
# 文件内容 → SHA-1哈希 → 对象文件

# 手动创建blob对象
echo "Hello Git" | git hash-object --stdin
# 输出:b7aec520dec0a9746479c1e5b3c2f1e4c5a8d9b2

# 查看blob内容
git cat-file -p b7aec520dec0a9746479c1e5b3c2f1e4c5a8d9b2
# 输出:Hello Git

关键特性:相同内容只存一份,天然去重.

Tree对象:存储目录结构

# Tree对象存储文件名,权限,类型和对应的blob哈希

# 查看某次提交的树结构
git cat-file -p HEAD^{tree}

# 输出示例:
# 100644 blob a906cb2a4a904a152e80877d4088654daad0c859    README.md
# 100644 blob 8f94139338f9404f26296befa88755fc2598c289    main.py
# 040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0    src

# 含义:
# 100644 = 普通文件权限
# blob = 文件内容对象
# tree = 子目录对象

Commit对象:存储版本历史

# 查看commit对象详情
git cat-file -p HEAD

# 输出:
# tree 4d5fcadc293a348e88f777dc0920f11e7d5e8e79
# parent 3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b
# author Zhang San  1712640000 +0800
# committer Zhang San  1712640000 +0800
#
# 修复登录bug

# 关键字段:
# tree - 本次提交对应的目录树
# parent - 父提交(形成链表结构)
# author/committer - 作者信息和时间戳

分支的本质:可移动的指针

# 分支只是指向commit的引用
$ cat .git/refs/heads/main
# a1b2c3d4e5f6... (40位commit哈希)

# HEAD指向当前分支
$ cat .git/HEAD
# ref: refs/heads/main

# 切换分支就是修改HEAD的指向
git checkout feature
# 等价于:echo "ref: refs/heads/feature" > .git/HEAD

图解Git存储结构

工作目录        暂存区(index)        本地仓库(objects)
   │                │                    │
   │   git add      │                    │
   │───────────────>│                    │
   │                │   git commit       │
   │                │───────────────────>│
   │                │                    │
   │                │              ┌─────────────┐
   │                │              │   commit    │
   │                │              │  ┌────────┐ │
   │                │              │  │ tree   │─┼──> 根目录树
   │                │              │  │ parent │─┼──> 父提交
   │                │              │  │ author │ │
   │                │              │  │ message│ │
   │                │              │  └────────┘ │
   │                │              └─────────────┘

Pack文件:压缩存储

Git会定期将松散对象打包,节省空间:

# 手动触发打包
git gc

# 查看pack文件
$ ls .git/objects/pack/
# pack-a1b2c3d4e5f6.pack  - 打包的数据
# pack-a1b2c3d4e5f6.idx   - 索引文件

# pack文件使用增量压缩
# 只存文件差异,而不是完整副本

总结

Git的设计哲学:内容寻址,不可变对象,引用指向.理解这些原理,你就能理解为什么Git分支切换那么快,为什么回滚那么安全.

发表评论