LFS objects are not cleaned, when push is rejected by pre-receive hook


We used to have a standard git repo, which had plenty of binary files. We used a pre-receive hook to parse the headers of the files and see if they follow our standard. Now we want to move to LFS for these files and accordingly reworked the pre-receive hook to cancel the push if we spot an issue with the files being pushed. This works in the following way:

  1. An user pushes a commit with binary files
  2. LFS pushes first the binary objects
  3. GIT pushes the rest of the source code
  4. pre-receive hook starts and checks the binary files

If on step 4 we want to cancel the push, this is okay. However the binary LFS objects stay in the LFS store and use space. I ran manually:
“remove_unreferenced_lfs_objects_worker” background job, but the files are still there.

Is this an expected behaviour? What would be appropriate cleanup steps?


In order to reproduce it, you need to create a git hook under “/var/opt/gitlab/git-data/repositories/[@hashed/]yourrepo.git/custom_hooks/pre-receive” (must be executable):


# Pre-receive hook that will block any new commits that contain dds files with invalid format


# Do not traverse over commits that are already in the repository
# (e.g. in a different branch)
# This prevents funny errors if pre-receive hooks got enabled after some
# commits got already in and then somebody tries to create a new branch
# If this is unwanted behavior, just set the variable to empty
excludeExisting="--not --all"

while read oldrev newrev refname; do
  echo $refname $oldrev $newrev

  # branch or tag get deleted
  if [ "$newrev" = "$zero_commit" ]; then

  # Check for new branch or tag
  if [ "$oldrev" = "$zero_commit" ]; then
    span=`git rev-list $newrev $excludeExisting`
    span=`git rev-list $oldrev..$newrev $excludeExisting`

  for COMMIT in $span;
      while IFS= read -r FILE; do
        case "$FILE" in
          *.bin )
          echo "ERROR: You are not allowed to push \"bin\" files -> \"$FILE\""
          echo "File is located under your lfs object store folder in subfolder:"
          echo "$(git show $newrev:"$FILE" | grep 'oid sha' | awk -F':' '{print $2}' | sed 's/\([a-f0-9][a-f0-9]\)\([a-f0-9][a-f0-9]\)\(.*\)/\1\/\2\/\3/g')"
      done <<< "$(git log -1 --name-only --pretty=format:'' $COMMIT)"
exit $errorLevel

enable LFS in a newly cloned test repo:

git lfs install
git lfs track '*.bin'
git add .gitattributes 
dd if=/dev/urandom bs=1M count=1 | gzip -c > ./file.bin
git add file.bin
git commit -m "Add files"
git push origin master