Git does not use the work-tree in any way when you run git push
. Specifically, what git push
pushes are commits, along with whatever objects—mostly files whose content was frozen into the commit at commit-time—are required to make those commits complete.1
Note that git commit
itself also does not use the work-tree: it commits whatever is in the index (also called the staging-area and sometimes the cache). This is why you must git add
your files before committing. There are a few options to git commit
that make it automatically copy work-tree files over top of the versions of those files in the index / staging-area; but the principle remains: git commit
commits what's in the index, not what's in the work-tree.
Your best bet at a Git hook for detecting this issue is therefore a pre-commit hook, as described in the githooks documentation:
pre-commit
This hook is invoked by git commit(1), and can be bypassed with the
--no-verify
option. It takes no parameters, and is invoked before
obtaining the proposed commit log message and making a commit. Exiting
with a non-zero status from this script causes the git commit
command
to abort before creating a commit.
(There is a bit more to the documentation; follow the links to see.)
Writing Git hooks is a bit tricky (especially server side hooks) but this one is not too bad:
#! /bin/sh
# pre-commit hook: check for large files
TMP=$(mktemp)
trap "rm -f $TMP" 0 1 2 3 15
MAX_FILE_SIZE=1048576 # 1 MB
status=0
git ls-files --stage > $TMP
while read mode hash stage path; do
objsize=$(git cat-file -s $hash)
if [ $objsize -gt $MAX_FILE_SIZE ]; then
echo "file too big: '$path' as staged exceeds $MAX_FILE_SIZE bytes" 1>&2
status=1
fi
done < $TMP
exit $status
(untested). You could instead opt for a pre-push hook, but that's later than appropriate.
1These Git objects are also compressed. Whenever possible, they are very-compressed by using existing previous objects already present on the server. So if you have a ten gigabyte text file, but you make one small change to it and commit, pushing that commit—even though it has a ten gigabyte file inside it—takes very little space since the so-called thin pack that Git sends winds up saying: Hey, remember that ten gigabyte object you already have? Take that one, remove a few bytes from the middle, and replace them with these other bytes.