Subject: Re: [PATCH v3] doc: add a explanation of Git's data model

From: Junio C Hamano <[email-masked]>
Date: Thu, 16 Oct 2025 09:54:45 -0700

"Julia Evans" <[email-masked]> writes:

>>> +[[tree]]
>>> +trees::
>>> +    A tree is how Git represents a directory. It lists, for each item in
>>> +    the tree:
>>> ++
>>> +[[file-mode]]
>>> +1. The *file mode*, for example `100644`. The format is inspired by Unix
>>> +   permissions, but Git's modes are much more limited. Git only supports these file modes:
>>> ++
>>> +  - `100644`: regular file (with type `blob`)
>>> +  - `100755`: executable file (with type `blob`)
>>> +  - `120000`: symbolic link (with type `blob`)
>>> +  - `040000`: directory (with type `tree`)
>>> +  - `160000`: gitlink, for use with submodules (with type `commit`)
>>
>> It is not really "supporting" file modes.  Rather, Git only records
>> 5 kinds of entities associated with each path in a tree object, and
>> uses numbers taht remotely resemble POSIX file modes to represent
>> these 5 kinds.
>>
>> Perhaps "supports" -> "uses"?
>
> "Uses" sounds good to me.

Also "much more limited" is misleading.  We only represent 5 kinds
of things, so we use only 5 mode-bits-looking numbers.

>>> +2. The *type*: either <<blob,`blob`>> (a file), `tree` (a directory),
>>> +  or <<commit,`commit`>> (a Git submodule, which is a
>>> +  commit from a different Git repository)
>>> +3. The <<object-id,*object ID*>>
>>> +4. The *filename*
>>
>> Here it may be worth noting that this "filename" is a single
>> pathname component (roughly, what you would see in non-recursive
>> "ls").  In other words, it may be a directory name.

Comments?

>>> +[[blob]]
>>> +blobs::
>>> +    A blob is how Git represents a file. A blob object contains the
>>> +    file's contents.
>>
>> "represents a file" hints as if the thing may know its name, but
>> that is not the case (its name is given only by surrounding tree).
>>
>> "A blob is how Git represents uninterpreted series of bytes, and
>> most commonly used to store file's contents." or something, perhaps?
>
> I'll say "A blob is how Git represents a file's contents", unless Git has
> another use for blobs that I don't know about (I think it's not
> that much of a stretch to say that a symbolic link is a special kind
> of file where the "contents" are the the link destination).

A few configuration variables like mailmap.blob name a blob object,
for which _only_ its contents, i.e., the sequence of bytes, matter
and where they originally were stored does not matter.

But we are falling into the area of tautology, as any sequence of
bytes can be stored in a file so they can be called "contents of a
file".  But the point is that these bytes do not have to be stored
to become a blob (think: "git cat-file -t blob -w --stdin").

> I think it's always clearer to be more specific when possible, if there's only
> one purpose for blobs it's unnecessary (and IMO a bit misleading, because
> it makes the reader wonder if there are other purposes that they should
> know about) to say that blobs can be used to store any arbitrary bytes for
> any purpose.

I do not think describing other use cases is unnecessary.  Even if
we limit ourselves to discuss a single purpose for blob, i.e. to
represent the contents of a file, we should stress that blob is to
store _only_ contents, and not other aspects of the file (e.g., in
what paths with what mode), and that is where my reaction to "how
Git reprsents a file" comes from.

>>> +[[branch]]
>>> +branches: `refs/heads/<name>`::
>>> +    A branch is a name for a commit ID.
>>
>> Well a commit ID is an alternative way to refer to a commit object
>> *name*, so it is a bit strange to say "a name for a commit ID".
>>
>> Perhaps "A branch ref stores a commit ID." is better?
>
> I think I'll leave this alone, none of the many test readers reported
> being confused by it.

Would a confused person report that they are confused? ;-)

> I see that you don't like the "name for a commit ID" phrasing :)
> Maybe there's another way to say it, though again none of the test
> readers said they were confused by this or disagreed with the phrasing.

Yes, I get that given "refs/heads/main", you want to say "main" is
one of the ways to have repo_get_oid() to yield the commit object,
and you are using "name" in that sense, but it is more like a ref
can be used to name an object.  It is *not* the name of the object,
because the object can have other names, and more importantly, it
(i.e., to give a name for an object) is not the only thing that a
ref can do.  And that is why I do not like that phrasing, combined
with the target of giving that name is spelled "a commit ID".  The
commit ID is already another way to name the thing the refname can
be also used to name: a commit object.  A commit object and a commit
object name are different things.  The latter is a name that can
refer to the former.  And a ref can be used just like the latter to
refer to the former (i.e. "commit object").

By the way, I do like the way many of your responses are "will think
about it more", not "I'll take your version".

Very much appreciated.

Thanks.