4 ms·
Simplest answer: Start with a filesystem like this. They all have a root object with an id that is pointing to a tree. The tree is (name, type, pointer to dat
by DannyBee 3y ago
Simplest answer:
Start with a filesystem like this. They all have a root object with an id that is pointing to a tree. The tree is (name, type, pointer to data):
root object 1:
dir1 directory 2
dir2 directory 3
file1 file 4
file2 file 5
You make a change to file1, and commit it.
What it stores is the following:
root object 6:
dir1 directory 2
dir2 directory 3
file1 file 7
file2 file 5
Note that our new root object stores a complete copy of the filesystem, but all we stored is the following:
1. The new root object, which is a bunch of pointers
2. the new file data
That is very fast to store, and very efficient to store and retrieve. It is not slower to access old data vs new data.
The data is all immutable, all you are storing is pointers to which data is named what.
If you had a file in dir1 instead, you would update the root object and dir1. dir2 would be untouched, so you would still store ... just as much as above.
This is how git works at a high level.
In practice, most commits change a small number of files. So you will update the root object, and all the directory objects on the way to your new file, but that's it.
Most source code trees are lets say 10 directories deep max?
So even if you have a thousand directories, you are updating only the directory objects that are parents of your file's path. So maybe 10 directory objects get updated. All others are untouched.
So O(10) changed directory objects to store, plus the root object, plus the new file data.
Everything else is reused.
This is very fast.
The worst case for something like the above is where you change a file in every directory.
It will then have to rewrite every directory object, even for small file changes.
Or you have flat directories with huge numbers of small files.
You then pay the cost of rewriting the directory objects all the time.
But for most source code layouts, the above works very fast.
Even without compression, the total space usage of your repo is O(total amount of changed data) rather than O(total amount of data represented by all root objects)
1 million revisions of kernel, at 4gig of data each, would be 4PB if you were storing complete copies at every revision.
Instead it's like 9 gigabytes or something, total.