搜索
首页电脑教程电脑知识Git 提交是差异、快照还是历史记录?

Git 提交是差异、快照还是历史记录?

Feb 19, 2024 am 11:39 AM
git提交快招

Git 提交是差异、快照还是历史记录?

理解Git提交实现方式对我来说很简单,但理解他人对提交的看法却有难度。因此,我在Mastodon上向他人提出了一些问题。

大家是怎么看待 Git 提交的?

我进行了一个 非常不科学的调查,询问大家是怎么看待 Git 提交的:是快照、差异,还是所有之前提交的列表?(当然,把它看作这三者都是合理的,但我很好奇人们的 主要

结果是:

  • 51% 差异
  • 42% 快照
  • 4% 所有之前的提交的历史记录
  • 3% “其他”

我很惊讶差异和快照两个选项的比例如此接近。人们还提出了一些有趣但相互矛盾的观点,比如
“在我看来,提交是一个差异,但我认为它实际上是以快照的形式实现的” 和
“在我看来,提交是一个快照,但我认为它实际上是以差异的形式实现的”。关于提交的实际实现方式,我们稍后再详谈。

在我们进一步讨论之前:我们的说 “一个差异” 或 “一个快照” 都是什么意思?

什么是差异?

我说的“差异”可能相当明显:差异就是你在运行 git show COMMIT_ID 时得到的东西。例如,这是一个 rbspy 项目中的拼写错误修复:

diff --git a/src/ui/summary.rs b/src/ui/summary.rs
index 5c4ff9c..3ce9b3b 100644
--- a/src/ui/summary.rs
+++ b/src/ui/summary.rs
@@ -160,7 +160,7 @@ mod tests {
";
let mut buf: Vec = Vec::new();
-stats.write(&mut buf).expect("Callgrind write failed");
+stats.write(&mut buf).expect("summary write failed");
let actual = String::from_utf8(buf).expect("summary output not utf8");
assert_eq!(actual, expected, "Unexpected summary output");
}

你可以在 GitHub 上看到它: https://github.com/rbspy/rbspy/commit/24ad81d2439f9e63dd91cc1126ca1bb5d3a4da5b

什么是快照?

我说的 “快照” 是指 “当你运行 git checkout COMMIT_ID 时得到的所有文件”。

Git 通常将提交的文件列表称为 “树”(如“目录树”),你可以在 GitHub 上看到上述提交的所有文件:

https://github.com/rbspy/rbspy/tree/24ad81d2439f9e63dd91cc1126ca1bb5d3a4da5b(它是 /tree/ 而不是 /commit/

“Git 是如何实现的”真的是正确的解释方式吗?

我最常听到的关于学习 Git 的建议大概是 “只要学会 Git 在内部是如何表示事物的,一切都会变得清晰明了”。我显然非常喜欢这种观点(如果你花了一些时间阅读这个博客,你就会知道我 喜欢

但是作为一个学习 Git 的方法,它并没有我希望的那么成功!通常我会兴奋地开始解释 “好的,所以 Git
提交是一个快照,它有一个指向它的父提交的指针,然后一个分支是一个指向提交的指针,然后……”,但是我试图帮助的人会告诉我,他们并没有真正发现这个解释有多有用,他们仍然不明白。所以我一直在考虑其他方案。

但是让我们还是先谈谈内部实现吧。

Git 是如何在内部表示提交的 —— 快照

在内部,Git 将提交表示为快照(它存储每个文件当前版本的 “树”)。我在 在一个 Git 仓库中,你的文件在哪里? 中写过这个,但下面是一个非常快速的内部格式概述。

这是一个提交的表示方式:

$ git cat-file -p 24ad81d2439f9e63dd91cc1126ca1bb5d3a4da5b
tree e197a79bef523842c91ee06fa19a51446975ec35
parent 26707359cdf0c2db66eb1216bf7ff00eac782f65
author Adam Jensen1672104452 -0500
committer Adam Jensen1672104890 -0500
Fix typo in expectation message

以及,当我们查看这个树对象时,我们会看到这个提交中仓库根目录下每个文件/子目录的列表:

$ git cat-file -p e197a79bef523842c91ee06fa19a51446975ec35
040000 tree 2fcc102acd27df8f24ddc3867b6756ac554b33ef.cargo
040000 tree 7714769e97c483edb052ea14e7500735c04713eb.github
100644 blob ebb410eb8266a8d6fbde8a9ffaf5db54a5fc979a.gitignore
100644 blob fa1edfb73ce93054fe32d4eb35a5c4bee68c5bf5ARCHITECTURE.md
100644 blob 9c1883ee31f4fa8b6546a7226754cfc84ada5726CODE_OF_CONDUCT.md
100644 blob 9fac1017cb65883554f821914fac3fb713008a34CONTRIBUTORS.md
100644 blob b009175dbcbc186fb8066344c0e899c3104f43e5Cargo.lock
100644 blob 94b87cd2940697288e4f18530c5933f3110b405bCargo.toml

这意味着检出一个 Git 提交总是很快的:对 Git 来说,检出昨天的提交和检出 100 万个提交之前的提交一样容易。Git 永远不需要重新应用 10000 个差异来确定当前状态,因为提交根本就不是以差异的形式存储的。

快照使用 packfile 进行压缩

我刚刚提到了 Git 提交是一个快照,但是,当有人说 “在我看来,提交是一个快照,但我认为它在实现上是一个差异”
时,这其实也是对的!Git
提交并不是以你可能习惯的差异的形式表示的(它们不是以与上一个提交的差异的形式存储在磁盘上的),但基本的直觉是,如果你要对一个 10,000
行的文件编辑 500 次,那么存储 500 份文件的效率会很低。

Git 有一个将文件以差异的形式存储的方法。这被称为 “packfile”,Git 会定期进行垃圾回收,将你的数据压缩成 packfile 以节省磁盘空间。当你 git clone 一个仓库时,Git 也会压缩数据。

这里,我没有足够的篇幅来完整地解释 packfile 是如何工作的(Aditya Mukerjee 的 《解压 Git packfile》是我最喜欢的解释它们是如何工作的文章)。不过,我可以在这里简单总结一下我对 deltas 工作原理的理解,以及它们与 diff 的区别:

  • 对象存储为 “原始文件” 和一个 “变化量delta” 的引用
  • 变化量是一系列例如 “读取第 0 到 100 字节,然后插入字节 ‘hello there’,然后读取第 120 到 200 字节” 的指令。它从原始文件中拼凑出新的文本。所以没有 “删除” 的概念,只有复制和添加。
  • 我认为变化量的层次较少:我不知道如何检查 Git 究竟要经过多少层变化量才能得到一个给定的对象,但我的印象是通常不会很多。可能少于 10 层?不过,我很想知道如何才能真正查出来。
  • 原始文件不一定来自上一个提交,它可以是任何东西。也许它甚至可以来自一个更晚的提交?我不确定。
  • 没有一个 “正确的” 算法来计算变化量,Git 只是有一些近似的启发式算法

当你查看差异时,实际上发生了一些奇怪的事情

当我们运行 git show SOME_COMMIT 来查看某个提交的差异时,实际上发生的事情有点反直觉。我的理解是:

  • Git 会在 packfile 中查找并应用变化量来重建该提交和其父提交的树。
  • Git 会对两个目录树(当前提交的目录树和父提交的目录树)进行差异比较。通常这很快,因为几乎所有的文件都是完全一样的,所以 git 只需比较相同文件的哈希值就可以了,几乎所有时候都不用做什么。
  • 最后 Git 会展示差异
  • 所以,Git 会将变化量转换为快照,然后计算差异。它感觉有点奇怪,因为它从一个类似差异的东西开始,最终得到另一个类似差异的东西,但是变化量和差异实际上是完全不同的,所以这是说得通的。

    也就是说,我认为 Git 将提交存储为快照,而 packfile 只是一个实现细节,目的是节省磁盘空间并加快克隆速度。我其实从来没必要知道 packfile 是如何工作的,但它确实能帮助我理解 Git 是如何在不占用太多磁盘空间的情况下将提交快照化的。

    一个 “错误的” Git 理解:提交是差异

    我认为一个相当常见的,对 Git 的 “错误” 的理解是:

    • 提交是以基于上一个提交的差异的形式存储的(加上指向父提交的指针和作者和消息)。
    • 要获取提交的当前状态,Git 需要从头开始重新应用所有之前的提交。

    这个理解当然是错误的(在现实中,提交是以快照的形式存储的,差异是从这些快照计算出来的),但是对我来说它似乎非常有用而且有意义!在考虑合并提交时会有一点奇怪,但是或许我们可以说这只是基于合并提交的第一个父提交的差异。

    我认为这个错误的理解有的时候非常有用,而且对于日常 Git 使用来说它似乎并没有什么问题。我真的很喜欢它将我们最常使用的东西(差异)作为最基本的元素——它对我来说非常直观。

    我也一直在思考一些其他有用但 “错误” 的 Git 理解,比如:

    • 提交信息可以被编辑(实际上不能,你只是复制了一个相同的提交然后给了它一个新的信息,旧的提交仍然存在)
    • 提交可以被移动到一个不同的基础上(类似地,它们是被复制了)

    我认为有一系列非常有意义的、 “错误” 的对 Git 的理解,它们在很大程度上都受到 Git 用户界面的支持,并且在大多数情况下都不会产生什么问题。但是当你想要撤销一个更改或者出现问题时,它可能会变得混乱。

    将提交视为差异的一些优势

    就算我知道在 Git 中提交是快照,我可能大部分时间也都将它们视为差异,因为:

    • 大多时候我都在关注我正在做的 更改 —— 如果我只是改变了一行代码,显然我主要是在考虑那一行代码而不是整个代码库的当前状态
    • 点击 GitHub 上的 Git 提交或者使用 git show 时,你会看到差异,所以这只是我习惯看到的东西
    • 我经常使用变基,它就是关于重新应用差异的

    将提交视为快照的一些优势

    但是我有时也会将提交视为快照,因为:

    • Git 经常对文件的移动感到困惑:有时我移动了一个文件并编辑了它,Git 无法识别它是否被移动过,而是显示为
      “删除了 old.py,添加了 new.py”。这是因为 Git 只存储快照,所以当它显示 “移动 old.py -> new.py”
      时,只是猜测,因为 old.py 和 new.py 的内容相似。
    • 这种方式更容易理解 git checkout COMMIT_ID 在做什么(重新应用 10000 个提交的想法让我感到很有压力)
    • 合并提交在我看来更像是快照,因为合并的提交实际上可以是任何东西(它只是一个新的快照!)。它帮助我理解为什么在解决合并冲突时可以进行任意更改,以及为什么在解决冲突时要小心。

    其他一些关于提交的理解

    Mastodon 的一些回复中还提到了:

    • 有关提交的 “额外的” 带外信息,比如电子邮件、GitHub 拉取请求或者你和同事的对话
    • 将“差异”视为一个“之前的状态 + 之后的状态”
    • 以及,当然,很多人根据情况的不同以不同的方式看待提交

    人们在谈论提交时使用的其他一些词可能不那么含糊:

    • “修订”(似乎更像是快照)
    • “补丁”(看起来更像是差异)

    就到这里吧!

    我很难了解人们对 Git 有哪些不同的理解。尤其棘手的是,尽管 “错误” 的理解往往非常有用,但人们却非常热衷于警惕 “错误”
    的心智模式,所以人们不愿意分享他们 “错误” 的想法,生怕有什么 Git 解释者会站出来向他们解释为什么他们是错的。(这些 Git
    解释者通常是出于善意的,但是无论如何它都会产生一种负面影响)

    但是我学到了很多!我仍然不完全清楚该如何谈论提交,但是我们最终会弄清楚的。

    感谢 Marco Rogers、Marie Flanagan 以及 Mastodon 上的所有人和我讨论 Git 提交。

    以上是Git 提交是差异、快照还是历史记录?的详细内容。更多信息请关注PHP中文网其他相关文章!

    声明
    本文转载于:每日运维。如有侵权,请联系admin@php.cn删除
    Zlib1.dll缺少或找不到错误?用简单的动作修复 -  MinitoolZlib1.dll缺少或找不到错误?用简单的动作修复 - MinitoolApr 16, 2025 am 12:52 AM

    什么是zlib1.dll?有些人遇到“ zlib1.dll丢失”错误或zlib1.dll试图打开包含zlib1.dll的应用程序时找不到错误。为了解决这些相关错误,PHP.CN网站上的这篇文章可以为您提供一些我

    Autofill在Excel中不起作用吗?这是修复程序! -  MinitoolAutofill在Excel中不起作用吗?这是修复程序! - MinitoolApr 16, 2025 am 12:51 AM

    你们中有些人可能会发现自动填充没有在Excel中工作。您能提出任何解决方案吗?如果没有,那么您就会到达正确的位置。 PHP.CN网站上的这篇文章将为您提供6种方法来解决Excel Autofill无法正常工作的方法。

    Windows 7 Starter Edition:这是什么?如何下载? -  MinitoolWindows 7 Starter Edition:这是什么?如何下载? - MinitoolApr 16, 2025 am 12:50 AM

    什么是Windows 7 Starter版本? Windows 7 Starter版的局限性是什么?如何获得Windows 7首发版ISO?来自PHP.CN的这篇文章为您提供了有关Windows 7 Starter Edition的详细信息。

    使用此顶部指南在Windows中以其他用户的方式运行应用程序使用此顶部指南在Windows中以其他用户的方式运行应用程序Apr 16, 2025 am 12:49 AM

    运行应用程序时,您是否通过登录目前然后登录另一个应用程序来更改帐户感到困扰? PHP.CN收集了一些有效的方法来帮助您在Windows 10和Windows 11中作为其他用户运行应用程序。

    修复:Dropbox下载您的文件有错误修复:Dropbox下载您的文件有错误Apr 16, 2025 am 12:48 AM

    您是否患有“ Dropbox下载文件的错误下载您的文件”错误?现在阅读PHP.CN发表的这篇文章,以获取有关此问题的一些有用解决方案。

    修复所选文件的5种方法未在文件资源管理器中突出显示-Minitool修复所选文件的5种方法未在文件资源管理器中突出显示-MinitoolApr 16, 2025 am 12:47 AM

    您是否对“所选文件在文件资源管理器中未突出显示”的问题感到困扰?您知道如何解决吗?如果没有,您可以在PHP.CN上阅读此帖子,以获取几个可行解决方案,以使所选文件在文件资源管理器中可见。

    修复任务栏中缺少语言栏 - 经过验证的指南修复任务栏中缺少语言栏 - 经过验证的指南Apr 16, 2025 am 12:46 AM

    如果您使用多语言,语言栏是必不可少的。您可以通过从任务栏调整设置来更改输入语言。但是,当您打开计算机时,语言条可能有一天会消失。如何修复语言栏丢失

    如何将外部驱动器连接到Android手机或平板电脑? -  Minitool如何将外部驱动器连接到Android手机或平板电脑? - MinitoolApr 16, 2025 am 12:45 AM

    是否想使用外部驱动器来扩展手机的存储空间?可以这样做。此php.cn帖子向您展示了如何将外部驱动器连接到手机的指南。此外,如果您需要从外部驱动器中恢复数据,则可以尝试PHP

    See all articles

    热AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智能驱动的应用程序,用于创建逼真的裸体照片

    AI Clothes Remover

    AI Clothes Remover

    用于从照片中去除衣服的在线人工智能工具。

    Undress AI Tool

    Undress AI Tool

    免费脱衣服图片

    Clothoff.io

    Clothoff.io

    AI脱衣机

    AI Hentai Generator

    AI Hentai Generator

    免费生成ai无尽的。

    热门文章

    R.E.P.O.能量晶体解释及其做什么(黄色晶体)
    4 周前By尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O.最佳图形设置
    4 周前By尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O.如果您听不到任何人,如何修复音频
    4 周前By尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O.聊天命令以及如何使用它们
    4 周前By尊渡假赌尊渡假赌尊渡假赌

    热工具

    Dreamweaver Mac版

    Dreamweaver Mac版

    视觉化网页开发工具

    EditPlus 中文破解版

    EditPlus 中文破解版

    体积小,语法高亮,不支持代码提示功能

    Atom编辑器mac版下载

    Atom编辑器mac版下载

    最流行的的开源编辑器

    VSCode Windows 64位 下载

    VSCode Windows 64位 下载

    微软推出的免费、功能强大的一款IDE编辑器

    SublimeText3 Mac版

    SublimeText3 Mac版

    神级代码编辑软件(SublimeText3)