I have been trying to code up an experiment that involves putting the following code in the post-receive
git hook:
unset GIT_DIR
cd (path to some temp directory outside the repository)
git clone --local (path to repository just pushed to) .
git checkout dev
git reset --hard HEAD^
git reflog expire --expire=now --all
git gc --aggressive --prune=now
Basically what I'm doing is cloning the repository that was just pushed to, doing a hard reset to remove the last commit, and then doing garbage collection to remove traces of the last commit from history. To check that the garbage collection is really doing its job, I commit a huge 4-MB file in the last commit, and then check the size of .git to see if it's been removed.
So when I run this code inside the git "post-receive" hook, the reset seems to work fine; the cloned repository is back in the state without the huge file. However, the garbage collection doesn't seem to have worked. The size of .git is still huge.
On the other hand, if I manually run "git reflog" and "git gc" from the command line at this point, it correctly removes the traces of the huge file, and the size of .git is restored to a manageable size.
Any ideas why garbage collection might behave differently when run within "post-receive", rather than at a command prompt?