前言

这一篇文章其实我筹谋了好久了,从七月暑假开始之时突然对git的源码感兴趣,想要深入了解一下,也确实看了些资料,但最后还是战线拖太长了,注意力转移到其他处了,写博文的事情就一直在todolist呆到现在🫠。
之前也略微写了两篇博文,第一篇大致的记录了git的基础知识包含一些vim的基础知识,第二篇则是主要关注git本地和远程仓库之间的操作,感兴趣的可以爬楼去看。
本打算一篇博客就讲完的,但是学了一下,发现可讲的东西确实有些丰富,就打算开一个系列,系统地讲讲Git。这篇文章也是系列的开始之作,希望能有头有尾吧orz。也算给我锻炼下文笔,努力给大家讲得明明白白的。

引文

要讲Git是什么,我打算还是先让大家了解下git诞生的目的是什么——版本控制🗄️

版本控制简介

版本控制系统(Version Control System,简称VCS)是一种软件工具,用于跟踪文件的更改历史,记录代码在不同时间点的状态。它的核心功能是允许开发者保存项目的多个版本,并能够在需要时回溯、对比、合并这些版本。通过版本控制,团队中的每个开发者都可以轻松地协同工作,同时确保代码的版本历史清晰可追溯。

为什么版本控制对软件开发至关重要?

  1. 保护代码历史:开发者可以在任意时间回滚到之前的某个版本,避免因误操作或错误改动而损坏项目。
  2. 多人协作的基础:VCS 使得多位开发者可以同时在同一个项目中工作,不必担心互相覆盖或干扰彼此的修改。
  3. 管理和追踪更改:每次提交代码都会生成一个记录,包括改动内容、时间和贡献者信息,方便审查和调试。
  4. 支持并行开发:开发者可以在不同的分支上进行并行开发,将不同的功能、修复或实验隔离开,最终可以通过合并整合这些分支。

传统方式的局限性:手动备份和集中式VCS

  • 手动备份:在没有版本控制工具的时代,开发者往往通过复制文件夹来保存项目的不同版本。例如,将文件夹命名为 project_v1, project_v2 来手动记录不同的代码版本。然而,这种方式效率低下,容易混淆,难以快速对比不同版本间的差异。而且,随着项目的复杂度增加,手动管理多个副本变得愈发困难。

  • 集中式版本控制系统(CVS/Subversion):像Subversion (SVN) 这样的早期VCS采取集中式的架构,所有代码和历史记录都存储在中央服务器上,开发者需要实时连接服务器才能访问历史版本。集中式VCS有几个明显的缺点:

    1. 单点故障:如果服务器发生故障,所有开发者的工作都会停滞,且有可能丢失数据。
    2. 操作效率低:每次提交、检出或同步都依赖于服务器,操作速度受限于网络延迟。
    3. 协作复杂:多人同时对同一文件进行修改时,往往容易导致冲突,而集中式系统的分支管理能力较弱,难以灵活处理。

Git的起源故事

之后我们就来简单的了解一下git的历史起源,当然不想听故事的同学可以直接略过,想当故事听的我推荐下B站up主北游老土的相关视频诸神传说:Git的诞生(1)这一系列讲Git和Github的发展历史的视频,我觉得还是蛮有意思的。最让我震惊的还是其中讲到的微软收购github的行为吧,让我对闭源和开源之间的关系有了新的认知,印象中的闭源地头蛇微软居然还维持这开源世界的扛把子github。

背景故事

在2005年,Linux内核项目的开发团队面临着一个巨大的挑战。作为开源社区中最活跃和复杂的项目之一,Linux内核项目依赖于一个名为 [[BitKeeper]] 的版本控制系统(VCS)。然而,BitKeeper并非开源工具,它是由商业公司提供的,并免费提供给Linux开发者使用。Andrew Tridgell通过逆向工程试图破解其协议,以便在不违反许可条款的情况下使用BitKeeper。这引起了BitKeeper公司(由Larry McVoy领导)的不满,导致他们决定撤回向开源社区免费提供BitKeeper的许可。这一事件直接推动了 Linus Torvalds 创建Git。
Andrew Tridgell,他也是一位非常著名的开源软件开发者。他最为人知的成就是开发[[Samba]],一个开源的软件套件,能够在不同的操作系统之间实现文件和打印共享。)
Linus,作为Linux内核的创始人和主要维护者,意识到Linux内核开发迫切需要一种高效、可靠且适合开源社区的版本控制工具。而当时市场上现有的版本控制工具,比如CVS和Subversion(SVN),都无法满足大规模、快速变化的开源项目的需求。出于对这些工具的性能不满,Linus决定自己开发一款新的工具—— Git
2005年4月3日:Linus Torvalds正式开始开发 Git。这是在 BitKeeper 停止免费向开源项目提供支持之后,他决定创建一个新的分布式版本控制系统的起点。2005年4月7日:仅仅四天后,Linus 发布了 Git 的第一个可用版本(0.1)。这个初始版本包含了 Git 的核心功能,如基本的数据结构和操作。 接下来的几周内: Linus 和其他早期贡献者对 Git 进行了快速迭代和改进,逐步完善了其稳定性和功能,以确保它能够胜任管理 Linux 内核代码库的任务。
虽然 Git 的初始版本在四天内发布,但要达到真正用于管理 Linux 内核项目的成熟程度,大约花费了一个月的时间。这包括了持续的优化、功能添加以及社区的反馈和贡献,确保 Git 能够高效、稳定地支持大型项目的需求。
Git之所以能够迅速获得广泛认可,也正是因为它在Linux内核项目这种超大规模、分布式协作项目中展现了极强的性能和稳定性。这种环境对版本控制系统提出了极高的要求,例如高并发、多分支的并行开发以及快速的代码合并,而Git的设计正是为了满足这些需求。因此,Git在开发Linux内核时的表现,验证了它在处理大型代码库时的稳定性和高效性,证明了它的性能下限。

Git的设计原则

一款好的工具应该设计目的明确,针对特定的问题和痛点需求进行解决,否则只会将精力白白浪费在开发出一些无关痛痒、毫无关联乃至是一些画蛇添足的功能上。

开源社区的需求

Git 之所以诞生,不仅仅是为了替代BitKeeper,更是为了解决Linux开发过程中面对的两个核心问题:

  1. 分布式开发:开源项目往往分散在全球各地,多个开发者同时在不同的时间段、不同的地点贡献代码,因此需要一个能支持 分布式开发 的版本控制工具。
  2. 非线性开发流程:在内核开发中,不同的功能、bug修复、优化等需要同时进行,版本控制工具必须具备强大的 分支与合并 能力,以便开发者能在不同分支上并行工作,并最终将这些工作无缝合并到主线代码中。

Linus对现有工具的不满

Linus 对现有集中式版本控制工具(如CVS、Subversion)的不满主要集中在几个方面:

  1. 性能问题:现有工具在处理大型代码库时效率较低,提交、合并操作往往非常缓慢,不能满足Linux内核项目的需求。
  2. 分支管理不灵活:传统工具的分支管理模型复杂且笨重,创建或合并分支的成本高昂。对于频繁需要分支和合并的开源项目,无法做到灵活处理。
  3. 中央服务器的依赖:这些工具依赖中央服务器,这意味着每一次提交、拉取都需要与服务器交互,降低了开发效率。而且,中央服务器一旦故障,整个开发流程可能会瘫痪。
    在这些不满的推动下,Linus决定从根本上重构版本控制工具的架构,创造一种全新的分布式系统,这就是Git。

设计原则

Linus在设计Git时,确立了几个核心目标,这些目标奠定了Git的基础:

  1. 快速:Git的每个操作(如提交、合并、分支切换等)都需要非常高效,能够快速处理数以千计的文件和海量代码。Linus的目标是让Git的基本操作比现有工具快一个数量级。

  2. 高效处理大型代码库:Linux内核是一个庞大的项目,Git需要能够轻松管理数百万行代码,同时保证资源占用少,操作流畅。

  3. 支持非线性开发:Git必须能够处理复杂的并行开发工作流,支持开发者自由创建、切换和合并分支。Git的分支和合并操作设计得极为轻量,让开发者可以毫无顾虑地频繁创建和合并分支。

  4. 数据完整性与安全性:Git的每一次提交都会通过SHA-1哈希生成唯一的ID,确保每个提交的内容不可篡改,同时保障代码历史记录的完整性。

Git核心理念

之后就是引入我们这系列的重头戏了,Git的设计理念围绕着分布式控制、快照管理、不可变对象模型和灵活的分支策略关键概念展开,我会在接下的文章逐个讲解这些核心理念的实现原理。

1. 分布式版本控制

与传统的集中式版本控制系统(如Subversion)不同,Git是一个分布式版本控制系统。这意味着每个开发者在自己的机器上都有一个完整的代码库和历史记录副本,而不依赖于中央服务器。这种设计带来了几个重要优势:

  • 本地操作:开发者可以在没有网络连接的情况下进行提交、查看历史和创建分支等操作,极大提高了操作的灵活性和效率。
  • 数据冗余:即使中央服务器出现故障,开发者依然可以从本地仓库中获取完整的项目历史和版本,这降低了数据丢失的风险。
  • 协作效率:多个开发者可以同时在不同的本地仓库上进行工作,最后将更改合并到主仓库,避免了集中式系统中可能出现的竞争与冲突。

2. 快照与差异

Git采用的核心理念之一是通过 快照 来记录文件的状态,而不是简单记录文件的差异(diff)。在每次提交时,Git会保存当前工作区的快照,记录项目的完整状态。这一机制带来了以下优势:

  • 高效存储:虽然Git保存的是每次提交的快照,但它只会存储自上次快照以来发生变化的部分。这意味着即使是大型项目,Git也能有效管理存储空间。
  • 版本回溯:由于每次提交都是一个完整的快照,开发者可以轻松地回溯到任何历史版本,无需担心文件之间的复杂差异。
    Git使用的 .git 文件夹是版本控制的核心,里面包含了所有的版本历史、对象和元数据。开发者在项目根目录下的 .git 文件夹中,可以找到有关每个提交的详细信息,包括树状结构、作者、时间戳等。这使得Git能够快速检索和还原任何历史版本。

3. 不可变对象模型

Git的内部数据结构依赖于 加密哈希函数(SHA-1),为每个对象(如文件和提交)生成唯一标识。这种设计确保了数据的不可变性:

  • 数据完整性:每个对象的内容会被哈希处理,任何对内容的修改都会导致哈希值的变化,从而提示开发者数据已被更改。
  • 一致性:由于对象的内容与其哈希值紧密关联,Git能够保证版本库的一致性,防止数据丢失或损坏。这种机制使得任何用户都可以安全地信任本地的Git仓库。

4.分支模型

Git的分支模型是其另一大核心优势,采用 轻量级分支 的设计,允许开发者快速、灵活地创建和管理分支:

  • 快速创建与切换:在Git中,创建一个新分支几乎是瞬时的,因为它仅仅是一个指向提交的指针。开发者可以毫不犹豫地创建多个分支,用于开发不同功能、修复bug或进行实验。
  • 无成本的分支管理:由于创建和切换分支的成本极低,Git鼓励开发者频繁使用分支。这使得团队能够在开发过程中保持清晰的结构,轻松地进行并行开发。
  • 便捷的合并操作:Git提供了强大的合并工具,使得将不同分支的工作合并变得简单。开发者可以轻松地将功能分支合并到主分支,或者处理合并冲突。

后记

这篇博文主要还是想从Git诞生的故事开始,简单探讨一些Git的设计原则和核心理念,或许会有些文绉绉的,但是我想任何一个伟大的事情诞生都不是凭空冒出来的,都是背负着过往的历史,立足当下的现实,努力去开创未来的前行方向的。Git的成功不是人为的偶然,而是历史的必然。