Skip to content

Instantly share code, notes, and snippets.

@kumorikuma
Last active February 5, 2024 23:24
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kumorikuma/efb30330adbdcffabf6065cc0f7033cd to your computer and use it in GitHub Desktop.
Save kumorikuma/efb30330adbdcffabf6065cc0f7033cd to your computer and use it in GitHub Desktop.
pre-push hook for Git LFS enabled projects that prevents any big files from being accidentally pushed and can automatically add them to Git LFS
#!/bin/sh
command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting '.git/hooks/pre-push'.\n"; exit 2; }
git lfs pre-push "$@"
# This pre-push hook will check any non git-lfs tracked files that are about to be pushed and make sure they are not too big.
# Big files can be migrated to LFS using [git lfs migrate]
#
# To enable this hook, rename this file to "pre-push".
# It should be installed to a path like "[Reponame]/.git/hooks/pre-push".
# Redirect output to stderr.
exec 1>&2
FILE_SIZE_LIMIT_KB=2048 # 2 MB
CURRENT_DIR="$(pwd)"
HAS_ERROR=""
COUNTER=0
echo "Checking filesizes..."
# generate file extension filter from gitattributes for git-lfs tracked files
# Looks for either the exact filepath (^%s$) or uses the extension wildcard (.%s$)
filter=$(cat .gitattributes | grep filter=lfs | awk '{printf "-e \\(^%s$\\|.%s$\\) ", $1, $1}')
# before git commit, check non git-lfs tracked files to limit size
files=$(git diff origin/main --name-only | sort | uniq | grep -i -v $filter)
while read -r file; do
if [ "$file" = "" ]; then
continue
fi
file_path=$CURRENT_DIR/$file
if [ ! -f "$file_path" ]; then
continue
fi
file_size=$(ls -l "$file_path" | awk '{print $5}')
file_size_kb=$((file_size / 1024))
if [ "$file_size_kb" -ge "$FILE_SIZE_LIMIT_KB" ]; then
echo "File [${file}] has size ${file_size_kb}KB, over commit limit ${FILE_SIZE_LIMIT_KB}KB."
HAS_ERROR="YES"
((COUNTER++))
fi
done <<< "$files"
# All good
if [ "$HAS_ERROR" == "" ]; then
exit 0
fi
# Some non-lfs tracked files are over file size limit
# Give option to automatically track them
echo "$COUNTER committed files are larger than permitted. Files should be migrated to LFS: [git lfs migrate import --include='path/to/file']"
# enable user input
exec < /dev/tty
read -p "Migrate files to LFS automatically (y/n)? " USERINPUT
if [ "$USERINPUT" == "y" ] || [ "$USERINPUT" == "Y" ]; then
for i in "$files"
do
$(git lfs migrate import --include='$i')
done
exit 0
fi
# Exit with error
exit 1
@kumorikuma
Copy link
Author

kumorikuma commented Feb 16, 2023

By default, git hooks are installed to [Repo]/.git/hooks. However, this directory is not inside the repo and managed under source control. You can instead move the hooks to a different folder in the repo and set the path in the git config: git config core.hooksPath hooks.

Thanks to bitinn for the idea: https://stackoverflow.com/questions/53690327/prevent-large-text-file-from-being-added-to-commit-when-using-github/53692461#53692461

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment