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