Shum
Shum

Reputation: 1266

How to get the tree hash of the working copy in git?

With git, how can I get the tree hash of the current state of the git directory? That is, what the tree hash of the commit (not the commit hash) would be if I were to run git add -A followed by git commit?

Upvotes: 3

Views: 1029

Answers (2)

torek
torek

Reputation: 488193

Somewhat easier than Greg Bacon's method:

  • create a temporary index by copying the current index
  • use git add -A to update everything in the temporary index
  • use git commit-tree to turn the temporary index into an actual tree

for which a small shell script (untested) suffices:

#! /bin/sh -e
export GIT_INDEX_FILE=$(mktemp)
trap "rm -f $GIT_INDEX_FILE" 0 1 2 3 15
cp $(git rev-parse --git-dir)/index $GIT_INDEX_FILE
git add -A && git write-tree

The reason to copy the current index is that files that might be ignored (through .gitignore or an exclude file) that are currently tracked (in the regular index) would be ignored when using the temporary index, if we did not prime the temporary index from the real index.

See also your own question How to get the tree hash of the index in git?

Upvotes: 4

Greg Bacon
Greg Bacon

Reputation: 139471

You could attempt to piece it together with git hash-object and git mktree as described in the Raw Git chapter of The Git Community Book, but I suggest the simpler approach of doing all the work on a throwaway detached HEAD.

Assuming you want to begin from the tip of the current branch, go to a detached HEAD state with

git checkout $(git rev-parse HEAD)

Part of the chatty output from git checkout hints at the advantage of doing it this way.

You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout.

Here I create new files that will give git something to do and that represent your real changes with

touch new other stuff blah etc

Now rather than having to reimplement git, let git do what it already does

git add -A .

This stages changes to the index, from which git write-tree will happily create a new tree object. The output on your machine in your repository is the hash you asked about.

git write-tree
afba5669cbf579a9f27f1fda66cb0958282fae3a

The hash written to the standard output is the hash of the tree object just created, but no need to take my word for it.

$ git commit -m 'Throwaway commit'
[detached HEAD 0ae9d12] Throwaway commit
 5 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 blah
 create mode 100644 etc
 create mode 100644 new
 create mode 100644 other
 create mode 100644 stuff

The output hints at the new commit’s SHA1 object name (0ae9d12), which we can confirm with

$ git rev-parse HEAD
0ae9d12408d1ea7eb02821d66f6de8a2f8423e7f

But you want to know the hash of the commit’s tree object, addressable with

$ git rev-parse HEAD^{tree}
afba5669cbf579a9f27f1fda66cb0958282fae3a

Note that the hash is identical to the output from git write-tree.

Now if you want to keep the commit, create a new branch here with git branch. Otherwise, if you ignore it, the commit and unused objects will eventually be discarded as part of git’s ordinary garbage collection.

Upvotes: 1

Related Questions