From: Julia Evans Date: Mon, 03 Nov 2025 19:43:39 GMT Subject: Re: [PATCH v5] doc: add an explanation of Git's data model Message-ID: <8b70796e-b5a4-4f70-8b27-c0ed80d1fc4d@app.fastmail.com> In-Reply-To: On Fri, Oct 31, 2025, at 10:44 AM, Junio C Hamano wrote: > "Julia Evans via GitGitGadget" writes: > >> diff --git a/Documentation/gitdatamodel.adoc b/Documentation/gitdatamodel.adoc >> new file mode 100644 >> index 0000000000..1cefbb4833 >> --- /dev/null >> +++ b/Documentation/gitdatamodel.adoc >> @@ -0,0 +1,296 @@ >> +gitdatamodel(7) >> +=============== >> + >> +NAME >> +---- >> +gitdatamodel - Git's core data model >> + >> +SYNOPSIS >> +-------- >> +gitdatamodel >> + >> +DESCRIPTION >> +----------- >> + >> +It's not necessary to understand Git's data model to use Git, but it's >> +very helpful when reading Git's documentation so that you know what it >> +means when the documentation says "object", "reference" or "index". >> + >> +Git's core operations use 4 kinds of data: >> + >> +1. <>: commits, trees, blobs, and tag objects >> +2. <>: branches, tags, >> + remote-tracking branches, etc >> +3. <>, also known as the staging area >> +4. <>: logs of changes to references ("ref log") >> + >> +[[objects]] >> +OBJECTS >> +------- >> + >> +All of the commits and files in a Git repository are stored as "Git objects". >> +Git objects never change after they're created, and every object has an ID, >> +like `1b61de420a21a2f1aaef93e38ecd0e45e8bc9f0a`. >> + >> +This means that if you have an object's ID, you can always recover its >> +exact contents as long as the object hasn't been deleted. >> + >> +Every object has: >> + >> +[[object-id]] >> +1. an *ID* (aka "object name"), which is a cryptographic hash of its >> + type and contents. >> + It's fast to look up a Git object using its ID. >> + This is usually represented in hexadecimal, like >> + `1b61de420a21a2f1aaef93e38ecd0e45e8bc9f0a`. >> +2. a *type*. There are 4 types of objects: >> + <>, <>, <>, >> + and <>. >> +3. *contents*. The structure of the contents depends on the type. >> + >> +Here's how each type of object is structured: >> + >> +[[commit]] >> +commit:: >> + A commit contains these required fields >> + (though there are other optional fields): >> ++ >> +1. The full directory structure of all the files in that version of the >> + repository and each file's contents, stored as the *<>* ID >> + of the commit's base directory. > > "base directory" is a new term; I think we most often use > "top-level" directory (in various spellings). > > $ git grep -e 'base directory' -e 'level directory' Documentation/ > >> +[[tree]] >> +tree:: >> + A tree is how Git represents a directory. >> + It can contain files or other trees (which are subdirectories). >> + It lists, for each item in the tree: >> ++ >> +1. The *filename*, for example `hello.py` >> +2. The *file mode*. Git has these file modes. which are only > > "has these" -> "uses only these" to clarify that this is an > exhaustive enumeration and users cannot invent 100664 and others, > which is a mistake Git itself used to make/allow. I like the idea to make it more explicit that this is an exhaustive enumeration. I'll try changing it to this instead: "These are all of the file modes in Git (which are only spiritually related to Unix file modes):" >> +[[tag-object]] >> +tag object:: >> + Tag objects contain these required fields >> + (though there are other optional fields): >> ++ >> +1. The object *ID* it references >> +2. The object *type* > > I would rephrase these to > > 1. The *ID* of the object it references > 2. The *type* of the object it references > > because (1) a tag object references another object, not ID. To name > the object it reference, it uses the object name of it, but just > like your name is not you, object name is not the object (it merely > is *one* way to refer to it). (2) unless it is very clear to readers > that "The object" in 1. and 2. refer to the same object, 2. invites > a question "type of which object?". That makes sense to me, will change it to that. >> +[[branch]] >> +branches: `refs/heads/`:: >> + A branch refers to a commit ID. > > A branch refers to a commit object (by its ID). Ditto for tags. What's the goal of this? I can't tell what misconception you're trying to avoid here. >> +NOTE: Git may delete objects that aren't "reachable" from any reference. >> +An object is "reachable" if we can find it by following tags to whatever >> +they tag, commits to their parents or trees, and trees to the trees or >> +blobs that they contain. >> +For example, if you amend a commit, with `git commit --amend`, >> +the old commit will usually not be reachable, so it may be deleted eventually. >> +Reachable objects will never be deleted. > > Very good write-up. As we would touch upon reflog later in the same > document, we may want to extend the "amend" example a bit, perhaps > like > > Note: Git never deletes objects that are "reachable". An object > is "reachable" if .... An unreachable object may be deleted. > > For example, ... a newly created commit will replace the old > commit and the current branch ref points at the new commit. The > old commit is recorded in the <> of the current > branch, so it is still "reachable", but sufficiently old reflog > entries are expired away, the old commit may become unreachable > at that point, and would get deleted. I like that, will include something similar, lightly reworded. > Other than the above, I found everything very nicely written. > > Thanks.