Boseong Choi
Boseong Choi

Reputation: 2596

Are all tree objects made when commit?

I'm wondering that:

  1. Are all tree object made when committed(maybe commit-tree in plumbing?).
  2. Then why tree objects(especially for directories) are not made in adding to index whereas blobs are?

I figured out blobs are made when I add files to index.

git init
mkdir test-dir
echo "File1" > test-dir/test.txt
git count-objects
# 0 objects, 0 kilobytes
git add test-dir/test.txt
git count-objects
# 1 objects, 4 kilobytes
git ls-files -s
# 100644 03f128cf48cb203d938805e9f3e13b808d1773e9 0       test-dir/test.txt

But I can't find tree object for test-dir until commit.

git commit -m "my first commit"
# [master (root-commit) 48448a5] my first commit
# 1 file changed, 1 insertion(+)
# create mode 100644 test-dir/test.txt
git count-objects
# 4 objects, 16 kilobytes
git rev-list --all --objects
# 48448a5c6d04cbcd6ab25b64c4bbab9dec5fcf94
# 5f618720e3fc14d396086feb6ee1d869fbbf2e21
# 3bdfe0bec6b5140848283e5e55fc0edd9bb52b32 test-dir
# 03f128cf48cb203d938805e9f3e13b808d1773e9 test-dir/test.txt
git cat-file -t 3bdfe0
# tree
git cat-file -p 3bdfe0
# 100644 blob 03f128cf48cb203d938805e9f3e13b808d1773e9    test.txt

Now I get tree object for test-dir directory.

Upvotes: 1

Views: 34

Answers (1)

torek
torek

Reputation: 488183

The tree objects get built by git write-tree. That is, git commit consists of several sub-commands (see notes below):

git write-tree
git commit-tree <parents> <message> <tree-hash-ID>
git update-ref <full-ref> <commit-hash-ID>

The first command, which takes no parameters, turns the index (use git ls-files --stage to view its contents) into a series of tree objects. The top level tree object's hash ID is printed to its standard output.

The second command needs parameters: -p for each parent commit hash ID, -m or -F to supply the commit log message, and the tree hash ID printed by git write-tree. It produces the commit object's hash ID as its standard output.

The last command also needs parameters: the full name of the current branch (e.g., refs/heads/master), or the name HEAD if HEAD is currently detached from any branch, and the commit hash ID produced by the second command. It updates the given ref to hold the given hash ID. If the ref is a branch name, or HEAD, the hash ID should be that of a commit.

Notes

Originally, git commit was a small shell script that simply ran these three commands (with appropriate shell glue). At that time, git commit did not have as many options and flags and modes as it does now.

Eventually git commit became a single C program. It now does all these parts internally. It also handles locking, runs pre-commit hooks, and other such things; these can't be done properly in a shell script using the three individual commands. The three individual commands do still remain, however, so that you can use them to build your own scripts, if you like.

Upvotes: 2

Related Questions