Hello! I posted a comic on Mastodon this week about what’s in the .git
directory and someone requested a text version, so here it is. I added some
extra notes too. First, here’s the image. It’s a ~15 word explanation of each
part of your .git
directory.
你好!本周我在 Mastodon 上发布了一篇关于.git
目录中内容的漫画,有人要求提供文本版本,所以就在这里。我还添加了一些额外的注释。首先,这是图像。这是对.git
目录每个部分的约 15 个字的解释。
You can git clone https://github.com/jvns/inside-git
if you want to run all
these examples yourself.
你可以 git clone https://github.com/jvns/inside-git
如果您想自己运行所有这些示例。
Here’s a table of contents:
这是一个目录:
- HEAD: .git/head 头:.git/head
- branch: .git/refs/heads/main
分支:.git/refs/heads/main - commit: .git/objects/10/93da429…
提交:.git/objects/10/93da429… - tree: .git/objects/9f/83ee7550…
树:.git/objects/9f/83ee7550… - blobs: .git/objects/5a/475762c…
斑点:.git/objects/5a/475762c… - reflog: .git/logs/refs/heads/main
引用日志:.git/logs/refs/heads/main - remote-tracking branches: .git/refs/remotes/origin/main
远程跟踪分支:.git/refs/remotes/origin/main - tags: .git/refs/tags/v1.0
标签:.git/refs/tags/v1.0 - the stash: .git/refs/stash
存储:.git/refs/stash - .git/config .git/配置
- hooks: .git/hooks/pre-commit
钩子:.git/hooks/pre-commit - the staging area: .git/index
暂存区:.git/index - this isn’t exhaustive 这并不详尽
- this isn’t meant to completely explain git
这并不是为了完全解释 git
The first 5 parts (HEAD
, branch, commit, tree, blobs) are the core of git.
前 5 个部分( HEAD
、branch、commit、tree、blob)是 git 的核心。
HEAD: .git/head
头: .git/head
HEAD
is a tiny file that just contains the name of your current branch.HEAD
是一个小文件,仅包含当前分支的名称。
Example contents: 示例内容:
$ cat .git/HEAD
ref: refs/heads/main
HEAD
can also be a commit ID, that’s called “detached HEAD state”.HEAD
也可以是提交 ID,这称为“分离的 HEAD 状态”。
branch: .git/refs/heads/main
分支: .git/refs/heads/main
A branch is stored as a tiny file that just contains 1 commit ID. It’s stored
in a folder called refs/heads
.
分支存储为仅包含 1 个提交 ID的小文件。它存储在名为refs/heads
的文件夹中。
Example contents: 示例内容:
$ cat .git/refs/heads/main
1093da429f08e0e54cdc2b31526159e745d98ce0
commit: .git/objects/10/93da429...
提交: .git/objects/10/93da429...
A commit is a small file containing its parent(s), message, tree, and author.
提交是一个小文件,包含其父文件、消息、树和作者。
Example contents: 示例内容:
$ git cat-file -p 1093da429f08e0e54cdc2b31526159e745d98ce0
tree 9f83ee7550919867e9219a75c23624c92ab5bd83
parent 33a0481b440426f0268c613d036b820bc064cdea
author Julia Evans <julia@example.com> 1706120622 -0500
committer Julia Evans <julia@example.com> 1706120622 -0500
add hello.py
These files are compressed, the best way to see objects is with git cat-file -p HASH
.
这些文件被压缩,查看对象的最佳方法是使用git cat-file -p HASH
。
tree: .git/objects/9f/83ee7550...
树: .git/objects/9f/83ee7550...
Trees are small files with directory listings. The files in it are called blobs.
树是带有目录列表的小文件。其中的文件称为blob 。
Example contents: 示例内容:
$ git cat-file -p 9f83ee7550919867e9219a75c23624c92ab5bd83
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 .gitignore
100644 blob 665c637a360874ce43bf74018768a96d2d4d219a hello.py
040000 tree 24420a1530b1f4ec20ddb14c76df8c78c48f76a6 lib
The permissions here LOOK like unix permissions, but they’re actually super
restricted, only 644 and 755 are allowed.
这里的权限看起来像unix权限,但实际上它们是超级受限的,只允许644和755。
blobs: .git/objects/5a/475762c...
斑点: .git/objects/5a/475762c...
blobs are the files that contain your actual code
blob是包含实际代码的文件
Example contents: 示例内容:
$ git cat-file -p 665c637a360874ce43bf74018768a96d2d4d219a
print("hello world!")
Storing a new blob with every change can get big, so git gc
periodically
packs them for efficiency in .git/objects/pack
.
每次更改时存储一个新的 blob 可能会变得很大,因此git gc
会定期将它们打包到.git/objects/pack
中以提高效率。
reflog: .git/logs/refs/heads/main
引用日志: .git/logs/refs/heads/main
The reflog stores the history of every branch, tag, and HEAD. For (mostly) every file in .git/refs
, there’s a corresponding log in .git/logs/refs
.
reflog 存储每个分支、标签和 HEAD 的历史记录。对于(大多数) .git/refs
中的每个文件, .git/logs/refs
中都有相应的日志。
Example content for the main
branch:main
分支的示例内容:
$ tail -n 1 .git/logs/refs/heads/main
33a0481b440426f0268c613d036b820bc064cdea
1093da429f08e0e54cdc2b31526159e745d98ce0
Julia Evans <julia@example.com>
1706119866 -0500
commit: add hello.py
each line of the reflog has:
reflog 的每一行都有:
- before/after commit IDs 提交 ID 之前/之后
- user 用户
- timestamp 时间戳
- log message 记录消息
Normally it’s all one line, I just wrapped it for readability here.
通常都是一行,我只是将其换行以方便阅读。
remote-tracking branches: .git/refs/remotes/origin/main
远程跟踪分支: .git/refs/remotes/origin/main
Remote-tracking branches store the most recently seen commit ID for a remote branch
远程跟踪分支存储远程分支最近看到的提交 ID
Example content: 示例内容:
$ cat .git/refs/remotes/origin/main
fcdeb177797e8ad8ad4c5381b97fc26bc8ddd5a2
When git status says “you’re up to date with origin/main
”, it’s just looking
at this. It’s often out of date, you can update it with git fetch origin
main
.
当 git status 说“你是最新的origin/main
”时,它只是在查看这个。它通常已经过时,您可以使用git fetch origin main
更新它。
tags: .git/refs/tags/v1.0
标签: .git/refs/tags/v1.0
A tag is a tiny file in .git/refs/tags
containing a commit ID.
标签是.git/refs/tags
中的一个小文件,包含提交 ID。
Example content: 示例内容:
$ cat .git/refs/tags/v1.0
1093da429f08e0e54cdc2b31526159e745d98ce0
Unlike branches, when you make new commits it doesn’t update the tag.
与分支不同,当您进行新提交时,它不会更新标签。
the stash: .git/refs/stash
存储: .git/refs/stash
The stash is a tiny file called .git/refs/stash
. It contains the commit ID of a commit that’s created when you run git stash
.
存储是一个名为.git/refs/stash
的小文件。它包含运行git stash
时创建的提交的提交 ID。
cat .git/refs/stash
62caf3d918112d54bcfa24f3c78a94c224283a78
The stash is a stack, and previous values are stored in .git/logs/refs/stash
(the reflog for stash
).
stash 是一个堆栈,以前的值存储在.git/logs/refs/stash
( stash
的 reflog )中。
cat .git/logs/refs/stash
62caf3d9 e85c950f Julia Evans <julia@example.com> 1706290652 -0500 WIP on main: 1093da4 add hello.py
00000000 62caf3d9 Julia Evans <julia@example.com> 1706290668 -0500 WIP on main: 1093da4 add hello.py
Unlike branches and tags, if you git stash pop
a commit from the stash, it’s
deleted from the reflog so it’s almost impossible to find it again. The
stash is the only reflog in git where things get deleted very soon after
they’re added. (entries expire out of the branch reflogs too, but generally
only after 90 days)
与分支和标签不同,如果您从存储中git stash pop
提交,它将从引用日志中删除,因此几乎不可能再次找到它。存储是 git 中唯一的引用日志,其中的内容在添加后很快就会被删除。 (条目也会在分支重新登录后过期,但通常仅在 90 天后过期)
A note on refs: 关于参考文献的注释:
At this point you’ve probably noticed that a lot of things (branches,
remote-tracking branches, tags, and the stash) are commit IDs in .git/refs
.
They’re called “references” or “refs”. Every ref is a commit ID, but the
different types of refs are treated VERY differently by git, so I find it
useful to think about them separately even though they all use
the same file format. For example, git deletes things from the stash reflog in
a way that it won’t for branch or tag reflogs.
此时您可能已经注意到,很多东西(分支、远程跟踪分支、标签和存储)都是.git/refs
中的提交 ID。它们被称为“参考文献”或“参考文献”。每个 ref 都是一个提交 ID,但是 git 处理不同类型的 ref 的方式非常不同,因此我发现单独考虑它们很有用,即使它们都使用相同的文件格式。例如,git 从存储引用日志中删除内容的方式与分支或标记引用日志不同。
.git/config .git/配置
.git/config
is a config file for the repository. It’s where you configure
your remotes..git/config
是存储库的配置文件。您可以在其中配置遥控器。
Example content: 示例内容:
[remote "origin"]
url = git@github.com: jvns/int-exposed
fetch = +refs/heads/*: refs/remotes/origin/*
[branch "main"]
remote = origin
merge refs/heads/main
git has local and global settings, the local settings are here and the global
ones are in ~/.gitconfig
hooks
git 有本地和全局设置,本地设置在这里,全局设置在~/.gitconfig
钩子中
hooks: .git/hooks/pre-commit
钩子: .git/hooks/pre-commit
Hooks are optional scripts that you can set up to run (eg before a commit) to do anything you want.
挂钩是可选脚本,您可以将其设置为运行(例如在提交之前)来执行您想要的任何操作。
Example content: 示例内容:
#!/bin/bash
any-commands-you-want
(this obviously isn’t a real pre-commit hook)
(这显然不是真正的预提交挂钩)
the staging area: .git/index
暂存区: .git/index
The staging area stores files when you’re preparing to commit. This one is a
binary file, unlike a lot of things in git which are essentially plain text
files.
当您准备提交时,暂存区会存储文件。这是一个二进制文件,与 git 中的许多东西不同,后者本质上是纯文本文件。
As far as I can tell the best way to look at the contents of the index is with git ls-files --stage
:
据我所知,查看索引内容的最佳方法是使用git ls-files --stage
:
$ git ls-files --stage
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 .gitignore
100644 665c637a360874ce43bf74018768a96d2d4d219a 0 hello.py
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 lib/empty.py
this isn’t exhaustive 这并不详尽
There are some other things in .git
like FETCH_HEAD
, worktrees
, and
info
. I only included the ones that I’ve found it useful to understand..git
中还有一些其他内容,例如FETCH_HEAD
、 worktrees
和info
。我只包含了那些我认为有助于理解的内容。
this isn’t meant to completely explain git
这并不是为了完全解释 git
One of the most common pieces of advice I hear about git is “just learn how
the .git
directory is structured and then you’ll understand everything!“.
我听到的关于 git 最常见的建议之一是“只要了解.git
目录的结构,然后你就会明白一切!”。
I love understanding the internals of things more than anyone, but there’s a
LOT that “how the .git directory is structured” doesn’t explain, like:
我比任何人都更喜欢了解事物的内部结构,但是有很多“.git 目录是如何构造的”没有解释,例如:
- how merges and rebases work and how they can go wrong (for instance this list of what can go wrong with rebase)
合并和变基如何工作以及它们如何出错(例如这个rebase 可能出错的列表) - how exactly your colleagues are using git, and what guidelines you should be following to work with them successfully
您的同事到底如何使用 git,以及您应该遵循哪些准则才能成功地与他们合作 - how pushing/pulling code from other repositories works
从其他存储库推送/拉取代码的工作原理 - how to handle merge conflicts
如何处理合并冲突
Hopefully this will be useful to some folks out there though.
希望这对一些人有用。
some other references: 其他一些参考:
- the book building git by James Coglan (side note: looks like there’s a 50% off discount for the rest of January)
James Coglan 的 Book Building git (旁注:看起来1 月份剩余时间有 50% 的折扣) - git from the inside out by mary rose cook
由内而外的 git作者:玛丽·罗斯·库克 - the official git repository layout docs
官方git 存储库布局文档