gpt4 book ai didi

git - git commit 对象数据结构的文件格式是什么?

转载 作者:IT王子 更新时间:2023-10-29 00:56:43 31 4
gpt4 key购买 nike

上下文:我希望能够搜索我的 git 提交消息和提交,而不必通过令人费解的复杂 git grep 命令,所以我决定看看 git 提交消息是如何存储的。

我查看了 .git 文件夹,在我看来,提交存储在

.git/objects 

.git 对象文件夹包含一堆名称类似于 a6 和 9b 的文件夹。这些文件夹每个都包含一个名称类似于提交 sha 2f29598814b07fea915514cfc4d05129967bf7 的文件。当我在文本编辑器中打开其中一个文件时,出现乱码。

  1. 这个乱码是什么文件格式/git 提交对象是如何存储的?
  2. 在这个 git 提交日志中,文件夹 9b 包含一个提交 sha

    aed8a9f773efb2f498f19c31f8603b6cb2a4bc

    为什么,是否存在文件 9b 中存储多个提交 sha 的情况?

  3. 有没有办法将这些乱码转换为纯文本,以便我可以在文本编辑器中处理提交?

最佳答案

创建一个最小示例并对格式进行逆向工程

创建一个简单的存储库,并在创建任何包文件之前(git gcgit config gc.autogit-prune-packed ...),使用以下方法之一解压缩提交对象:How to DEFLATE with a command line tool to extract a git object?

export GIT_AUTHOR_DATE="1970-01-01T00:00:00+0000"
export GIT_AUTHOR_EMAIL="author@example.com"
export GIT_AUTHOR_NAME="Author Name" \
export GIT_COMMITTER_DATE="2000-01-01T00:00:00+0000" \
export GIT_COMMITTER_EMAIL="committer@example.com" \
export GIT_COMMITTER_NAME="Committer Name" \

git init

# First commit.
echo
touch a
git add a
git commit -m 'First message'
# (for python2, remove the two `.buffer`s in the next line)
python -c "import zlib,sys;sys.stdout.buffer.write(zlib.decompress(sys.stdin.buffer.read()))" \
<.git/objects/45/3a2378ba0eb310df8741aa26d1c861ac4c512f | hd

# Second commit.
echo
touch b
git add b
git commit -m 'Second message'
# (for python2, remove the two `.buffer`s in the next line)
python -c "import zlib,sys;sys.stdout.buffer.write(zlib.decompress(sys.stdin.buffer.read()))" \
<.git/objects/74/8e6f7e22cac87acec8c26ee690b4ff0388cbf5 | hd

输出是:

Initialized empty Git repository in /home/ciro/test/git/.git/

[master (root-commit) 453a237] First message
Author: Author Name <author@example.com>
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 a
00000000 63 6f 6d 6d 69 74 20 31 37 34 00 74 72 65 65 20 |commit 174.tree |
00000010 34 39 36 64 36 34 32 38 62 39 63 66 39 32 39 38 |496d6428b9cf9298|
00000020 31 64 63 39 34 39 35 32 31 31 65 36 65 31 31 32 |1dc9495211e6e112|
00000030 30 66 62 36 66 32 62 61 0a 61 75 74 68 6f 72 20 |0fb6f2ba.author |
00000040 41 75 74 68 6f 72 20 4e 61 6d 65 20 3c 61 75 74 |Author Name <aut|
00000050 68 6f 72 40 65 78 61 6d 70 6c 65 2e 63 6f 6d 3e |hor@example.com>|
00000060 20 30 20 2b 30 30 30 30 0a 63 6f 6d 6d 69 74 74 | 0 +0000.committ|
00000070 65 72 20 43 6f 6d 6d 69 74 74 65 72 20 4e 61 6d |er Committer Nam|
00000080 65 20 3c 63 6f 6d 6d 69 74 74 65 72 40 65 78 61 |e <committer@exa|
00000090 6d 70 6c 65 2e 63 6f 6d 3e 20 39 34 36 36 38 34 |mple.com> 946684|
000000a0 38 30 30 20 2b 30 30 30 30 0a 0a 46 69 72 73 74 |800 +0000..First|
000000b0 20 6d 65 73 73 61 67 65 0a | message.|
000000ba

[master 748e6f7] Second message
Author: Author Name <author@example.com>
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 b
00000000 63 6f 6d 6d 69 74 20 32 32 33 00 74 72 65 65 20 |commit 223.tree |
00000010 32 39 36 65 35 36 30 32 33 63 64 63 30 33 34 64 |296e56023cdc034d|
00000020 32 37 33 35 66 65 65 38 63 30 64 38 35 61 36 35 |2735fee8c0d85a65|
00000030 39 64 31 62 30 37 66 34 0a 70 61 72 65 6e 74 20 |9d1b07f4.parent |
00000040 34 35 33 61 32 33 37 38 62 61 30 65 62 33 31 30 |453a2378ba0eb310|
00000050 64 66 38 37 34 31 61 61 32 36 64 31 63 38 36 31 |df8741aa26d1c861|
00000060 61 63 34 63 35 31 32 66 0a 61 75 74 68 6f 72 20 |ac4c512f.author |
00000070 41 75 74 68 6f 72 20 4e 61 6d 65 20 3c 61 75 74 |Author Name <aut|
00000080 68 6f 72 40 65 78 61 6d 70 6c 65 2e 63 6f 6d 3e |hor@example.com>|
00000090 20 30 20 2b 30 30 30 30 0a 63 6f 6d 6d 69 74 74 | 0 +0000.committ|
000000a0 65 72 20 43 6f 6d 6d 69 74 74 65 72 20 4e 61 6d |er Committer Nam|
000000b0 65 20 3c 63 6f 6d 6d 69 74 74 65 72 40 65 78 61 |e <committer@exa|
000000c0 6d 70 6c 65 2e 63 6f 6d 3e 20 39 34 36 36 38 34 |mple.com> 946684|
000000d0 38 30 30 20 2b 30 30 30 30 0a 0a 53 65 63 6f 6e |800 +0000..Secon|
000000e0 64 20 6d 65 73 73 61 67 65 0a |d message.|
000000eb

那么我们推导出格式如下:

  • 顶层:

    commit {size}\0{content}

    哪里{size}{content} 中的字节数.

    这对所有对象类型都遵循相同的模式。

  • {content} :

    tree {tree_sha}
    {parents}
    author {author_name} <{author_email}> {author_date_seconds} {author_date_timezone}
    committer {committer_name} <{committer_email}> {committer_date_seconds} {committer_date_timezone}

    {commit message}

    哪里:

    • {tree_sha} : 此提交指向的树对象的 SHA。

      这代表顶级 Git 存储库目录。

      那个SHA来自树对象的格式:What is the internal format of a Git tree object?

    • {parents} : 表单的父提交对象的可选列表:

      parent {parent1_sha}
      parent {parent2_sha}
      ...

      如果没有 parent ,则列表可以为空,例如对于 repo 中的第一次提交。

      两个 parent 发生在常规 merge 提交中。

      git merge -Xoctopus 可能有两个以上的 parent ,但这不是一个常见的工作流程。这是一个例子:https://github.com/cirosantilli/test-octopus-100k

    • {author_name} :例如:Ciro Santilli .不能包含 < , \n

    • {author_email} :例如:cirosantilli@mail.com .不能包含 > , \n

    • {author_date_seconds} :自 1970 年以来的秒数,例如946684800是2000年的第一秒

    • {author_date_timezone} :例如:+0000是UTC

    • 提交者字段:类似于作者字段

    • {commit message} : 任意。

我已经制作了一个最小的 Python 脚本,它生成一个带有一些提交的 git 仓库:https://github.com/cirosantilli/test-git-web-interface/blob/864d809c36b8f3b232d5b0668917060e8bcba3e8/other-test-repos/util.py#L83

我用它来做一些有趣的事情,比如:

下面是标签对象格式的类似分析:What is the format of a git tag object and how to calculate its SHA?

关于git - git commit 对象数据结构的文件格式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22968856/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com