Git中的commit:它是快照/状态/映像还是更改/差异/补丁/增量?

6psbrbz9  于 2023-08-01  发布在  Git
关注(0)|答案(4)|浏览(182)
  • Git中的一些操作(例如checkout)似乎假定提交是工作树的快照或状态。
  • Git中的其他操作(例如rebase)似乎假定提交是一个更改:一种可以应用于工作树的算子。

那么,什么是Git commit呢?

deyfvvtc

deyfvvtc1#

虽然可以解释为两者兼而有之,但GitHub工程团队很清楚(12月12日)。2020年):

Commits are snapshots, not diffs

Derrick Stolee开始于

  • 对象ID
  • 斑点(文件内容)
  • 树(目录列表)
  • 提交:快照!

对象ID

关于Git对象,最重要的一点是Git通过对象ID(简称OID)引用每个对象,为对象提供唯一的名称。
我们将使用git rev-parse <ref>命令来发现这些OID。
每个对象本质上都是一个纯文本文件,我们可以使用git cat-file -p <oid>命令检查其内容。

Blob(文件内容)

要查找当前修订版文件的OID,请运行git rev-parse HEAD:<path>
然后,使用git cat-file -p <oid>查找其内容。

Trees(目录列表)

请注意,blob包含文件内容,但不包含文件 * 名称 *!
这些名称来自Git的目录表示:树木
树是路径条目的有序列表,与该路径上的对象类型、文件模式和对象的OID配对。
子目录也被表示为树,所以树可以指向其他树!
最后:

commit:快照时间

提交是时间快照。每个提交都包含一个指向其根目录树的指针,表示当时工作目录的状态

提交具有对应于先前快照的父提交的列表。
没有父提交是根提交,而有多个父提交是合并提交。
提交还包含描述快照的元数据,例如作者和提交者(包括姓名、电子邮件地址和日期)以及提交消息。
提交消息是提交作者相对于父提交描述该提交的目的的机会。
x1c 0d1x的数据
即使提交是快照,我们也经常在历史视图或GitHub上将提交视为差异。事实上,提交消息经常引用这个差异。
通过比较提交和其父提交的根树,从快照数据动态生成差异。Git可以在时间上比较任意两个快照,而不仅仅是相邻的提交。
计算差异是启用git cherry-pickgit rebase的原因。
由于提交不是diff...
Git不跟踪重命名。Git内部没有数据结构来存储在提交和其父提交之间发生的重命名记录。
相反,Git尝试在动态比较计算期间检测重命名。此重命名检测有两个阶段:精确重命名和编辑重命名。
在第一次计算diff后,Git检查diff的内部模型,以发现哪些路径被添加或删除。
自然,从一个位置移动到另一个位置的文件将显示为从第一个位置删除,而在第二个位置添加。Git尝试匹配这些添加和删除以创建一组推断的重命名。

flvtvl50

flvtvl502#

提交是快照状态。当执行git diff时,它计算与父类的差异。这就是为什么可以有多个父代(当存在合并时的情况)。在内部,有增量压缩,但版本模型不是基于补丁的。
Git中的一个核心概念是 index。这是一个包含被跟踪对象树的大对象。当更改从工作副本传播到索引时,将暂存更改;这将索引置于修改状态。提交操作将该状态转换为新的提交。

bkhjykvo

bkhjykvo3#

这里的答案太长了。

  1. Commit是一个小的元数据文件。它包含恢复项目的完整快照的所有信息。
    1.某些命令,如cherry-pickcompute 快照之间的差异。
uajslkp6

uajslkp64#

理解Git粒子波二象性

  • 简短回答:*两者都是
  • 中等回答:* 这取决于**
  • 冗长的回答:* Git有点像量子现象:这两种观点都不能单独解释所有的观察结果。继续读下去。
    在内部,Git将使用两种表示,这取决于(概念上)它认为哪一种在给定提交的存储空间和执行时间方面更有效。快照表示是主要表示。
    从用户的Angular 看,但这取决于你做了什么:

对偶1:作为快照提交与作为变更提交

事实上只有当你把提交看作是工作树的快照时,一些命令才有意义。这在checkout中最为明显,但在stash中也是如此,在fetchreset中至少有一半是如此。
对于其他命令,当您试图以这种方式考虑提交时,可能会导致疯狂。对于那些其他命令,提交明确被视为更改

  • 或者以补丁的形式,您可以查看(例如,showdiff
  • 或者以操作符的形式,您可以应用它来修改您的工作树(例如,applycherry-pickpull
  • 或者以你可以用来修改其他提交的操作符的形式(例如rebase
  • 或者以操作符的形式,你可以应用它来创建新的提交(例如mergecherry-pick

对偶二:作为一个固定的事情提交与像流动的东西一样承诺

二元性1有一个副作用,可能会让习惯于其他版本系统的Git新手感到震惊。事实上,Git似乎甚至不提交自己的提交。
什么?
假设你已经创建了一个分支X,其中包含你喜欢认为是你的提交AB的内容。但是master已经进步了一点,所以你rebase X到master
当你把AB看作变化,而把master看作快照 (嘿,粒子和波在一个实验中!),这不是问题:只需将更改AB应用到快照master
这种想法是如此自然,以至于你几乎不会注意到Git已经重写了你的提交AB:它们现在具有不同的快照内容,因此具有不同的SHA-1 ID。在Git中,作为开发人员,概念上的提交并不是一成不变的,而是在使用仓库时发生变化的动态对象。
相比之下,如果你把这三个(ABmaster)都看作是快照,或者把这三个都看作是变化,你的大脑会受到伤害,你将一事无成。

免责声明

以上是非常简化的描述。在Git现实中

  • 提交根本不是快照,它是一段元数据(快照的 who/when/why)加上指向快照的指针;
  • 快照在Git术语中称为 tree;
  • commiss-as-changes内部表示使用 packfiles;
  • 上述命令中的一些具有不符合相同特征的另外的作用;
  • 并且即使对于给定的角色,在某种程度上,某些命令属于哪一个(或哪些)类别也是品味问题。

不要被Pro Git这本书对Git的第一个描述(在“Git Basics”一节)是 “快照,而不是差异” 这一事实所迷惑。
Git is complicated after all.

相关问题