git commit对象的文件格式是什么?

Tar*_*oys 11 git

上下文:我希望能够通过我的git提交消息和提交进行搜索而无需经历令人费解的复杂git grep命令,因此我决定看看如何存储git commit消息.

我看了一下.git文件夹,它看起来像是存储的提交

.git/objects 
Run Code Online (Sandbox Code Playgroud)

.git对象文件夹包含一堆名称为a6和9b的文件夹.这些文件夹中的每个文件夹都包含一个名称类似于提交的文件2f29598814b07fea915514cfc4d05129967bf7.当我在文本编辑器中打开其中一个文件时,我会感到胡言乱语.

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

    aed8a9f773efb2f498f19c31f8603b6cb2a4bc
    
    Run Code Online (Sandbox Code Playgroud)

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

  3. 有没有办法将这个乱码转换成纯文本,以便我可以在文本编辑器中混淆提交?

Cir*_*四事件 21

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

创建一个简单的存储库,并创建之前的任何打包文件(git gc,git config gc.auto,git-prune-packed...),解压提交物体的距离的方法之一:如何使用命令行工具来提取一个git对象DEFLATE?

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'
python -c "import zlib,sys;sys.stdout.write(zlib.decompress(sys.stdin.read()))" \
  <.git/objects/45/3a2378ba0eb310df8741aa26d1c861ac4c512f | hd

# Second commit.
echo
touch b
git add b
git commit -m 'Second message'
python -c "import zlib,sys;sys.stdout.write(zlib.decompress(sys.stdin.read()))" \
  <.git/objects/74/8e6f7e22cac87acec8c26ee690b4ff0388cbf5 | hd
Run Code Online (Sandbox Code Playgroud)

输出是:

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
Run Code Online (Sandbox Code Playgroud)

然后我们推断出格式如下:

  • 顶层:

    commit {size}\0{content}
    
    Run Code Online (Sandbox Code Playgroud)

    其中{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}
    
    Run Code Online (Sandbox Code Playgroud)

    哪里:

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

      这代表顶级Git repo目录.

      SHA来自树对象的格式:git树对象的内部格式是什么?

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

      parent {parent1_sha}
      parent {parent2_sha}
      ...
      
      Run Code Online (Sandbox Code Playgroud)

      如果没有父母,则列表可以为空,例如,对于回购中的第一次提交.

      两个父母在定期合并提交中发生.

      可能有两个以上的父母git merge -Xoctopus,但这不是一个常见的工作流程.这是一个例子: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 repo,其中包含一些提交:https://github.com/cirosantilli/test-git-web-interface/blob/864d809c36b8f3b232d5b0668917060e8bcba3e8/other-test-repos/util.py #L83

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

以下是标记对象格式的类似分析:git标记对象的格式是什么以及如何计算其SHA?


Twe*_*les 17

在你进一步探讨这条道路之前,我可能会建议你仔细阅读Git手册中关于其内部的部分.我发现知道本章的内容通常是喜欢Git和讨厌它的区别.理解为什么Git以它的方式做事通常会使它对事物的所有奇怪命令更有意义.

要回答你的问题,你看到的乱码就是使用zlib压缩后的对象数据.如果您查看上面链接中的"对象存储"标题,您可以看到有关其工作原理的一些详细信息.这是文件存储在git中的简短版本:

  1. 为内容创建一个特定于git的标头.
  2. 生成标题+内容的串联的散列.
  3. 压缩标题+内容的串联.
  4. 将压缩数据存储到磁盘上,文件夹的名称等于数据散列的前两个字符,文件名的剩余38个字符.

因此,回答第二个问题,文件夹将包含以相同的两个字符开头的所有压缩对象,无论其内容如何.

如果你想看到一个blob的内容,你所要做的就是解压缩它.如果您只想查看文件的内容,可以在大多数编程语言中轻松完成.但是,我会警告你不要试图修改数据.修改文件中的单个字节将改变它的散列.git中的所有元数据(即目录结构和提交)都是使用对哈希的引用进行存储的,因此修改单个文件意味着您还必须更新该文件下游引用该文件哈希的所有对象.然后,您必须更新引用这些哈希值的所有对象.而且,开启,开启和开启...试图实现这一目标变得非常非常复杂.通过学习git内置的命令,你将为自己节省大量的时间和心痛.


Joh*_*ter 5

一句警告

请不要在编辑器中编辑对象。如果不小心,您可能会损坏 Git 存储库。值得花时间学习使用git grep。它实际上与 没有什么不同grep,而且速度要快得多。要搜索提交消息,请查看git log --grep

在底层,git 有一个对象的概念。对象通常由标头和一些数据组成。文件内容存储为 blob 对象。树对象包含文件名并指向表示文件的 blob 对象,以及表示其他目录的树对象。然后是提交对象,它们记录日志消息并指向表示适当树状态的树对象。还有带注释的标签对象,它们通常指向放置在提交上的标签。

该在线书籍提供了有关不同类型的对象以及如何查看它们的一些信息,还包括有关用于存储对象的格式的一些详细信息。

请记住,您所看到的是松散的物体。包文件中还包含对象,它们可以具有不同的格式

Git用户手册还提供了有关对象数据库的详细信息。