本文主要是介绍【Git】git 从入门到实战系列(四)—— 工作区、暂存区以及版本库 .git 详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
<> 博客简介:Linux、rtos系统,arm、stm32等芯片,嵌入式高级工程师、面试官、架构师,日常技术干货、个人总结、职场经验分享
<> 公众号:嵌入式技术部落
<> 系列专栏:C/C++、Linux、rtos、嵌入式开发、流媒体、数据结构、网络协议、开源库、CMake、Makefile、架构设计模式等
本文目录
- 一、前言
- 二、工作区
- 三、版本库 .git
- 1、index 文件
- 2、HEAD文件
- 3、logs 文件夹
- 4、objects 文件夹
- 5、refs 文件夹
- 6、info 文件夹
- 7、hooks 文件夹
- 8、branches 文件夹
- 9、config 文件
- 10、description 文件
- 11、COMMIT_EDUTMSG 文件
- 12、FETCH_HEAD文件
- 三、暂存区
- 四、工作区、暂存区和版本库之间的关系
- 五、写在最后
一、前言
上篇文章【Git】git 从入门到实战系列(三)——创建版本库 我们总结了如何创建版本库,以及如何提交本地代码。
本文我们总结工作区、暂存区以及对版本库 .git 文件夹里的内容进行详细介绍。了解工作区、暂存区和 .git 文件夹里的内容,能更透彻的理解 git 的机制,对该专栏后面的内容可以起到辅助的作用。知其然,更要知其所以然,理解的透彻,才能用的更好。
二、工作区
上篇文章【Git】git 从入门到实战系列(三)——创建版本库 我们在文件夹 myProject 中创建的文件 example.txt 其实就处在该 git 文件夹的工作区,这点很好理解吧,换句话说,myProject 文件夹就是一个工作区。(下图为ubuntu环境)
三、版本库 .git
设置勾选显示隐藏文件后,会出现一个 .git 文件夹,这是执行 git init 命令后生成的,.git 文件夹就是版本库。它是 git 版本控制系统用于存储仓库元数据和对象的目录,更是 git 的核心。它包含了 git 仓库的全部信息,包括版本历史、分支、标签、配置等。
可以看到,版本库 .git 也在工作区,.git 文件夹目录内容如下:
.git 目录及其子目录内容,树状图形式显示如下:
.git 文件夹是 Git 版本库的核心,它使得 Git 能够追踪文件的更改、管理分支、记录提交历史等。这个文件夹通常位于项目的根目录下。在通常情况下,用户不太需要直接操作这个文件夹,而是通过 Git 命令来与版本库进行交互。为了更好地了解 git,一起来看看 .git 文件夹下几个重要的文件及文件夹。
1、index 文件
index 文件(也称为 “staging area” 或 “cache”)是一个至关重要的文件,用于暂存即将要提交的文件和更改,或者说存储了将被包含在下一次提交中的文件信息。我们可以理解为这就是 Staging Area 即暂存区的内容。这就是为什么说暂存区的内容其实也被包括在工作区。
2、HEAD文件
HEAD文件用于指示当前所在分支或提交,当前表明我们在本地的 master分支,HEAD 文件的内容是ref: refs/heads/master,如果我们切换到另一本地分支,比如 feature-test,那么这个 HEAD 文件的内容就会显示 ref: refs/heads/feature-test。
HEAD 文件的内容是一个路径文件,我们打开这个路径下的mastrer文件 .git/refs/heads/master
显示为一段 hash 码,这个 hash 码就是我们通过 git commit提交后生成的。通过 git log 查看提交记录,是对应的。
3、logs 文件夹
用于存储 Git 仓库的引用日志信息。
logs文件夹下包括一个 HEAD 文件和一个 refs 文件夹。
HEAD文件
与上一个 HEAD 文件不同,这个 HEAD 文件在 logs 文件夹下,它主要记录的是 HEAD 引用的变化,即当前所在的分支或提交的变化。可用于记录分支切换,版本回退,提交等日志。比如每次切换分支或提交时,都会在这个文件中生成一条记录,包括变化的时间、旧的 HEAD 引用的位置、新的 HEAD 引用的位置等信息。
我们创建一个分支feature-test,然后再回到主分支,看一下 HEAD 文件内容:
refs文件夹
refs 文件夹中包含 heads 和 remotes 两个文件夹,heads 是关于本地仓库的,remotes 很明显是关于远程仓库的。
按照目前的操作你的环境可能看不到 remotes 文件夹,只能看到 heads 文件夹,关于如何将本地代码推送至远程仓库,我们后续文章会详细总结,此处我们先详细介绍一下 remotes 文件夹,大家有个印象。
remotes 文件夹包含一个 origin 文件夹,origin 文件夹内包含一个或多个文件,文件名都是远程分支的名字,其中一个文件是主分支文件 master。这些文件是用于记录远程特定分支的变化,每次该分支发生变化时,都会在这个文件中生成一条记录。
remotes 文件夹内容:
heads 文件夹中包含一个或多个文件,文件名都是本地分支的名字,其中一个文件是主分支文件 master。这些文件是用于记录本地特定分支的变化,每次该分支发生变化时,都会在这个文件中生成一条记录,包括变化的时间、旧的分支位置、新的分支位置等信息。
heads 文件夹内容:
4、objects 文件夹
objects 文件夹是存储数据的核心部分。它主要负责保存项目的所有内容对象,包括文件的实际内容、版本历史、目录结构等。
哈希目录
objects 文件夹中会包含以两级目录结构存储的文件。每个Git对象以其 SHA-1 哈希值为名称。
对象的 SHA-1 哈希值的前两位会被用作子目录名,其余的部分构成文件名。
例如,如果一个对象的 SHA-1 值是 abcd1234567890ef1234567890abcdef12345678,它会被存储在 .git/objects/ab/cd1234567890ef1234567890abcdef12345678 这个路径下。例如上图中的文件夹6a、e5、e6。
在这些哈希目录中,存储了 Git 仓库中的所有对象,包括提交对象、树对象、文件对象等。每个对象都已二进制格式存储在对应的哈希姆目录中,文件内容经过压缩和哈希计算。通过这种方式,Git 可以高效地存储和管理大量的对象,使得版本控制和跟踪文件的变化变得高效和可靠。
info 文件夹:
通常为空,主要用于存放对象的额外信息,可以包含指向具体对象的信息或索引。该文件夹并不是频繁使用的,通常在简单的项目或工具中不会涉及。
pack 文件夹:
包含压缩的对象文件,这些文件通常以 .pack 和 .idx 为扩展名。
当 Git 检测到有许多小的对象时,它会自动将这些对象打包成一个或多个 pack 文件,以提高存储效率和访问速度。
这种方法减少了文件系统的开销,并加快了对历史版本和内容的访问。
注意:objects 目录中的内容是 Git 的内部结构,通常不需要直接操作这些文件。
5、refs 文件夹
refs 文件夹是一个至关重要的目录,其主要用途是存储对 Git 对象的引用。这些引用可以指向具体的提交、标签以及远程分支。
heads文件夹:
存储本地分支的引用,每个文件对应一个分支。每个文件的名称都对应一个本地分支的名称,文件的内容是指向具体提交对象的 SHA-1 哈希值。例如,.git/refs/heads/main 文件的内容可能是 abc123…,指向 main 分支的最新提交。用于快速访问和管理本地分支的状态和版本。
tags文件夹:
存储标签的引用,每个文件对应一个标签。类似于分支,标签文件的名称与标签名称相匹配,文件内容是对应标签指向的提交对象的 SHA-1 哈希值。用于识别并访问项目的特定版本,这在软件发布和版本管理中非常有用。
remotes文件夹:
通常用于存储远程分支的引用。这个目录的存在取决于 Git 的使用情况和配置。包含远程仓库的名称,每个远程分支的引用以 remote/branch 的命名方式存在,这与 .git/refs/remotes/origin/main 这样的结构类似。便于管理和访问不同远程仓库中的分支,帮助用户进行远程协作。
注意: refs 目录中的引用文件是 Git 维护的,不应手动修改或删除这些文件,以免导致仓库状态不一致。
6、info 文件夹
info 文件夹主要用于存放一些额外的配置和信息。
exclude:
这是一个文本文件,功能类似于 .gitignore,用于指定需要忽略的文件或目录。
但是与 .gitignore 不同的是,exclude 文件是针对某个特定 Git 仓库的,而 .gitignore 文件通常可以、并且应该被提交到版本控制中,以便团队成员共享。
通常用于添加本地不想要被追踪的文件或目录,而不希望这些规则影响整个项目或上传到共享的版本库中。
exclude 文件提供了一种为特定仓库添加忽略规则的方法。开发者可以在这个文件中列出不希望被提交到版本库中的文件,而不必在项目的根目录中添加 .gitignore。
存在于 info 文件夹中的配置通常是本地的,适合个人开发或专用环境,不会影响团队其他成员的工作。这样可以保持项目的干净,同时允许每个开发者根据个人需要临时隐藏某些文件。
7、hooks 文件夹
hooks 文件夹是用于存放 Git 钩子脚本的地方。Git 钩子是一些自定义的脚本,可以在特定事件(如提交、合并等)触发时执行,帮助实现自动化的工作流程。
常见的 Git 钩子脚本:
pre-commit:在执行提交操作前运行,可以用于代码检查、格式化等操作,以确保提交的代码符合规范。
pre-receive:在执行推送操作前执行,可以用于进行服务端校验、权限验证等操作,以控制推送到远程仓库的内容。
post-commit:在执行提交操作后运行,可以用于发送通知、执行后续操作等。
post-receive:在执行推送操作后运行,可以用于执行服务器端处理、触发自动部署等操作。
钩子的作用
自动化任务:通过在特定的 Git 事件中插入自定义脚本,可以实现自动化任务,例如运行测试、检查代码风格、更新文档等。
质量控制:使用钩子可以确保代码在提交或推送之前符合特定的标准,从而提高代码质量。
协作规范:团队可以通过配置钩子来统一提交消息的格式,有助于维护项目的整洁性。
集成和部署:钩子可以用于自动集成、部署和其他 CI/CD 的流程。
使用钩子
要使用某个钩子,只需在 hooks 文件夹中创建一个与钩子同名的脚本文件,并且确保该文件具有可执行权限(在 UNIX/Linux 系统上一般使用 chmod +x filename 命令)。根据需要编写代码逻辑,Git 在相应的事件触发时会自动调用这个脚本。
8、branches 文件夹
branches 文件夹是一个相对较少使用的部分,其功能主要是在早期版本的 Git 中用于管理和存储包含远程分支的附加引用。需要指出的是,现在的 Git 通常使用 refs/heads 和 refs/remotes 来管理本地和远程分支,而 branches 文件夹的功能被认为是过时的。
9、config 文件
config 文件用于存储与当前 Git 仓库相关的配置信息。这个文件包含了许多有关版本控制的信息,包括用户信息、仓库设置以及项目的具体配置。
config 文件是一个纯文本文件,使用 INI 格式进行组织,包括多个段落、键值对和注释。每个段落通常以方括号开始,这些段落定义了不同的配置设置。
在 config 文件中,常见的配置项如下:
[core]:包含与 Git 核心功能相关的配置选项,如仓库路径、忽略文件权限等。
repositoryformatversion:标识仓库格式的版本号,通常为 0。
filemode:指示文件模式。如果为 true,Git 将跟踪文件的权限(在 UNIX 系统中)。
bare:指示此仓库是否为裸仓库。裸仓库是一种没有工作区的仓库,主要用于共享目的。
logallrefupdates:指示 Git 是否记录所有引用更新,提升操作的可追溯性。
[remote “<remote-name>”]:用于定义与远程仓库的连接和交互的配置选项,可以指定远程仓库的 URL、分支跟踪等。
url:远程仓库的 URL,通常指向 GitHub、GitLab 或其他托管服务的地址。
fetch:定义从远程仓库获取数据时 Git 的行为,通常包括所有分支的获取路径。
[branch "<branch-name>"]:用于定义分支相关的配置选项,如分支的追踪关系、合并策略等。
remote:指定名为 <name> 的分支的远程配置信息,告诉 Git 默认的远程仓库(通常是 origin)。
merge:指定该分支应跟踪的远程分支,帮助在推送和合并时自动关联。
[user]:用于设置 Git 用户的姓名和邮箱地址,这些信息会出现在提交记录中。
name:表示用户的名称,在提交时显示为作者。这一信息对于追踪代码变更的责任至关重要。
email:用户的电子邮件地址,也会记录在提交信息中,方便其他开发者联系。
细心的读者发现了,上图中并没有[user]一项,这是怎么回事?
这是因为 Git 允许在系统层面或用户层面进行配置。如果你在全局配置中设置了用户信息,你可能在某个特定仓库的 config 文件中找不到 [user] 部分。config 文件夹是每个 Git 仓库独立的,不会被版本控制。我们可以使用 git config --global 命令来修改全局配置文件。如果你想确保 .git/config 中有 [user] 部分,你可以执行以下步骤进行本地配置,也就是用户层面的配置:
git config user.name "Your Name"
git config user.email "you@example.com"
如下图:
你可以查看全局配置:
git config --global --list
使用以下命令列出当前配置:
git config --list
如下图:
上图中查看当前配置出现了两个user和email,因为我们在【Git】git 从入门到实战系列(二)——Git介绍以及安装方法一文中已经执行过了全局配置,上面我们又进行了本地配置,所以会出现两个。
10、description 文件
description 文件是一个文本文件,主要用于描述该 Git 仓库的目的或用途。
description 文件通常只包含一行或少数几行文本,描述该仓库的目标、功能或关键特点。
description 文件的存在与否,以及其内容,与 Git 的基本操作没有直接关系。你可以在没有这个文件的情况下使用 Git 的所有功能。即如果你的仓库中没有description 文件,也不会影响 Git 的正常运行和版本控制功能。
11、COMMIT_EDUTMSG 文件
COMMIT_EDITMSG 是一个文本文件,用于存储最近一次 Git 提交时的提交消息。
当你使用 git commit 命令提交代码时,Git 会打开一个文本编辑器,让你输入提交消息。输入的消息会保存在 COMMIT_EDITMSG 文件中。这个文件包含了你最近一次提交的提交消息内容。
通过编辑 COMMIT_EDITMSG 文件,你可以查看、修改或删除之前的提交消息。这对于需要进行提交消息的审查或修改非常有用。
COMMIT_EDITMSG 文件只记录最近一次提交的提交消息。每次提交后,文件内容会被更新为新的提交消息。旧的提交消息不会保留。
12、FETCH_HEAD文件
FETCH_HEAD 文件是一个特殊的文件,用于保存最近执行 git fetch 命令时获取的对象的引用信息。它记录了从远程分支拉取的数据,包括最新的提交记录和对应的分支信息。
输入命令 git pull --help,可以看到,git pull 是 git fetch 的缩写,其后是 git merge FETCH_HEAD。
FETCH_HEAD 文件是 Git 维护的,不应手动修改或删除这个文件,以免导致仓库状态不一致。每次执行 git fetch,都会覆盖 FETCH_HEAD 文件的内容,因此之前的引用信息会丢失。
关于版本库 .git 文件夹里内容上面我们已一 一总结,需要注意的是,随着项目提交次数的增多,.git 目录占用的空间大小也会增加,因为版本库 .git 文件夹要对提交,下拉等操作数据做记录和跟踪。有的 .git 目录大小甚至可能会比项目源代码本身要大,这主要体现在一些开源库上面。
三、暂存区
通过上面的总结,我们知道了什么是工作区,什么是暂存区。如果您还没明白,那么我们再次总结一下。
.git 是版本库文件,版本库文件所在的目录就是工作区。
暂存区这里叫stage或index,一般是放在.git目录下的 index 文件。
可见版本库包含了暂存区,版本库和暂存区其实也被包括在工作区。
暂存区是Git非常重要的概念,弄明白了暂存区,就弄明白了 Git 的很多操作到底干了什么。
四、工作区、暂存区和版本库之间的关系
上面总结了,版本库和暂存区其实也被包括在工作区,那么在提交代码过程中,三者是什么关系呢?上篇文章【Git】git 从入门到实战系列(三)——创建版本库 讲了我们把文件往Git版本库里添加的时候,是分两步执行的,现在我们结合工作区、暂存区和版本库来重新认识一下:
第一步是用 git add 把文件 example.txt 添加进去,实际上就是把文件修改添加到暂存区;
此处的 HEAD,就是我们上面讲到的 HEAD 文件,git add 命令实际上就是把要提交的所有修改放到暂存区(Stage)。
第二步是用 git commit 提交更改,实际上就是把暂存区的所有内容提交到当前分支。
git commit就可以一次性把暂存区的所有修改提交到分支。
因为我们创建Git版本库时,Git自动为我们创建了唯一 一个master分支,所以,现在,git commit就是往master分支上提交更改。你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
多年前,在我刚开始玩 git 的时候,收集了这样一张图
在这个图中,我们可以看到部分 Git 命令是如何影响工作区、暂存区(stage, index)和版本库的。其实这张图后面还应该加上远程仓库。这个待我们总结完所有命令后回头详细总结这一张图的内容。
五、写在最后
如有疑问或建议,可在评论区交流沟通或添加作者微信沟通交流。作者微信 “_PiaoYaoXiaoWei_”,微信名"骠姚校尉"。
关于工作区、暂存区以及版本库 .git 详解总结完毕,之前我们总结了添加文件,提交文件,该专栏下一篇文章我们总结修改文件,如何对比修改,跟踪修改,撤销修改。
这篇关于【Git】git 从入门到实战系列(四)—— 工作区、暂存区以及版本库 .git 详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!