Git原理与使用详解(三):深入.git与文件管理实战

一、 引言:窥探Git的"心脏"------.git目录

在上一篇中,我们成功创建了Git仓库,并了解到其核心是一个名为 .git的隐藏目录。这个目录是Git真正的"大脑"和"心脏",它保存了项目所有的版本控制信息。理解 .git目录的结构和工作原理,能让我们对版本控制有更本质的认识,在遇到问题时也能知其所以然。

同时,在实际开发中,我们不仅需要添加新文件,更重要的是对已有文件进行频繁的修改。如何让Git有效地追踪这些变化,是每个开发者必须掌握的基本功。本篇我们将首先深入 .git目录,然后重点学习如何使用Git来管理文件的修改、查看状态和比较差异。

二、 深入剖析.git目录结构

让我们再次进入之前创建的 gitcode目录,并使用 tree命令(如果未安装,可使用 sudo yum install treesudo apt install tree安装)来查看 .git的目录结构。

复制代码
liu@139-159-150-152:~/gitcode$ tree .git/ -L 2
.git/
├── branches
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── fsmonitor-watchman.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   └── update.sample
├── index
├── info
│   └── exclude
├── logs
│   ├── HEAD
│   └── refs
│       └── heads
│           └── master
├── objects
│   ├── 2d
│   │   └── 832d9044c6980818dc0508b4b8f2e7f84f0a9a
│   ├── 61
│   │   └── 422f8e7f3b7f3c9e5f3f7f3b7f3c9e5f3f7f3b7
│   ├── c6
│   │   └── 1428926f3853d4ec6dde904415b0e6c1dabcc6
│   ├── e6
│   │   └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
│   ├── info
│   └── pack
└── refs
    ├── heads
    │   └── master
    └── tags

20 directories, 20 files

结构看起来有些复杂,但我们只需关注其中几个最核心的文件和目录:

  1. HEAD文件 :这是一个指向当前所在分支的引用文件。通常它的内容是 ref: refs/heads/master,表示当前处于 master分支。你可以把它理解为一个"指南针",总是指向你正在工作的分支。

  2. index文件 :这就是暂存区(Stage) ​ 的实际物理存储位置。它是一个二进制文件,记录了当前有哪些文件被暂存,以及它们的内容哈希等信息。执行 git add命令就是在修改这个文件。

  3. objects目录 :这是Git的对象数据库 ,是Git版本控制的核心。所有被Git管理的内容(文件内容、目录树、提交信息等)都以"对象"的形式存储在这里。它是一个内容寻址文件系统,意味着每个对象由其内容的SHA-1哈希值来命名和查找。正是这个设计,保证了Git数据的完整性和高效性。

    • Blob对象:存储文件的具体内容。

    • Tree对象:类似于目录,存储了指向Blob对象或其他Tree对象的指针,记录了目录结构。

    • Commit对象:存储一次提交的元数据,如作者、提交者、提交时间、提交信息,以及指向其父提交(一个或多个)和顶层Tree对象的指针。

  4. refs目录 :存储**引用(References)**​ 的地方,可以理解为是"指针"或"标签"的集合。

    • refs/heads/下存放着各个分支 的引用。例如,refs/heads/master文件里存储着master分支最新一次提交的SHA-1值。

    • refs/tags/下存放着标签的引用(用于标记特定的重要版本,如v1.0.0)。

  5. config文件 :当前Git仓库的配置文件。这里保存的配置会覆盖全局(~/.gitconfig)的配置。

  6. hooks目录 :存放钩子(Hooks)脚本的目录。钩子是在Git执行某些特定操作(如提交、推送等)前后自动触发的自定义脚本,可用于自动化任务,如代码风格检查、运行测试等。

一个简单的例子来串联这些概念

当我们执行 git commit -m "first commit"时,Git会:

  • 将暂存区(index)中的内容生成一个Tree对象,存入 objects

  • 创建一个Commit对象,指向这个Tree对象和父提交(首次提交没有父提交),存入 objects

  • 将当前分支(如master)的引用(在refs/heads/master中)更新为这个新Commit对象的SHA-1值。

三、 管理文件修改

现在,我们回到实战层面。版本控制的核心是跟踪文件的变化 。让我们修改 ReadMe文件,并让Git记录这个过程。

  1. 修改工作区文件

    复制代码
    liu@139-159-150-152:~/gitcode$ vim ReadMe
    # 在第一行"hello world"后面添加一个感叹号,在第二行"hello git"后面也添加一个感叹号
    liu@139-159-150-152:~/gitcode$ cat ReadMe
    hello world!
    hello git!
  2. 查看仓库当前状态 (git status)

    修改完成后,我们首先需要知道仓库当前的状态。git status命令用于显示工作区和暂存区的状态,这是最常用的Git命令之一。

    复制代码
    liu@139-159-150-152:~/gitcode$ git status
    On branch master
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
    
            modified:   ReadMe
    
    no changes added to commit (use "git add" and/or "git commit -a")

    git status命令输出了非常有价值的信息:

    • On branch master:告诉你当前在 master分支上。

    • Changes not staged for commit"未被暂存以备提交的变更" 。这是关键!它列出了工作区中那些已经被Git跟踪过,但修改后尚未放入暂存区 的文件。这里显示 ReadMe文件被修改了。

    • 它还友好地给出了提示:使用 git add <file>...来暂存修改(即放入暂存区),或者使用 git restore <file>来丢弃工作区的修改(将文件恢复到暂存区或版本库中的状态)。

    • no changes added to commit:暂存区是空的,没有可以提交的内容。

  3. 将修改添加到暂存区 (git add)

    根据提示,我们需要将修改添加到暂存区。

    复制代码
    liu@139-159-150-152:~/gitcode$ git add ReadMe

    再次运行 git status查看状态:

    复制代码
    liu@139-159-150-152:~/gitcode$ git status
    On branch master
    Changes to be committed:
      (use "git restore --staged <file>..." to unstage)
    
            modified:   ReadMe

    状态变了!现在 ReadMe文件位于 Changes to be committed区域下,表示修改已经被暂存,准备提交。

  4. 提交修改 (git commit)

    将暂存区的修改提交到版本库。

    复制代码
    liu@139-159-150-152:~/gitcode$ git commit -m "add exclamation mark to ReadMe"
    [master 926f385] add exclamation mark to ReadMe
     1 file changed, 2 insertions(+), 2 deletions(-)

    注意提交信息的描述,要能清晰反映本次修改的目的。

  5. 再次查看状态

    复制代码
    liu@139-159-150-152:~/gitcode$ git status
    On branch master
    nothing to commit, working tree clean

    非常棒!working tree clean表示工作区是干净的,没有任何未暂存或未提交的修改。所有改动都已记录在版本库中。

四、 查看文件修改差异

git status只能告诉我们哪些文件被修改了,但具体修改了什么内容,我们需要 git diff命令。

git diff是一个功能强大的命令,用于比较不同版本、不同分支、工作区、暂存区之间的差异。

场景一:工作区与暂存区的差异

当我们修改了文件,但还没有执行 git add时,可以使用 git diff来查看工作区文件暂存区文件的差异。

  1. 再次修改 ReadMe文件

    复制代码
    liu@139-159-150-152:~/gitcode$ vim ReadMe
    # 在文件末尾新增一行 "I am learning git."
    liu@139-159-150-152:~/gitcode$ cat ReadMe
    hello world!
    hello git!
    I am learning git.
  2. 使用 git diff查看未暂存的修改

    复制代码
    liu@139-159-150-152:~/gitcode$ git diff
    diff --git a/ReadMe b/ReadMe
    index 8e56c2b..7c7a6c3 100644
    --- a/ReadMe
    +++ b/ReadMe
    @@ -1,2 +1,3 @@
     hello world!
     hello git!
    +I am learning git.

    让我们解析这个输出:

    • --- a/ReadMe+++ b/ReadMe:表示比较的是a版本(通常是旧版本/暂存区版本)和b版本(通常为新版本/工作区版本)的 ReadMe文件。

    • @@ -1,2 +1,3 @@:表示在旧版本中,比较范围是从第1行开始的2行;在新版本中,比较范围是从第1行开始的3行。

    • -开头的行(红色,在终端中通常显示为红色)表示在旧版本中存在,但在新版本中被删除的行(本例中没有)。

    • +开头的行(绿色,在终端中通常显示为绿色)表示在新版本中存在,但在旧版本中不存在的行。这里显示新增了 +I am learning git.这一行。

场景二:暂存区与版本库的差异

当我们已经执行了 git add将修改放入暂存区,但还没有提交时,可以使用 git diff --cached(或 git diff --staged,这是更现代的名称)来查看暂存区文件版本库中最后一次提交的差异。

  1. 将刚才的修改添加到暂存区

    复制代码
    liu@139-159-150-152:~/gitcode$ git add ReadMe
  2. 查看暂存区与版本库的差异

    复制代码
    liu@139-159-150-152:~/gitcode$ git diff --cached
    diff --git a/ReadMe b/ReadMe
    index 8e56c2b..7c7a6c3 100644
    --- a/ReadMe
    +++ b/ReadMe
    @@ -1,2 +1,3 @@
     hello world!
     hello git!
    +I am learning git.

    输出与之前类似,因为这次比较的是"暂存区(新)"和"版本库最新提交(旧)"。

场景三:查看两次提交之间的差异

我们可以通过 git diff <commit-id1> <commit-id2>来比较任意两次提交之间的差异。<commit-id>可以是完整的SHA-1哈希值,也可以是它的前几位(通常6-8位就足够唯一标识了)。

  1. 首先查看提交历史,获取提交ID

    复制代码
    liu@139-159-150-152:~/gitcode$ git log --oneline
    926f385 (HEAD -> master) add exclamation mark to ReadMe
    c614289 commit my first file
  2. 比较首次提交和第二次提交的差异

    复制代码
    liu@139-159-150-152:~/gitcode$ git diff c614289 926f385
    diff --git a/ReadMe b/ReadMe
    index 61f422f..8e56c2b 100644
    --- a/ReadMe
    +++ b/ReadMe
    @@ -1,2 +1,2 @@
    -hello world
    -hello git
    +hello world!
    +hello git!

    输出显示,第一次提交(c614289)中的两行没有感叹号,而第二次提交(926f385)中这两行都加上了感叹号。

五、 总结与回顾

本篇我们深入了两个重要的方面:

  1. Git的内部机理 :我们打开了 .git目录这个"黑盒",初步了解了 HEADindexobjectsrefs等核心组件的作用。这有助于我们理解Git的强大和高效是如何实现的。

  2. 文件修改的完整工作流:我们实践了修改文件的标准流程:

    • 修改文件(在工作区)。

    • 使用 git status查看状态,确认哪些文件被修改。

    • 使用 git diff查看工作区与暂存区的详细修改内容。

    • 使用 git add将修改从工作区移动到暂存区

    • 再次使用 git status查看状态,确认修改已暂存。

    • 使用 git diff --cached查看暂存区与版本库的差异。

    • 使用 git commit将修改从暂存区永久提交到版本库

    • 最终 git status显示工作区干净。

这是Git最基本的、也是最核心的单人开发工作流。掌握好 git statusgit diff这两个状态查看和差异分析工具,将使你清楚地知道每一步操作的结果,从而能更自信、更准确地使用Git。

在下一篇博客中,我们将探索Git的"时光机"功能:如何进行版本回退、撤销修改,以及删除被Git管理的文件。

相关推荐
鸿乃江边鸟2 小时前
Spark Datafusion Comet 向量化Rule--CometExecRule分析 规则转换分析
大数据·spark·native
Hello.Reader2 小时前
Flink on Hadoop YARN 从 0 到可上线的 Session / Application 部署指南
大数据·hadoop·flink
小五传输2 小时前
国产FTP服务器软件 如何构建自主可控的文件传输架构?
大数据·运维·安全
木易 士心2 小时前
GitLab 安装指南
git·gitlab
硕博计算机毕设指导2 小时前
【大数据毕设全套源码+文档】Django基于大数据技术的智慧居家养老服务平的设计与实现(丰富项目+远程调试+讲解+定制)
大数据·python·信息可视化·django·毕业设计·课程设计
B站计算机毕业设计超人2 小时前
计算机毕业设计Python+Django考研院校推荐系统 考研分数线预测系统 大数据毕业设计 (代码+LW文档+PPT+讲解视频)
大数据·人工智能·hive·python·django·毕业设计·课程设计
what丶k2 小时前
SQL三大核心查询语法(WHERE/ORDER BY/GROUP BY)综合运用指南
大数据·数据库·sql·mysql·面试
阳艳讲ai3 小时前
九尾狐AI智能矩阵:重构企业获客新引擎
大数据·人工智能
萤丰信息3 小时前
四大核心技术领航,智慧园区重构产业生态新范式
java·大数据·人工智能·智慧城市·智慧园区