Droopycom
Droopycom

Reputation: 1921

Reconstruct git hash from an exported repo

I have the content of a git repo (i.e.:working directory) that was exported as a tar.gz archive, and I would like to verify to which tag or commit the archive really correspond to.

I don't think I can go back all the way to the commit, but I think it should at least be possible to generate file and trees hashes and try to match that to the existing commits.

I can see conceptually how to do that, but are there tools or script that do something like that already ?

Upvotes: 1

Views: 365

Answers (4)

jthill
jthill

Reputation: 60235

In your exported dir:

git init
git add .
tree=`git write-tree`

In the repo it came from:

git log --all --format='%T %h' | grep $tree

(or you could get all pretty with it and do %T %h %Cgreen%d%Creset %s)

Upvotes: 0

TwentyMiles
TwentyMiles

Reputation: 4089

If you have a .git directory in your archive, the this is pretty simple. You already have the history, since the .git directory is all you need for a fully functioning git repository. Just untar the archive and begin interacting with git the way you normally would.

If you do not have a .git directory, you will not be able to regenerate any hashes for tags or commits, but you can re-generate the hashes for the files and trees by creating a new git repository in the untared directory and committing all the files there.

git init
git add .
git commit

Because they are based on content, hashes for files will show up the same in the new repository. Depending on how the directories were created in the original repo, the hashes for the trees may show up the same, and they may not. Then you can use something like git status to compare the root tree of the commits in your original repository to those in the new one.

That being said, if you have access to the original repository, and a general idea of when the archive was created, it might be easier to just create a script that will checkout commits, archive them, and then compare them to archive you are trying to match. It might not be faster to do it that way, but it will let the script do most of the work instead of forcing you to.

Upvotes: 0

JB.
JB.

Reputation: 42094

git filter-branch provides a lot of the machinery to go through a list of trees; all that's left to plug in is a best-match comparison. You might try and simply use git status for that.

For example, assuming you're somewhere git recognizes or have set GIT_DIR appropriately:

$ git filter-branch --index-filter \
    'GIT_WORK_TREE=/path/to/archive git status --porcelain | wc -l'
Rewrite a2c4140ec0c94c31164ff44b6721ae2f2c83e5b3 (1/10)23
Rewrite e5fd02d47c4c1723b9c0e5ec787636c64c8e3c6b (2/10)22
Rewrite 74932cbcad41e9a001a4c841d3e16ac3376f21be (3/10)22
Rewrite 639f7944f3d9a49d995ddffd238b1e553e972898 (4/10)21
Rewrite 9784f3015d46107c900897f759a82dce9f64bf7e (5/10)16
Rewrite 30ced58105248343bd43c99f8d32790693640bc3 (6/10)12
Rewrite 07cba40558d16e24cb3cbc0fd8ab477ef2722df3 (7/10)12
Rewrite a0553b0608225c5c59f25d284ff1a57bb8040b94 (8/10)4
Rewrite 5438477bfd33a0e338fe58a126eef80e16108094 (9/10)3
Rewrite 60748e131596cf2999134e6506604f763cc3e238 (10/10)1

WARNING: Ref 'refs/heads/master' is unchanged

The lowest number would be a good indicator of a match. In my case, it's the last commit (HEAD). With the current version of git filter-branch, it can't get to zero, there'll always be a ./git-rewrite/ internal-use file around.

Note: the warning is actually good news—we don't intend to rewrite the branch, and it reminds us we haven't messed up anything in the process.

Upvotes: 1

torek
torek

Reputation: 487705

Don't know of any, but the obvious solution is to create a git directory and check the contents in. Then, read the tree out of the commit you just generated:

$ mkdir temp
$ cd temp
$ git init
$ tar xf ...
$ git add .; git commit -m 'just for hash'
$ git cat-file -p HEAD | awk '/^tree / { print $2 }' # or grep ^tree

Unfortunately this only gets you the tree ID (not a commit ID), but now you can just check each commit in the "real" repo to see if its tree matches. If so, that's the commit:

$ lookfor=$(git cat-file -p HEAD | grep ^tree)
$ cd /real/repo.git
$ for id in `git rev-list --all`; do
>     if git cat-file -p $id | grep -q "^${lookfor}$"; then
>         echo found: commit $id; break
>     fi
> done

Then use git describe or whatever to turn the raw commit SHA-1 into a useful name, perhaps.

Upvotes: 0

Related Questions