What are the benefits of content based addressing in Git?

Viewed 395

The question:

Git uses content based file addressing system (that is it uses blobs and trees hashes as a "file names"). I was wondering what are the benefits of such addressing system?

I can clearly see some of the benefits, but those are minor:

  1. If someone changes some file in the git repo, it will break all the commits which point to it. Thus you will for sure know that something bad has happend. But is it really that useful?
  2. Using hash for a file decouples real file name from its content and thus you can "cheaply" rename a file...

I feel that the true reason for using sha for file addressing is quite different. Can anyone explain?

P.S. The clarification. The question is about WHY Git uses hashes for addressing files and not HOW does it do so. I know somewhat of a HOW, I need to know WHY.

P.P.S. There is an article about Git principals and why Git looks so strange (because it should be used on a machine where no other software except for core OS and a text editor present), but still this article mentions only this WHY:

if you calculate sha of a file and this sha is already in the objects folder, then you know that you need not store it again, since sha depends on contents.

All right, this WHY I get. Any other WHY use content addressable file system?

2 Answers

One of the most common things git needs to do is to compare two versions of a project. Because the object storage (commits, trees, and blobs) are content addressable, this can be done very quickly by comparing the "filenames".

Additionally when storing content, it is very easy to see if it's a copy of something you're already storing, so you can avoid storing a duplicate.

This hash is a unique ID of an object. You could do the same with blobs that you store in DB - calculate the hash and make it an ID. Which has benefits like:

  1. De-duplication. If you have the same blob (same file in Git) - you won't duplicate the data - it's going to be stored once and be referenced from different places. Which means that:
    • You can copy same file or folder and there won't be any duplicates in Git "database", just multiple references to the same blob. So the amount of space to be stored/transferred is minimized.
    • When you rename/move files - their content won't be added to Git again with a different name. Git will generate the same hash and thus will quickly recognize that no new objects need to be created. Again - same objects will be referenced from different locations.
    • If you remove the file one one commit and then add it again in another commit - still no new objects are created since old ones still reside in .git (they're referenced by older commits thus have to stay in .git).
  2. Also how can you quickly show diff between 2 commits? For Git it's easy since folders are just objects (trees) that reference blobs and other folders - and this information is also content-addressable. So if a tree (folder) now references a different blob/tree (or their names changed) - the hash-based ID will change. So Git can first check the hashes of trees (folders) to see if their content is different and whether Git has to step inside to check for other differences.
  3. You don't have to store additional database (meta-information) about which surrogate ID references which data. The ID can be deduced from the content.

PS: though points 1-2 can be achieved with a surrogate ID too, you'd simply have to store hash along with those IDs. So before storing a new file you'd have to calculate its hash and look up a surrogate ID by the hash in the database. Less convenient, but possible.

Related