5

如何使用 git hash-object 手动构建 git commit 对象?我现在它适用于 blob,它的文档说它可以使用 -t 构建不同的对象,但是你如何构建一个提交呢?

4

2 回答 2

4

这是一个完整且有效的脚本示例,该脚本无需运行即可创建commit对象git commit

mkdir project
cd project
git init

hash=`echo -n "" | git hash-object -w --stdin`

tree=`echo -e "100644 blob ${hash}\temptyfile" | git mktree`

commit=`echo -e "yourname\nyour@email.com\n2013 12:20:15 +0200\ncommittername\ncommitter@email.com\n2013 10:13:15 +0200" | git commit-tree ${tree}`

git update-ref refs/heads/master ${commit}

要验证脚本是否创建了包含空文件的提交,请运行:

git checkout --
git log --oneline
#2abbdc2 yourname your@email.com 2013 12:20:15 +0200 committername committer@email.com

编辑:修复和改进

于 2013-10-17T10:07:27.303 回答
2

为了读者的利益:

Arialdo Martini 接受的答案是完全正确的,并解释了如何git使用适当的管道命令创建一个空的 repo。请注意,他的变体bare也适用于存储库(您可以emptyfilegit-dir 中创建而不会产生不良副作用)。

这里的答案将其总结为一个稍作调整的脚本:文件的内容取自“stdin”,并且可以将文件放入工作树的子目录中。

脚本git-init-with-file-from-stdin.sh new-git-workdir filename 'commit message'

#!/bin/bash

mkdir "$1" &&
cd "$1" &&
git init &&

dir="$(dirname "$2")" &&
name="$(basename "${2:-dummyfile}")" &&

obid="$(git hash-object -w --stdin)" &&
treeid="$(git mktree < <(printf '100644 blob %q\t%q\n' "$obid" "$name"))" &&

if [ . = "$dir" ]; then git read-tree -i "$treeid";
else git read-tree --prefix="$dir/" -i "$treeid"; fi &&

git commit -m "${3:-automatic commit}" &&
git reset --hard

电话解释

    ./git-init-with-file-from-stdin.sh newgitdir path/to/file <<< "hellOw W0rld"
  • mkdir "$1", cd "$1",git init创建新的git工作树并对其进行初始化。它以第一个参数(此处为newgitdir)命名,假定它在现有路径中命名一个不存在的目录。

  • dir="$(dirname "$2")",name="$(basename "${2:-dummyfile}")"提取第二个参数的路径和名称部分,它定义了想要的文件名。该路径相对于创建的git-workdir。请注意,此参数不能以 a 开头/,否则命令将失败。这里dir=path/toname=file。如果离开,新文件在 -workdir 的顶部称为“dummyfile” git

  • obid="$(git hash-object -w --stdin)"然后将带有从 repo 读取的信息的对象存储stdingitrepo 中,并将新对象的 SHA(对象 id)存储在变量中obid。在示例中,内容hellOw W0rld后跟一个NL.

  • git mktree < <(printf '100644 blob %q\t%q\n' "$obid" "$name")几乎printf '100644 blob %q\t%q\n' "$obid" "$name" | git mktree与创建一个适当的 git-tree 相同。 100644是通常的文件模式。如果你想创建可执行文件,你需要100755在这里。

  • treeid="$(...)"然后将其分配给给定的变量treeid

  • if [ . = "$dir" ]; then git read-tree -i "$treeid";这会将这个新创建的树读入git暂存区以供以后提交。但是,这是针对这种情况,文件应直接位于git-workdir 中。

  • else git read-tree --prefix="$dir/" -i "$treeid"; fi当您想将其放入git-workdir 的子目录时,情况也是如此。好消息是,它git会自动为您创建所有中间目录节点。(可悲的是--prefix="./"产生了一个错误。)

  • git commit -m "${3:-automatic commit}"然后使用众所周知的提交来创建提交

  • git reset --hard然后将git-worktree 与最新的提交同步。

变体的bare变化:

  • git commit除了(这需要一个工作目录)和git reset(你不需要它)之外,一切都类似。

  • 代替

    git init &&
    

    git init --bare &&
    

    也更换

    git commit -m "${3:-automatic commit}" &&
    git reset --hard
    

    具有与已接受答案中相似的顺序:

    commitid="$(git commit-tree "$(git write-tree)" <<< "${3:-automatic commit}")" &&
    git update-ref "refs/heads/master" "$commitid"
    

评论:

于 2017-08-16T14:13:55.740 回答