GIT的正确使用姿势与最佳实践——我与GIT(5)| 豆包MarsCode AI 刷题

64 阅读8分钟

2.5 Git 的数据结构:Objects(commit/tree/blob)

Git 使用三种核心对象来存储和管理数据:

commit 对象

一个 commit 对象是 Git 的基本单位,记录了提交的作者信息、提交时间、提交注释以及一个指向 tree 对象的指针。

Commit:
- 元数据:作者、时间、注释
- 指向 tree 对象

tree 对象

tree 对象表示项目目录结构。它包含文件名、文件模式以及指向 blob 对象的指针,可以理解为一个目录的快照。

Tree:
- 文件结构和属性
- 指向 blob 对象

blob 对象

blob 对象保存文件的内容,是 Git 存储的最基本单位。不论文件名称如何改变,只要内容相同,Git 都会生成相同的 blob 对象。

Blob:
- 文件内容

通过 commit -> tree -> blob 的结构,Git 实现了文件的高效存储和版本追踪。


2.6 refs(引用)

refs 是 Git 用来管理分支和标签的指针。

  • HEAD:指向当前正在操作的分支。
  • refs/heads/ :存储各分支的最新提交信息。
  • refs/tags/ :存储标签信息,用于标记特定提交。

2.7 annotation tag(注释标签)

注释标签是一种特殊的 refs,用来给特定的 commit 打标签,通常用于版本发布:

git tag -a v1.0 -m "Release version 1.0"  # 创建注释标签
git push origin v1.0                     # 推送标签到远端

与轻量标签(lightweight tag)不同,注释标签保存了额外的元数据(作者、时间、注释等)。


2.8 追溯历史版本

Git 提供了丰富的工具追溯代码历史,帮助开发者了解文件变化:

git log                     # 查看提交历史
git log --oneline           # 简化显示
git log -p <file>           # 查看某文件的详细历史
git blame <file>            # 查看每一行代码的提交记录

这些命令对于定位问题、分析代码变动至关重要。


2.9 修改历史版本

在需要调整提交历史时,可以使用以下命令:

  • git rebase:重新整理提交历史,用于生成更清晰的提交记录。
  • git commit --amend:修改最近一次提交的内容或注释。

需要注意的是,修改历史记录后可能影响其他人的同步工作,应谨慎操作。


2.10 悬空对象与新增对象

在 Git 中,未被任何 refs 指向的对象被称为“悬空对象”(dangling objects)。这些对象通常是在历史修改、分支删除或错误操作后产生的。

git fsck --lost-found  # 检查并列出悬空对象

2.11 垃圾回收与恢复:git gcreflog

  • git gc:清理无用的悬空对象,优化存储空间:

    git gc --prune=now  # 立即清理悬空对象
    
  • reflog:记录分支和 HEAD 的历史移动,用于恢复误操作:

    git reflog        # 查看 HEAD 的移动历史
    git reset --hard HEAD@{1}  # 恢复到之前的某一状态
    

2.12 完整的 Git 存储视图

image.png

Git 的存储结构

.git 目录

Git 的所有历史记录和元数据都保存在项目目录下的 .git 文件夹中。

  • 重要子目录

    • objects/:存储所有的 Blob、Tree 和 Commit 对象。
    • refs/:存储分支和标签的引用信息。
    • HEAD:指向当前分支或提交。

快照链

每次提交会生成一个提交对象(Commit),它包含:

  • 提交的目录树(Tree)的哈希值。
  • 上一个提交对象的哈希值(形成链表结构)。
  • 提交的作者信息、时间戳和提交信息。

例如:

Commit A -> Commit B -> Commit C

每个提交指向上一次提交,形成了历史链条


通过 commit、tree、blob 和 refs 等核心概念,Git 构建了一个完整的存储模型:

  1. 本地存储:每一次提交的版本快照通过对象存储在 .git 目录中。
  2. 远端仓库同步:在多人合作中,通过 pull 和 push 保持数据一致性。
  • 高效存储:通过哈希和快照,Git 只存储变化的部分。

  • 完整性:所有历史记录通过 SHA-1 哈希校验,防止数据篡改。

  • 灵活性:分支和合并操作简单高效,分支仅是指针移动。

  • 分布式:每个开发者的本地仓库都是完整的历史版本。

总结:Git 是如何存储代码历史的

  1. 核心思想:Git 通过哈希值和指针记录每一次提交、文件快照和历史关系。
  2. 高效存储:文件内容未改变时,Git 重用已有数据对象,而不重复存储。
  3. 完整性保证:通过 SHA-1 哈希校验,任何改动都会导致哈希值变化,确保数据安全和版本一致性。
  4. 链式结构:每个提交记录指向其父提交,形成完整的历史链条,使得代码可以随时回溯到任意版本。

这种存储结构使得 Git 高效且灵活,无论是小型项目还是复杂的多人协作开发,都能应对自如。


image.png

2.13 拉取代码:git clone & pull & fetch

git clone

从远程仓库复制一个完整的版本库:

git clone <repository_url>      # 克隆整个仓库
git clone -b <branch_name> <url>  # 克隆指定分支

git fetch

拉取远端更新到本地但不合并,为用户提供检查的机会:

git fetch origin main  # 获取远程 main 分支的更新

git pull

拉取远端更新并自动合并到当前分支:

git pull origin main  # 拉取并合并远程更新

2.14 推送代码:git push

将本地代码推送到远端仓库:

git push origin main  # 推送本地 main 分支的更新

如果远程分支受到保护(如 GitHub 的主分支保护策略),需要通过 Pull Request(PR)合并代码。


其他补充说明

以下是 Git 中关于 git checkoutgit diffgit addgit commitgit fetch 的详细解释以及用法:

1. git checkout

  • 切换到指定的分支或提交。
  • 恢复工作区中的文件到某个版本的状态。
# 切换分支
git checkout <分支名>

# 切换到某个提交(此时进入“分离 HEAD”状态)
git checkout <提交哈希值>

# 恢复某个文件到暂存区或指定提交的版本
git checkout <提交哈希值或分支名> -- <文件名>

示例

# 切换到分支 main
git checkout main

# 将文件 file.txt 恢复到最新提交的状态
git checkout HEAD -- file.txt

2. git diff

显示文件的改动对比,包括:

  • 工作区和暂存区之间的差异。
  • 暂存区和仓库最新提交之间的差异。
# 查看工作区和暂存区的差异
git diff

# 查看暂存区和最新提交的差异
git diff --cached

# 查看工作区和最新提交的差异
git diff HEAD

# 查看两个分支之间的差异
git diff <分支A> <分支B>

image.png

示例

# 比较当前文件的修改与暂存区的差异
git diff

# 比较暂存区和最新提交的差异
git diff --cached

3. git add

作用

将修改后的文件从工作区添加到暂存区。

常用语法

# 添加单个文件到暂存区
git add <文件名>

# 添加当前目录及子目录中所有修改的文件
git add .

# 添加指定类型的文件(通配符)
git add *.txt

示例

# 添加 file.txt 到暂存区
git add file.txt

# 添加所有修改到暂存区
git add .

4. git commit

将暂存区的内容提交到本地仓库,生成一个新的提交记录。

# 提交暂存区的所有内容,并添加提交信息
git commit -m "<提交信息>"

# 直接提交工作区中修改过的文件并跳过暂存区
git commit -a -m "<提交信息>"

# 修改最近一次提交的提交信息
git commit --amend -m "<新提交信息>"

示例

# 提交并附带提交信息
git commit -m "Add new feature"

# 修改最近一次提交信息
git commit --amend -m "Fix typo in last commit message"

5. git fetch

从远程仓库拉取最新的更新,但不自动合并到本地分支。

# 拉取远程仓库的更新
git fetch <远程名>

# 查看远程分支的更新
git fetch --dry-run

示例

# 拉取远程 origin 的最新更新
git fetch origin

# 检查是否有更新但不下载
git fetch --dry-run

通过这些命令可以高效地管理本地和远程仓库的代码版本!


解决问题

问题 1:悬空对象过多,占用存储空间

解决方法:使用垃圾回收清理:

git gc --prune=now

问题 2:误删分支或提交

解决方法:通过 reflog 恢复:

git reflog        # 找到误删前的 HEAD
git reset --hard HEAD@{n}

问题 3:拉取后发生冲突

解决方法:手动解决冲突并提交合并:

# 编辑冲突文件,保留需要的内容
git add <file>
git commit -m "Resolve merge conflict"

以上内容涵盖了 Git 的存储逻辑、核心操作及常见问题解决,为开发者提供了全面的理解和实用工具。


欢迎在评论区分享你的 Git 学习经历与心得,也许我们会因为共同的挑战而收获新的灵感! Git 的学习并不是一蹴而就,但每一次遇到问题并解决的过程,都是迈向更高水平的积累。期待与你一起交流、进步!