1

我正在玩弄git管道命令以更好地了解其内部机制。我正在尝试在不使用该git commit命令的情况下重现提交。让我们创建一个blob

$ git init
$ echo "I'm an apple" > apple.txt
$ git hash-object -w apple.txt
2d1b0d728be34bfd5e0df0c11b01d61c77ccdc14

现在让我们将它添加到索引中,但使用不同的文件名

$ git update-index --add --cacheinfo 100644 2d1b0d728be34bfd5e0df0c11b01d61c77ccdc14 orange.txt

这是输出git status

$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   orange.txt

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    deleted:    orange.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    apple.txt

这里发生了什么?

apple.txt仍然存在但未被跟踪,这对我来说似乎很正常,因为我将 SHA-1 提供给了blob仅包含文件内容的对象。

让我们继续写树:

$ git write-tree
abbb70126eb9e77aaa65efbe0af0330bda48adf7
$ git cat-file -p abbb70126eb9e77aaa65efbe0af0330bda48adf7
100644 blob 2d1b0d728be34bfd5e0df0c11b01d61c77ccdc14    orange.txt
$ git cat-file -p 2d1b0d728be34bfd5e0df0c11b01d61c77ccdc14
I'm an apple

让我们通过创建指向这棵树的提交来完成这个操作:

$ echo "Add fruit" | git commit-tree abbb70126eb9e77aaa65efbe0af0330bda48adf7
57234c35c0d58713d2b4f57b695043e5331afe58
$ git cat-file -p a4386cb82e1f6d1755e47ace1f378df35df31967
tree abbb70126eb9e77aaa65efbe0af0330bda48adf7
author Gregoire Borel <gregoire.borel@nxxx.xx> 1527001408 +0200
committer Gregoire Borel <gregoire.borel@xxx.xx> 1527001408 +0200

Add fruit

现在,如果我运行git status,输出与上面给出的相同。为什么?此外,似乎还没有创建提交:

$ git log
fatal: your current branch 'master' does not have any commits yet

我错过了什么?

4

2 回答 2

3

您创建了提交,但您没有更新任何 ref 以指向它。你仍然被签出到一个未出生的master分支。(请记住,默认情况下git log会显示已签出内容的历史记录;即使您告诉它显示“全部”,它也会倾向于从 refs 中可以访问的内容。)

您没有在上面显示它,但是当您发布commit-tree它时,它应该已经将哈希打印到标准输出(并且在我按照您的步骤进行的测试中,它确实如此)。因此,正如<commit-hash>您所说的那样

git merge <commit-hash>

更改文件名主要是红鲱鱼。索引和数据库都不包含apple.txt在这种情况下知道的对象,因此apple.txt您注意到它只是工作树上未跟踪的文件。


更新- 作为附加说明,您正在创建没有父级的新提交,这是有道理的,因为您的存储库中还没有任何提交(如果我正确阅读了您的场景)。通常,如果向现有(并已签出)分支添加新提交,则需要提供类似-p HEAD- 的参数,即使这样,commit-tree单独的命令也不会更新分支。

如果您想避免合并(偏爱较低级别的命令),另一种选择是git update-ref,如

git update-ref refs/heads/master 50b7

(这有点危险,因为假设您知道自己在做什么,即使您犯了错误,也更有可能做错事......但这就是管道命令的本质。)

于 2018-05-22T16:14:15.817 回答
1

你还需要跑

git update-ref refs/heads/master a4386cb82e1f6d1755e47ace1f378df35df31967

这会将您的新提交注册为当前 HEAD

于 2018-05-22T16:17:10.567 回答