如何使用 git hash-object 手动构建 git commit 对象?我现在它适用于 blob,它的文档说它可以使用 -t 构建不同的对象,但是你如何构建一个提交呢?
2 回答
这是一个完整且有效的脚本示例,该脚本无需运行即可创建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
编辑:修复和改进
为了读者的利益:
Arialdo Martini 接受的答案是完全正确的,并解释了如何git
使用适当的管道命令创建一个空的 repo。请注意,他的变体bare
也适用于存储库(您可以emptyfile
在git
-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/to
和name=file
。如果离开,新文件在 -workdir 的顶部称为“dummyfile”git
。obid="$(git hash-object -w --stdin)"
然后将带有从 repo 读取的信息的对象存储stdin
到git
repo 中,并将新对象的 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"
评论:
这里需要
bash
,这意味着它也适用于 Windows 10