当前位置: 首页 > news >正文

【git教程】git add 命令讲解

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 一、基本使用方法
    • `git add` 命令的常见用法:
    • `-u`参数说明
    • 对比说明
  • 二、底层原理
    • `git add` 的核心作用
    • `SHA-1`哈希值生成
    • 在线SHA-1工具与Git哈希值差异的原因


git add 是Git中用于将文件修改添加到暂存区(也称为索引)的命令。下面从使用方法和底层原理两方面进行详细讲解。

一、基本使用方法

git add 命令的常见用法:

# 添加单个文件
git add filename.txt# 添加多个文件
git add file1.txt file2.txt# 添加当前目录下的所有修改
git add .# 添加某个目录下的所有修改
git add directory/# 添加所有被修改和已删除文件,但不包括新文件
git add -u  或  git add --update# 添加所有修改(包括新文件、已修改和已删除文件)
git add -A  或  git add --all       //*注意不能用 git add -a

-u参数说明

git add -u 中的 -u--update 的缩写,它源自英文单词 update(更新)。这个选项的作用是:只更新已经被Git跟踪的文件,即只添加那些已经存在于版本库中且被修改或删除的文件,但不包括新创建的文件(未被Git跟踪的文件)。

底层原理角度
从Git底层来看,-u 选项只更新暂存区中已存在的条目。当你执行 git add -u 时:

  1. Git会遍历暂存区中的所有文件路径。
  2. 对于每个路径,检查工作区中对应的文件是否被修改或删除。
  3. 如果有修改,则生成新的blob对象并更新暂存区记录;如果已删除,则从暂存区中移除该文件记录。
  4. 完全忽略那些不在暂存区中的新文件。

常用场景
git add -u 常用于以下场景:

  • 你只需要提交已跟踪文件的修改,不希望意外提交新创建的测试文件或临时文件。
  • 你在清理项目时删除了一些文件,希望将这些删除操作纳入提交。
  • 配合 git add <path> 单独添加新文件,实现更精细的提交控制。

例如,假设你有以下文件状态:

已修改:  a.txt
已删除:  b.txt
新文件:  c.txt

执行 git add -u 后,只有 a.txt 的修改和 b.txt 的删除会被添加到暂存区,而 c.txt 不会被处理。

对比说明

  • git add -ugit add --update
    只处理已跟踪文件的修改和删除,不处理新文件。

  • git add .
    处理所有修改,包括新文件、已修改文件和已删除文件。

  • git add -Agit add --all
    处理所有修改,效果等同于 git add .,但在某些Git版本中可能有细微差异(例如在子目录中执行时)。

二、底层原理

Git的底层数据结构主要由三种对象组成:blob对象tree对象commit对象。理解git add的底层原理,需要先了解这三种对象:

  1. blob对象(Binary Large Object):存储文件的内容,每个blob对应一个文件的特定版本。
  2. tree对象:类似于文件系统中的目录,记录文件名、目录结构和指向blob对象或其他tree对象的引用。
  3. commit对象:指向一个tree对象,并记录提交的元数据(作者、时间、提交信息等)。

git add 的核心作用

git add 命令的核心是将文件的当前状态保存为blob对象,并更新暂存区(索引)的内容。具体步骤如下:

  1. 计算文件哈希值:对文件内容使用SHA-1算法计算哈希值(例如:1f7a7a472abf3dd9643fd615f6da379c4acb3e3)。

  2. 存储blob对象:将文件内容压缩后存储在 .git/objects 目录中,文件路径为哈希值的前两位作为目录名,后38位作为文件名。例如:

    .git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3
    
  3. 更新暂存区:在暂存区(.git/index 文件)中记录文件路径、哈希值、文件模式等信息。暂存区本质上是一个二进制文件,记录了下次提交时要包含的内容。

示例说明
假设你有一个项目,包含两个文件 a.txtb.txt,执行以下操作:

  1. 修改 a.txt 后执行 git add a.txt

    • Git会计算 a.txt 的新哈希值,创建对应的blob对象并存储在 .git/objects 目录中。
    • 暂存区会更新 a.txt 的记录,指向新的blob对象。
  2. 此时如果再次修改 a.txt 但不执行 git add

    • 工作区的 a.txt 与暂存区中的 a.txt 指向不同的blob对象。
    • 下次提交时,只有第一次 git add 时记录的版本会被提交。

暂存区的作用
暂存区是Git区别于其他版本控制系统的一个重要特性,它的主要作用是:

  1. 选择性提交:允许你将不同的修改分批提交,而不必一次提交所有修改。
  2. 多阶段提交:可以将一个大的修改拆分成多个小的提交,使提交历史更加清晰。
  3. 提交准备:作为工作区和版本库之间的缓冲区,方便组织提交内容。

git add 命令的本质是:将工作区中的文件修改转换为Git内部的blob对象,并更新暂存区的记录。理解这一点有助于更好地使用Git,特别是在处理复杂的提交场景时。

SHA-1哈希值生成

在Git中,当执行git add命令时,Git会为文件内容计算SHA-1哈希值,这个哈希值是通过特定的组合字符串生成的。下面详细介绍这个组合字符串的构成。

组合字符串的基本结构
Git生成SHA-1哈希值的组合字符串由以下几部分构成:

blob [文件大小]\0[文件内容]

其中:

  • blob是固定的前缀字符串,表示这是一个blob对象。
  • [文件大小]是文件内容的字节数,以十进制表示。
  • \0是ASCII码为0的空字节(null byte),用于分隔元数据和文件内容。
  • [文件内容]是文件的实际字节数据。

计算示例
假设我们有一个文件test.txt,内容为hello world(不包含换行符),其组合字符串的构成为:

  1. 前缀字符串:blob (注意后面有一个空格)。
  2. 文件大小:11(因为hello world包含11个字符)。
  3. 空字节:\0
  4. 文件内容:hello world

组合后的完整字符串为:

blob 11\0hello world

对应的ASCII表示为:

b l o b   1 1 \0 h e l l o   w o r l d

对这个组合字符串计算SHA-1哈希值,得到的结果是:

sha1("blob 11\0hello world") = 95d09f2b10159347eece71399a7e2e907ea3df4f

验证方法
可以通过以下命令在Git中验证这个哈希值:

# 创建测试文件
echo -n "hello world" > test.txt# 计算文件的SHA-1哈希值(组合字符串的哈希值)
git hash-object test.txt
# 输出:95d09f2b10159347eece71399a7e2e907ea3df4f# 或者使用以下命令直接计算组合字符串的哈希值
echo -n -e "blob 11\0hello world" | sha1sum
# 输出:95d09f2b10159347eece71399a7e2e907ea3df4f -

或者

import hashlibcontent = b"hello world"  # 注意:是字节形式的 "hello world"
obj_type = "blob"header = f"{obj_type} {len(content)}\0"
store = header.encode() + contentsha1 = hashlib.sha1()
sha1.update(store)
git_hash = sha1.hexdigest()print(f"组合字符串: {header.encode() + content}")
print(f"Git哈希值: {git_hash}")

其他注意事项

  • 内容相关 :如果两个文件内容相同,即使文件名不同或其他元数据不同,它们的blob 哈希值也会相同。
  • 换行符敏感:文件中的换行符(LF或CRLF)会影响哈希值的计算。
  • 空文件:对于空文件,组合字符串为blob 0\0,对应的哈希值是e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
  • 二进制文件:Git对二进制文件和文本文件的处理方式相同,都是直接计算字节数据的哈希值。
  • 完整性检查:哈希值包含文件大小信息,可用于验证文件内容在传输过程中是否被篡改。

理解这种组合字符串的构成,有助于深入理解Git的底层原理和数据存储方式。

在线SHA-1工具与Git哈希值差异的原因

网上有很多在线计算SHA-1哈希值工具,输入上述组合字符串之后发现得到的哈希值与Git哈希值并不一样,下面是搜索得到的答案:
问题本质在于 空字节(\0)的处理方式不同。Git 中的 \0 是二进制空字节(ASCII 0),而在线工具通常将其作为普通文本字符处理。

核心差异:空字节的表示方式

  • Git 的处理
    blob 1\01 中的 \0二进制空字节(字节值为 0x00),组合字符串的实际字节序列为:
    62 6c 6f 62 20 31 00 31(对应 blob 1\01)。

  • 在线工具的处理
    当您在网站输入 blob 1\01 时,工具会将 \0 视为两个普通字符(\0),字节序列为:
    62 6c 6f 62 20 31 5c 30 31(对应 blob 1\01,其中 \0x5C00x30)。

两种情况的输入字节完全不同,因此 SHA-1 哈希值必然不同

为什么在线工具无法正确计算?

  1. 空字节无法直接输入
    大多数文本输入框会过滤或无法识别空字节(\0 在编程中通常表示字符串结束),因此无法在网页中直接输入真实的空字节。

  2. 工具设计定位
    这类在线工具主要用于文本内容的哈希计算,而非 Git 底层对象的哈希计算,未考虑 Git 的二进制格式要求。

总结:差异的本质

场景输入内容的字节表示哈希值(示例)
Git 实际计算blob 1\01\0 是0x00空字节)56a6051ca2b02b04ef92d5150c9ef600403cb1de
在线工具文本输入blob 1\01\0 是"\0"字符串)37c720f73d5b7aa9f212e266aeccafb6f038d315

关键结论:Git 的哈希计算包含二进制空字节,而在线工具无法处理这种格式,因此必须通过 Git 命令或编程方式验证真实的 Git 哈希值。


相关文章:

  • 如何让ChatGPT模仿人类写作,降低AIGC率?
  • zookeeper Curator(2):Curator的节点操作
  • var let setTimeOut 经典面试题
  • 第十节:Vben Admin 最新 v5.0 (vben5) 快速入门 - 菜单管理(下)
  • 前端与 Spring Boot 后端无感 Token 刷新 - 从原理到全栈实践
  • KS值:风控模型的“风险照妖镜”
  • 投稿爱思唯尔期刊,是什么Manuscript without Author Details,LaTeX文件怎么上传
  • 能否仅用两台服务器实现集群的高可用性??
  • 从用户到权限:解密 AWS IAM Identity Center 的授权之道
  • vue-29(创建 Nuxt.js 项目)
  • StarRocks 向量索引如何让大模型“记性更好”?
  • RK3568-drm框架
  • 软测八股--计算机网络
  • Http请求参数的区别
  • Youtube双塔模型
  • 网络 : 传输层【UDP协议】
  • 源码运行效果图(六)
  • 2025年健康医疗大数据开放共享:现状、挑战与未来发展
  • Spring Cloud 微服务(负载均衡策略深度解析)
  • 概述-4-通用语法及分类