By random chance I ended up in the git internals doc^1 today, also lovely refered to as plumbing and porcelain. It's a fantastic read, very well explained. I wish all doc was written with such explicit care to be understood. It reads like a good friend is trying to explain you something.<p>What got me into that was a 51Gb ".pack" file that I wanted to understand. If you wonder about that, they're pack files, and what that "delta compression" message when you commit is about^2. The 51Gb file though I don't have an explanation for as of yet, I'm guessing something terrible happened before I joined, and people didn't find the courage to forego the history just yet. But at least I got an entertaining read out of it.<p>^1: <a href="https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain" rel="nofollow noreferrer">https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Po...</a><p>^2: <a href="https://git-scm.com/book/en/v2/Git-Internals-Packfiles" rel="nofollow noreferrer">https://git-scm.com/book/en/v2/Git-Internals-Packfiles</a>
If you'd like a more in-depth treatment of the topic, let me suggest chapter 10 of the git book:<p><a href="https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain" rel="nofollow noreferrer">https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Po...</a><p>> But what gets sent to the other git repo? It is everything that is in objects and under refs.<p>Not everything under refs. Just the refs that you push. What gets pushed depends on how you configure git, what arguments you provide to `git push` and how the refspecs are configured for the remote under `.git/config`:<p><a href="https://git-scm.com/book/en/v2/Git-Internals-The-Refspec" rel="nofollow noreferrer">https://git-scm.com/book/en/v2/Git-Internals-The-Refspec</a><p>e.g., I regularly use `git push origin +HEAD:develop` to force push the checked out branch to a destination branch named `develop`.<p>A couple additional points not mentioned:<p>There are also tag objects. You create these with `git tag -a`. These are also called annotated tags. They carry their own message and point to a commit. Without `-a` you create a so-called lightweight tag which is just an entry under `refs/tags` pointing directly to a commit (as opposed to pointing to a tag object).<p><a href="https://git-scm.com/docs/git-tag" rel="nofollow noreferrer">https://git-scm.com/docs/git-tag</a><p>All those loose objects get packed up into pack files periodically to save space and improve git's speed. You can manually run `git gc` but git will do so for you automatically every so many commits. You'll find the pack files under `.git/objects/pack`:<p><a href="https://git-scm.com/book/en/v2/Git-Internals-Packfiles" rel="nofollow noreferrer">https://git-scm.com/book/en/v2/Git-Internals-Packfiles</a>
Nice post, thanks for sharing! I found that another way to learn about Git internals is following a very step by step re-implementation of Git. It really was a very cool and efficient way for me to understand what's in the .git repository.<p>See for example the ugit [1] "build Git from scratch in Python" series for that.<p>[1] <a href="https://www.leshenko.net/p/ugit/" rel="nofollow noreferrer">https://www.leshenko.net/p/ugit/</a>
It's fairly easy to grab info from .git for your own purposes. For example, the program that generates my PS1 peeks there (without wasting precious cycles on shelling out to the git command) to find the current branch we're on:<p><a href="https://github.com/rollcat/etc/blob/b2fd739/cmd/prompter/main.go#L78">https://github.com/rollcat/etc/blob/b2fd739/cmd/prompter/mai...</a>
What's with the random bit flips in pieces that look like they would have been copied from the shell (i.e. likely not typos)?<p>objects/4c -> objects/5c<p>2023-07-02 -> 2024-07-02
just a random comment:<p>the<p><pre><code> .git/info/exclude
</code></pre>
file acts as a personal, private .gitignore you don't have to commit
The way I learn git internals through experimenting is, executing a git command, watch the file changes happen in .git directory, it's pretty fun. I actually wrote a simple cli util to watch the changes: <a href="https://github.com/wong2/meowatch">https://github.com/wong2/meowatch</a>
There is a trend to all these hidden dot folders and files from apps. VS code is another example. Personally I do not like this. Couldn't there be another way for this config files?
On the same topic, I usually refer back to this fantastic talk on how to add and commit a file without using git add or git commit: <a href="https://www.youtube.com/watch?v=mdvlu_R8EWE">https://www.youtube.com/watch?v=mdvlu_R8EWE</a>