Let's take things one step at a time.
Every time you add a file to your repository, usually by adding it to the index and then committing, a snapshot of the whole file is added. A hash is calculated, and this hash is the identifier for this file.
However, if you 5-6 commits down the line manage to restore a files contents back to what it was previously, its new hash will already exist in the repository and thus no additional file will be added. Instead, whatever is going to refer to this file will use the hash but thus refer to the "old" file.
Tree objects are just text files that contains the hashes of the files in the directory, as well as the hashes that identify sub-trees (sub-folders). The hash of tree objects is also calculated from the contents of the tree, and thus depends on the hashes of the files, and the hashes of sub-trees.
In other words, with that above scenario where we restored a file, if we end up restoring the contents of all the files in a repository back to the state they had in a previous commit, the hash of the new tree will already exist and no new tree object will be added. Instead, whatever is going to refer to that tree, a commit most likely, will use the hash and refer to the "old" tree.
In most cases, this is probably a bit theoretical. It is probably not a scenario you will encounter very often that you end up restoring all the files back to some older state. So in practice, every time you create a commit you will most likely also create and add one or more new tree objects as well.
To add a commit without file changes, known as an "empty commit", you can use this git command:
git commit --allow-empty
You can tack on things like -m "message" or the like as you normally would.
Here's an example:
λ git init .
Initialized empty Git repository in D:/Temp/.git/
λ echo a >test.txt
λ git add .
λ git commit -m test1
[master (root-commit) dc613fe] test1
1 file changed, 1 insertion(+)
create mode 100644 test.txt
λ git commit -m test2 --allow-empty
[master c197192] test2
λ git lg
* c197192: (7 seconds ago) test2 (HEAD -> master)
| Lasse Vågsæther Karlsen <[email protected]> (Sat, 20 Apr 2019 23:28:44 +0200)
|
* dc613fe: (17 seconds ago) test1
Lasse Vågsæther Karlsen <[email protected]> (Sat, 20 Apr 2019 23:28:34 +0200)
Now, if I output the contents of those two commits:
λ git cat-file -p c197192
tree 35b422a71005d59dd6af858a3425b608b63f7b5a
parent dc613fe57276009b399d8152a657cb971fad605a
author Lasse Vågsæther Karlsen <[email protected]> 1555795724 +0200
committer Lasse Vågsæther Karlsen <[email protected]> 1555795724 +0200
test2
λ git cat-file -p dc613fe
tree 35b422a71005d59dd6af858a3425b608b63f7b5a
author Lasse Vågsæther Karlsen <[email protected]> 1555795714 +0200
committer Lasse Vågsæther Karlsen <[email protected]> 1555795714 +0200
test1
You can see that they both refer to the exact same tree object, which looks like this:
λ git cat-file -p 35b422a71005d59dd6af858a3425b608b63f7b5a
100644 blob f5eea678d87a8664e4c76e12d3ef5c4ff775ad58 test.txt