在Git中,文件内容存储在blob对象中。树对象代表一个目录。它们列出目录中的文件以及存储文件内容的blob。它们还列出子目录和表示子目录的树。从这个意义上说,Git中的树是一个递归数据结构:它可以包含对自身的引用。
替代方案是非递归数据结构,其中单个树对象将列出存储库中的所有跟踪文件,并且不仅存储文件名,而且存储相对于存储库根的完整路径。
我很欣赏Git处理数据的优雅方式,所以我确信Git必须有一个很好的理由来使用递归形式。我提出了几个原因,我抛弃了所有这些原因:
每个子目录的树将允许跟踪目录。它可以启用跟踪空目录。以递归形式存储目录元数据更加优雅(非递归树将需要两种类型的条目来跟踪子目录)。
但是,Git 不跟踪空目录,也不存储目录元数据。
递归树允许未更改的子目录在提交之间共享同一个树。这在具有许多文件的存储库中将更具空间效率,其中每次提交仅更改少量文件,尤其是在使用许多子目录时。
但是,空间效率不是树对象的关注点:packfiles负责压缩,非递归树甚至可以更好地压缩,因为它们包含较少的哈希值(基本上是随机的)。此外,数据到文件的比率通常很大,因此树对象的大小对存储库大小的影响很小。
递归树可能允许更优雅的算法。可以递归地处理存储库上的操作。
但是,(可能是递归地)构建存储库中所有文件的列表,然后在平面列表上操作,在许多情况下甚至更容易。
递归树可以更容易地检测目录重命名。
然而,Git使用启发式方法来检测重命名,所以这没什么用。
我不确定性能上的差异。对我来说,两种表示中的一种表现更快是不明显的。
我的问题是:为什么使用递归形式?使用这种形式有特定的优势吗?