Re: [PATCH v5] doc: add an explanation of Git's data model
- From
Julia Evans <julia@jvns.ca>
- Date
- Nov 3, 2025, 19:43 UTC
- Message-ID
- <8b70796e-b5a4-4f70-8b27-c0ed80d1fc4d@app.fastmail.com>
- In-Reply-To
- <xmqqtszf2kro.fsf@gitster.g>
On Fri, Oct 31, 2025, at 10:44 AM, Junio C Hamano wrote:
Show 86 quoted lines
> "Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> 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. <<objects,Objects>>: commits, trees, blobs, and tag objects
>> +2. <<references,References>>: branches, tags,
>> + remote-tracking branches, etc
>> +3. <<index,The index>>, also known as the staging area
>> +4. <<reflogs,Reflogs>>: 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:
>> + <<commit,commits>>, <<tree,trees>>, <<blob,blobs>>,
>> + and <<tag-object,tag objects>>.
>> +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 *<<tree,tree>>* 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):"
Show 19 quoted lines
>> +[[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.
Show 5 quoted lines
>> +[[branch]] >> +branches: `refs/heads/<name>`:: >> + 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.
Show 21 quoted lines
>> +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 <<reflogs,reflog>> 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.