git/list[1] front-page[2] threads[3] people[4] search[5] about
 

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

From
Patrick Steinhardt <ps@pks.im>
Date
Oct 8, 2025, 04:18 UTC
Message-ID
<aOXmA5L5LsUuXWEh@pks.im>
In-Reply-To
<dbf0727d-66bf-4698-aa21-d69da86027c3@app.fastmail.com>
On Tue, Oct 07, 2025 at 02:55:37PM -0400, Julia Evans wrote:
Show 7 quoted lines
> On Tue, Oct 7, 2025, at 10:32 AM, Patrick Steinhardt wrote:
> > On Fri, Oct 03, 2025 at 05:34:36PM +0000, Julia Evans via GitGitGadget wrote:
> >> diff --git a/Documentation/gitdatamodel.adoc b/Documentation/gitdatamodel.adoc
> >> new file mode 100644
> >> index 0000000000..4b2cb167dc
> >> --- /dev/null
> >> +++ b/Documentation/gitdatamodel.adoc
[snip]
Show 18 quoted lines
> >> +[[tree]]
> >> +trees::
> >> +    A tree is how Git represents a directory. It lists, for each item in
> >> +    the tree:
> >> ++
> >> +1. The *permissions*, for example `100644`
> >
> > I think we should rather call these "mode bits". These bits are
> > permissions indeed when you have a blob, but for subtrees, symlinks and
> > submodules they aren't.
> 
> I think it's a bit strange to call them mode bits since I thought they were stored
> as ASCII strings and it's basically an enum of 5 options, but I see your point.
> I think "file mode" will work and that's used elsewhere.
> 
> I wonder if it would make sense to list all of the possible file modes if
> this isn't documented anywhere else, my impression is that it's a short
> list and that it's unlikely to change much in the future.
Agreed, that seems reasonable to me.
Show 14 quoted lines
> And listing them all might make it more clear that Git's file modes don't
> have much in common with Unix file modes.
> I looked for where this is documented and it looks like the only place is
> in `man git-fast-import` . That man page says that there are just 5 options
> (040000, 160000, 100644, 100755, 120000)
> 
> >> +2. The *type*: either <<blob,`blob`>> (a file), `tree` (a directory),
> >> +  or <<commit,`commit`>> (a Git submodule)
> >
> > There's also symlinks.
> 
> I created a test symlink and it looks like symlinks are stored as type "blob".
> I might say which type corresponds to which file mode,
> though I'm not sure what type corresponds to the "gitlink" mode (commit?).

Yeah, gitlinks are used for submodules. They point to an object ID that refers to a commit in the submodule itself.

Show 8 quoted lines
> I think these are the 5 modes and what they mean / what type they
> should have. Not sure about the gitlink mode though.
> 
>   - `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`)

This list looks good to me. gitlinks are somewhat special given that they refer to a commit stored in the submodule repository, not in the repository that has the gitlink. But the expectation is that the object name should always resolve to a commit indeed.

[snip]
Show 34 quoted lines
> >> +[[blob]]
> >> +blobs::
> >> +    A blob is how Git represents a file. A blob object contains the
> >> +    file's contents.
> >> ++
> >> +Storing a new blob for every new version of a file can get big, so
> >> +`git gc` periodically compresses objects for efficiency in `.git/objects/pack`.
> >
> > I would claim that it's not necessary to mention object compression.
> > This should be a low-level detail that users don't ever have to worry
> > about. Furthermore, packing objects isn't only relevant in the context
> > of blobs: trees for example also tend to compress very well as there
> > typically is only small incremental updates to trees.
> 
> I discussed why I think this important in another reply,
> https://lore.kernel.org/all/51e0a55c-1f1d-4cae-9459-8c2b9220e52d@app.fastmail.com/,
> will paste what I said here. I'll think about this more though.
> 
> paste follows:
> 
> That's true! The reason I think this is important to mention is that I find
> that people often "reject" information that they find implausible, even
> if it comes from a credible source. ("that can't be true! I must be
> not understanding correctly. Oh well, I'll just ignore that!")
> 
> I sometimes hear from users that "commits can't be snapshots", because
> it would take up too much disk space to store every version of
> every commit. So I find that sometimes explaining a little bit about the
> implementation can make the information more memorable.
> 
> Certainly I'm not able to remember details that don't make sense
> with my mental model of how computers work and I don't expect other
> people to either, so I think it's important to give an explanation that
> handles the biggest "objections".

Hm, fair I guess. In any case, if we want to mention this I'd leave away the details how exactly Git achieves this. E.g. we could say something like:

    Storing a new blob for every new version of a file can result to a
    lot of duplication. Git regularly runs repository maintenance to
    optimize to counteract this. Part of the maintenance involves
    compression of objects, where incremental changes to the same object
    are optimized to be stored as deltas, only.

We skip over the details, but this should give enough pointers to an interested reader to go dig deeper. We could also generalize this to objects in general, not only blobs.

[snip]
Show 21 quoted lines
> >> +[[HEAD]]
> >> +HEAD: `.git/HEAD`::
> >> +    `HEAD` is where Git stores your current <<branch,branch>>.
> >> +    `HEAD` is normally a symbolic reference to your current branch, for
> >> +    example `ref: refs/heads/main` if your current branch is `main`.
> >> +    `HEAD` can also be a direct reference to a commit ID,
> >> +    that's called "detached HEAD state".
> >> +
> >> +[[remote-tracking-branch]]
> >> +remote tracking branches: `.git/refs/remotes/<remote>/<branch>`::
> >> +    A remote-tracking branch is a name for a commit ID.
> >> +    It's how Git stores the last-known state of a branch in a remote
> >> +    repository. `git fetch` updates remote-tracking branches. When
> >> +    `git status` says "you're up to date with origin/main", it's looking at
> >> +    this.
> >
> > This misses "refs/remotes/<remote>/HEAD". This reference is a symbolic
> > reference that indicates the default branch on the remote side.
> 
> Is "refs/remotes/<remote>/HEAD" a remote-tracking branch?
> I've never thought about that reference and I'm not sure what to call it.
No, it's not. I think the term we use is "remote reference".
Show 21 quoted lines
> >> +[[other-refs]]
> >> +Other references::
> >> +    Git tools may create references in any subdirectory of `.git/refs`.
> >> +    For example, linkgit:git-stash[1], linkgit:git-bisect[1],
> >> +    and linkgit:git-notes[1] all create their own references
> >> +    in `.git/refs/stash`, `.git/refs/bisect`, etc.
> >> +    Third-party Git tools may also create their own references.
> >> ++
> >> +Git may also create references in the base `.git` directory
> >> +other than `HEAD`, like `ORIG_HEAD`.
> >
> > Let's mention that such references are typically spelt all-uppercase
> > with underscores between. You shouldn't ever create a reference that is
> > for example called ".git/foo".
> >
> > We enforce this restriction inconsistently, only, but I don't think that
> > should keep us from spelling out the common rule.
> 
> That makes sense. I'm also not sure whether third-party
> Git tools are "supposed" to create references outside of "refs/",
> or whether that's common. 

They really shouldn't, and to the best of my knowledge they don't. There is only a rather limited number of root references with very specific use cases. And nowadays we have also tightened the meaning of pseudo refs, of which there are only two ("FETCH_HEAD" and "MERGE_HEAD").

[snip]
Show 12 quoted lines
> >> +[[reflogs]]
> >> +REFLOGS
> >> +-------
> >> +
> >> +Git stores the history of branch, tag, and HEAD refs in a reflog
> >> +(you should read "reflog" as "ref log"). Not every ref is logged by
> >> +default, but any ref can be logged.
> >
> > If we mention this here, do we maybe want to mention how the user can
> > decide which references are logged?
> 
> Do you mean by using the setting `core.logAllRefUpdates`?

Yeah. Otherwise the reader won't have any pointers to figure out _how_ they can change this. I don't think we have a man page that provides a better overview than this configuration.

Thanks!
Patrick
Previous: Julia EvansNext: Junio C Hamano
Message 19 of 89 in “doc: add a explanation of Git's data model”
  1. doc: add a explanation of Git's data modelJulia Evans via GitGitGadget, Oct 3, 2025
  2. Kristoffer HaugsbakkOct 3, 2025
  3. Julia EvansOct 6, 2025
  4. D. Ben KnobleOct 6, 2025
  5. Julia EvansOct 6, 2025
  6. D. Ben KnobleOct 6, 2025
  7. Julia EvansOct 9, 2025
  8. Kristoffer HaugsbakkOct 8, 2025
  9. Junio C HamanoOct 6, 2025
  10. Julia EvansOct 6, 2025
  11. Kristoffer HaugsbakkOct 7, 2025
  12. Junio C HamanoOct 7, 2025
  13. Patrick SteinhardtOct 7, 2025
  14. Junio C HamanoOct 7, 2025
  15. Julia EvansOct 7, 2025
  16. Junio C HamanoOct 7, 2025
  17. D. Ben KnobleOct 7, 2025
  18. Julia EvansOct 7, 2025
  19. Patrick SteinhardtOct 8, 2025
  20. Junio C HamanoOct 8, 2025
  21. Julia EvansOct 8, 2025
  22. doc: add a explanation of Git's data modelJulia Evans via GitGitGadget, Oct 8, 2025
  23. Patrick SteinhardtOct 10, 2025
  24. Junio C HamanoOct 13, 2025
  25. Patrick SteinhardtOct 14, 2025
  26. Julia EvansOct 14, 2025
  27. Patrick SteinhardtOct 14, 2025
  28. Junio C HamanoOct 14, 2025
  29. doc: add a explanation of Git's data modelJulia Evans via GitGitGadget, Oct 14, 2025
  30. Patrick SteinhardtOct 15, 2025
  31. Junio C HamanoOct 15, 2025
  32. Julia EvansOct 15, 2025
  33. Junio C HamanoOct 15, 2025
  34. Julia EvansOct 16, 2025
  35. Junio C HamanoOct 15, 2025
  36. Julia EvansOct 16, 2025
  37. Junio C HamanoOct 16, 2025
  38. Julia EvansOct 16, 2025
  39. Junio C HamanoOct 16, 2025
  40. Kristoffer HaugsbakkOct 16, 2025
  41. Kristoffer HaugsbakkOct 20, 2025
  42. Junio C HamanoOct 20, 2025
  43. doc: add an explanation of Git's data modelJulia Evans via GitGitGadget, Oct 27, 2025
  44. Junio C HamanoOct 27, 2025
  45. Julia EvansOct 28, 2025
  46. Junio C HamanoOct 28, 2025
  47. doc: add an explanation of Git's data modelJulia Evans via GitGitGadget, Oct 30, 2025
  48. Junio C HamanoOct 31, 2025
  49. Patrick SteinhardtNov 3, 2025
  50. Junio C HamanoNov 3, 2025
  51. Julia EvansNov 3, 2025
  52. Junio C HamanoNov 4, 2025
  53. Julia EvansNov 4, 2025
  54. Junio C HamanoNov 4, 2025
  55. Julia EvansNov 4, 2025
  56. Junio C HamanoNov 4, 2025
  57. Julia EvansNov 5, 2025
  58. Ben KnobleNov 5, 2025
  59. Julia EvansNov 5, 2025
  60. Ben KnobleNov 6, 2025
  61. Junio C HamanoOct 31, 2025
  62. Patrick SteinhardtNov 3, 2025
  63. Julia EvansNov 3, 2025
  64. doc: add an explanation of Git's data modelJulia Evans via GitGitGadget, Nov 7, 2025
  65. Junio C HamanoNov 7, 2025
  66. Junio C HamanoNov 7, 2025
  67. Julia EvansNov 7, 2025
  68. Junio C HamanoNov 7, 2025
  69. Junio C HamanoNov 8, 2025
  70. Ben KnobleNov 9, 2025
  71. Junio C HamanoNov 9, 2025
  72. Julia EvansNov 10, 2025
  73. Junio C HamanoNov 11, 2025
  74. Ben KnobleNov 11, 2025
  75. Julia EvansNov 11, 2025
  76. Junio C HamanoNov 12, 2025
  77. Junio C HamanoNov 12, 2025
  78. Julia EvansNov 13, 2025
  79. Junio C HamanoNov 13, 2025
  80. Julia EvansNov 13, 2025
  81. Chris TorekNov 13, 2025
  82. Junio C HamanoNov 13, 2025
  83. doc: add an explanation of Git's data modelJulia Evans via GitGitGadget, Nov 12, 2025
  84. Junio C HamanoNov 12, 2025
  85. Junio C HamanoNov 23, 2025
  86. Patrick SteinhardtDec 1, 2025
  87. Junio C HamanoDec 2, 2025
  88. Julia EvansOct 9, 2025
  89. Ben KnobleOct 10, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.