《Git版本控制管理(第2版)》——第4章 基本的Git概念 4.1基本概念

简介: Git版本库(repository)只是一个简单的数据库,其中包含所有用来维护与管理项目的修订版本和历史的信息。在Git中,跟大多数版本控制系统一样,一个版本库维护项目整个生命周期的完整副本。然而,不同于其他大多数VCS,Git版本库不仅仅提供版本库中所有文件的完整副本,还提供版本库本身的副本。

本节书摘来自异步社区《Git版本控制管理(第2版)》一书中的第4章,第4.1节,作者:【美】Jon Loeliger , Matthew McCullough著,更多章节内容可以访问云栖社区“异步社区”公众号查看

第4章 基本的Git概念

4.1 基本概念

前一章介绍了Git的一个典型应用,并且可能引发了相当多的问题。Git是否在每次提交时存储整个文件?.git目录的目的是什么?为什么一个提交ID像乱码?我应该注意它吗?

如果你用过其他VCS,比如SVN或者CVS,那么对最后一章的命令可能会很熟悉。事实上,你对一个现代VCS期望的所有操作和功能,Git都能提供。然而,在一些基本的和意想不到的方面,Git会有所不同。

本章会通过讨论Git的关键架构组成和一些重要概念来探讨Git的不同之处和原因。这里注重基础知识并且演示如何与一个版本库交互;第12章会介绍如何操作很多关联的版本库。追踪多个版本库可能看起来是个艰巨的任务,但是你在本章学到的基本原则是一样适用的。
4.1.1 版本库
Git版本库(repository)只是一个简单的数据库,其中包含所有用来维护与管理项目的修订版本和历史的信息。在Git中,跟大多数版本控制系统一样,一个版本库维护项目整个生命周期的完整副本。然而,不同于其他大多数VCS,Git版本库不仅仅提供版本库中所有文件的完整副本,还提供版本库本身的副本。

Git在每个版本库里维护一组配置值。在前面的章节你已经见过其中的一些了,比如,版本库的用户名和email地址。不像文件数据和其他版本库的元数据,在把一个版本库克隆(clone)或者复制到另一个版本库的时候配置设置是不跟着转移的。相反,Git对每个网站、每个用户和每个版本库的配置和设置信息都进行管理与检查。

在版本库中,Git维护两个主要的数据结构:对象库(object store)和索引(index)。所有这些版本库数据存放在工作目录根目录下一个名为.git的隐藏子目录中。

对象库在复制操作的时候能进行有效复制,这也是用来支持完全分布式VCS的一种技术。索引是暂时的信息,对版本库来说是私有的,并且可以在需要的时候按需求进行创建和修改。

接下来的两节将对对象库和索引进行更详细的描述。

4.1.2 Git对象类型
对象库是Git版本库实现的心脏。它包含你的原始数据文件和所有日志消息、作者信息、日期,以及其他用来重建项目任意版本或分支的信息。

Git放在对象库里的对象只有4种类型:块(blob)、目录树(tree)、提交(commit)和标签(tag)。这4种原子对象构成Git高层数据结构的基础。

块(blob)
文件的每一个版本表示为一个块(blob)。blob是“二进制大对象”(binary large object)的缩写,是计算机领域的常用术语,用来指代某些可以包含任意数据的变量或文件,同时其内部结构会被程序忽略。一个blob被视为一个黑盒。一个blob保存一个文件的数据,但不包含任何关于这个文件的元数据,甚至连文件名也没有。

目录树(tree)
一个目录树(tree)对象代表一层目录信息。它记录blob标识符、路径名和在一个目录里所有文件的一些元数据。它也可以递归引用其他目录树或子树对象,从而建立一个包含文件和子目录的完整层次结构。

提交(commit)
一个提交(commit)对象保存版本库中每一次变化的元数据,包括作者、提交者、提交日期和日志消息。每一个提交对象指向一个目录树对象,这个目录树对象在一张完整的快照中捕获提交时版本库的状态。最初的提交或者根提交(root commit)是没有父提交的。大多数提交都有一个父提交,虽然本书后面(第9章)会介绍一个提交如何引用多个父提交。

标签(tag)
一个标签对象分配一个任意的且人类可读的名字给一个特定对象,通常是一个提交对象。虽然9da581d910c9c4ac93557ca4859e767f5caf5169指的是一个确切且定义好的提交,但是一个更熟悉的标签名(如Ver-1.0-Alpha)可能会更有意义!

随着时间的推移,所有信息在对象库中会变化和增长,项目的编辑、添加和删除都会被跟踪和建模。为了有效地利用磁盘空间和网络带宽,Git把对象压缩并存储在打包文件(pack file)里,这些文件也在对象库里。

4.1.3 索引
索引是一个临时的、动态的二进制文件,它描述整个版本库的目录结构。更具体地说,索引捕获项目在某个时刻的整体结构的一个版本。项目的状态可以用一个提交和一棵目录树表示,它可以来自项目历史中的任意时刻,或者它可以是你正在开发的未来状态。

Git的关键特色之一就是它允许你用有条理的、定义好的步骤来改变索引的内容。索引使得开发的推进与提交的变更之间能够分离开来。

下面是它的工作原理。作为开发人员,你通过执行Git命令在索引中暂存(stage)变更。变更通常是添加、删除或者编辑某个文件或某些文件。索引会记录和保存那些变更,保障它们的安全直到你准备好提交了。还可以删除或替换索引中的变更。因此,索引支持一个由你主导的从复杂的版本库状态到一个可推测的更好状态的逐步过渡。

在第9章中,你会看到索引在合并(merge),允许管理、检查和同时操作同一个文件的多个版本中起到的重要作用。

4.1.4 可寻址内容名称
Git对象库被组织及实现成一个内容寻址的存储系统。具体而言,对象库中的每个对象都有一个唯一的名称,这个名称是向对象的内容应用SHA1得到的SHA1散列值。因为一个对象的完整内容决定了这个散列值,并且认为这个散列值能有效并唯一地对应特定的内容,所以SHA1散列值用来做对象数据库中对象的名字和索引是完全充分的。文件的任何微小变化都会导致SHA1散列值的改变,使得文件的新版本被单独编入索引。

SHA1的值是一个160位的数,通常表示为一个40位的十六进制数,比如,9da581d910c9c4ac93557ca4859e767f5caf5169。有时候,在显示期间,SHA1值被简化成一个较小的、唯一的前缀。Git用户所说的SHA1、散列码和对象ID都是指同一个东西。

全局唯一标识符

SHA散列计算的一个重要特性是不管内容在哪里,它对同样的内容始终产生同样的ID。换言之,在不同目录里甚至不同机器中的相同文件内容产生的SHA1哈希ID是完全相同的。因此,文件的SHA1散列ID是一种有效的全局唯一标识符。

这里有一个强大的推论,在互联网上,文件或者任意大小的blob都可以通过仅比较它们的SHA1标识符来判断是否相同。
4.1.5 Git追踪内容
理解Git不仅仅是一个VCS是很重要的,Git同时还是一个内容追踪系统(content tracking system)。这种区别尽管很微小,但是指导了Git的很多设计,并且也许这就是处理内部数据操作相对容易的关键原因。然而,因为这也可能是对新手来讲最难把握的概念之一,所以做一些论述是值得的。

Git的内容追踪主要表现为两种关键的方式,这两种方式与大多数其他①修订版本控制系统都不一样。

首先,Git的对象库基于其对象内容的散列计算的值,而不是基于用户原始文件布局的文件名或目录名设置。因此,当Git放置一个文件到对象库中的时候,它基于数据的散列值而不是文件名。事实上,Git并不追踪那些与文件次相关的文件名或者目录名。再次强调,Git追踪的是内容而不是文件。

如果两个文件的内容完全一样,无论是否在相同的目录,Git在对象库里只保存一份blob形式的内容副本。Git仅根据文件内容来计算每一个文件的散列码,如果文件有相同的SHA1值,它们的内容就是相同的,然后将这个blob对象放到对象库里,并以SHA1值作为索引。项目中的这两个文件,不管它们在用户的目录结构中处于什么位置,都使用那个相同的对象指代其内容。

如果这些文件中的一个发生了变化,Git会为它计算一个新的SHA1值,识别出它现在是一个不同的blob对象,然后把这个新的blob加到对象库里。原来的blob在对象库里保持不变,为没有变化的文件所使用。

其次,当文件从一个版本变到下一个版本的时候,Git的内部数据库有效地存储每个文件的每个版本,而不是它们的差异。因为Git使用一个文件的全部内容的散列值作为文件名,所以它必须对每个文件的完整副本进行操作。Git不能将工作或者对象库条目建立在文件内容的一部分或者文件的两个版本之间的差异上。

文件拥有修订版本和从一个版本到另一个版本的步进,用户的典型看法是这种文件简直是个工艺品。Git用不同散列值的blob之间的区别来计算这个历史,而不是直接存储一个文件名和一系列差异。这似乎有些奇怪,但这个特性让Git在执行某些任务的时候非常轻松。

4.1.6 路径名与内容
跟很多其他VCS一样,Git需要维护一个明确的文件列表来组成版本库的内容。然而,这个需求并不需要Git的列表基于文件名。实际上,Git把文件名视为一段区别于文件内容的数据。这样,Git就把索引从传统数据库的数据中分离出来了。看看表4-1会很有帮助,它粗略地比较了Git和其他类似的系统。
screenshot
文件名和目录名来自底层的文件系统,但是Git并不真正关心这些名字。Git仅仅记录每个路径名,并且确保能通过它的内容精确地重建文件和目录,这些是由散列值来索引的。

Git的物理数据布局并不模仿用户的文件目录结构。相反,它有一个完全不同的结构却可以重建用户的原始布局。在考虑其自身的内部操作和存储方面,Git的内部结构是一种更高效的数据结构。

当Git需要创建一个工作目录时,它对文件系统说:“嘿!我这有这样大的一个blob数据,应该放在路径名为path/to/directory/file的地方。你能理解吗?”文件系统回复说:“啊,是啊,我认出那个字符串是一组子目录名,并且我知道把你的blob数据放在哪里!谢谢!”

4.1.7 打包文件
一个聪明的读者也许已经有了关于Git的数据模型及其单独文件存储的挥之不去的问题:直接存储每个文件每个版本的完整内容是否太低效率了?即使它是压缩的,把相同文件的不同版本的全部内容都存储的效率是否太低了?如果你只添加一行到文件里,Git是不是要存储两个版本的全部内容?

幸运的是,答案是“不是,不完全是!”

相反,Git使用了一种叫做 打包文件(pack file) 的更有效的存储机制。要创建一个打包文件,Git首先定位内容非常相似的全部文件,然后为它们之一存储整个内容。之后计算相似文件之间的差异并且只存储差异。例如,如果你只是更改或者添加文件中的一行,Git可能会存储新版本的全部内容,然后记录那一行更改作为差异,并存储在包里。

存储一个文件的整个版本并存储用来构造其他版本的相似文件的差异并不是一个新伎俩。这个机制已经被其他VCS(如RCS)用了好几十年了,它们的方法本质上是相同的。

然而,Git文件打包得非常巧妙。因为Git是由内容驱动的,所以它并不真正关心它计算出来的两个文件之间的差异是否属于同一个文件的两个版本。这就是说,Git可以在版本库里的任何地方取出两个文件并计算差异,只要它认为它们足够相似来产生良好的数据压缩。因此,Git有一套相当复杂的算法来定位和匹配版本库中潜在的全局候选差异。此外,Git可以构造一系列差异文件,从一个文件的一个版本到第二个,第三个,等等。

Git还维护打包文件表示中每个完整文件(包括完整内容的文件和通过差异重建出来的文件)的原始blob的SHA1值。这给定位包内对象的索引机制提供了基础。

打包文件跟对象库中其他对象存储在一起。它们也用于网络中版本库的高效数据传输。

相关文章
|
8天前
|
存储 开发工具 数据安全/隐私保护
「Mac畅玩鸿蒙与硬件9」鸿蒙开发环境配置篇9 - 使用 Git 进行版本控制
在 HarmonyOS 项目开发中,Git 版本控制可以帮助开发者规范地管理代码变更,确保协作流程顺畅。本篇将详细介绍从创建项目、提交代码到 Git 远程仓库,再到修改、推送更新的完整操作流程,重点演示如何使用 Git 和 GitHub 进行身份验证和版本管理。
37 3
「Mac畅玩鸿蒙与硬件9」鸿蒙开发环境配置篇9 - 使用 Git 进行版本控制
|
1月前
|
Linux 开发工具 git
掌握 Git:版本控制的艺术
Git 是由 Linus Torvalds 开发的分布式版本控制系统,广泛用于代码管理和团队协作。其核心价值在于分布式特性、数据完整性和支持非线性开发。本文介绍 Git 的安装、仓库初始化、文件管理、分支管理、远程仓库操作及撤销操作等基础与高级技巧,助你掌握版本控制的艺术。通过实践,你将能更高效地利用 Git 进行代码管理和团队协作。
|
4月前
|
存储 JavaScript Linux
Git秘籍大公开:从基础概念到高级技巧的全面解析
在软件开发的征途中,Git如同导航明灯,以其分布式、高效的特性引领着团队前行。本篇博客将带您走进Git的世界,从诞生背景到核心操作流程,一一揭秘。我们将深入讲解工作区、暂存区、仓库区的概念,并详述Git单人本地仓库的操作步骤,包括创建、配置、提交、版本管理等。此外,还将展示Git远程仓库(如Github、Gitee)的协作魅力,通过实例演示项目克隆、多人协作、冲突解决及分支管理等高级技巧。
Git秘籍大公开:从基础概念到高级技巧的全面解析
|
11天前
|
Ubuntu 开发工具 git
Git高手必备:掌握这些版本控制最佳实践,让你的代码管理效率翻倍!
【10月更文挑战第25天】使用 Git 进行版本控制是现代软件开发的重要部分。本文详细介绍了 Git 的安装、配置、基本操作、分支管理、冲突解决及常用命令,帮助开发者提高工作效率,确保代码质量和团队协作的顺利进行。通过合理使用 Git,可以有效管理代码变更,支持多人协作,并追踪历史记录。
39 4
|
11天前
|
开发工具 C# git
C#一分钟浅谈:Git 版本控制与 GitFlow 工作流
【10月更文挑战第22天】本文介绍了 Git 和 GitFlow 的结合使用,从基础概念到具体操作,涵盖了安装配置、基本命令、GitFlow 工作流的核心分支和流程示例。同时,文章还讨论了常见的问题和易错点,如忽略文件、冲突解决、回退提交和分支命名规范,并提供了代码案例。通过学习本文,读者可以更好地理解和应用 Git 及 GitFlow,提高团队协作效率。
39 1
|
10天前
|
开发工具 git 开发者
|
1月前
|
编译器 开发工具 数据安全/隐私保护
Git——多人协作/版本控制,在一个gitee仓库下开发(Gitee版教程)手把手教学,包好用的!
本文提供了一个关于如何在Gitee上进行多人协作和版本控制的详细教程,包括新建和初始化仓库、克隆仓库、邀请好友共同管理仓库以及注意事项,旨在帮助用户顺利进行代码协作开发。
119 0
Git——多人协作/版本控制,在一个gitee仓库下开发(Gitee版教程)手把手教学,包好用的!
|
2月前
|
存储 Linux 开发工具
掌握 Git:版本控制的瑞士军刀
在软件开发中,版本控制对于代码管理和团队协作至关重要。Git 是一款由 Linus Torvalds 开发的分布式版本控制系统,广泛应用于各类项目。本文介绍了 Git 的基本原理、核心概念及常用命令,如初始化仓库 (`git init`)、克隆 (`git clone`)、提交 (`git commit`) 和合并 (`git merge`) 等。此外,还分享了编写清晰提交信息、使用分支开发和定期合并等最佳实践,帮助开发者更高效地使用 Git。
|
2月前
|
测试技术 开发工具 git
掌握 Git 分支策略:提升你的版本控制技能
在现代软件开发中,版本控制至关重要,Git 作为最流行的分布式版本控制系统,其分支管理策略对于高效协作和代码维护尤为重要。本文介绍了几种常用的 Git 分支策略,包括主线开发模型、功能分支模型、Gitflow 工作流和 Forking 工作流,并探讨了如何根据项目需求选择合适的分支模型。通过保持 `master` 分支稳定、及时合并清理分支、使用命名规范、利用 Pull Request 进行代码审查及自动化测试等最佳实践,可以显著提升团队协作效率和软件质量。掌握这些策略将帮助开发者更好地管理代码库,加快开发流程。
|
1月前
|
数据可视化 项目管理 开发工具
Git 可视化的实现:提升版本控制体验的利器
Git是最流行的分布式版本控制系统,广泛用于软件开发和项目管理。但其命令行操作复杂,难以直观理解,尤其是涉及分支和合并时。为此,Git可视化工具应运而生,通过图形界面帮助开发者更清晰地理解项目历史、分支结构及变更情况。本文将探讨Git可视化的概念背景、技术方法及相关工具,包括GitKraken、Sourcetree、Gitg、Git Extensions和Tig等,帮助读者掌握其在日常工作中的应用,提升版本管理效率。此外,还将介绍如何结合可视化项目管理工具,如板栗看板,实现更高效的团队协作和任务管理。
31 0