Skip to content

Instantly share code, notes, and snippets.

@hynekcer
Last active November 27, 2019 20:14
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hynekcer/476a593a3fc584278b87 to your computer and use it in GitHub Desktop.
Save hynekcer/476a593a3fc584278b87 to your computer and use it in GitHub Desktop.
Git post-checkout hook for Python to remove orphan *.pyc files and empty dir
#!/bin/env python
# This work is licensed under the terms of the MIT license.
# For a copy, see <https://opensource.org/licenses/MIT>.
"""
A hook to git that removes orphan files "*.pyc" and "*.pyo" for "*.py"
beeing deleted or renamed by git checkout. It also removes their empty parent
directories.
Place it to "my_local_repository/.git/hooks/post-checkout" and make it executable.
Nothing is cleaned for .py files deleted manually or by "git rm" etc.
Related to http://stackoverflow.com/q/1504724/448474
"""
import glob
import os
import sys
from subprocess import Popen, PIPE
#print("HOOK POST-CHECKOUT")
oldrev, newrev, _ = sys.argv[1:]
cmd = 'git diff --name-only --diff-filter=DR {0}..{1}'.format(oldrev, newrev)
dirs = set()
p = Popen(cmd.split(), stdout=PIPE)
for line in p.stdout:
filepath = line.strip()
root, srcext = os.path.splitext(filepath)
if srcext == '.py' and not os.path.isfile(filepath):
parent_dir = os.path.dirname(root)
cache_dir = os.path.join(parent_dir, '__pycache__')
for ext in ('.pyc', '.pyo'):
if os.path.isdir(cache_dir):
for pycfile in glob.iglob(os.path.join(cache_dir, '*' + ext)):
os.remove(pycfile)
if not os.listdir(cache_dir):
os.rmdir(cache_dir)
dirs.add(parent_dir)
if os.path.isfile(root + ext):
os.remove(root + ext)
dirs.add(parent_dir)
p.stdout.close()
p.wait()
for pdir in sorted(dirs, key=lambda x: len(x.split(os.path.sep)), reverse=True):
if os.path.isdir(pdir) and not os.listdir(pdir):
os.rmdir(pdir)
@steve-tregidgo
Copy link

This hook is very useful; thanks for sharing it.

What licence does it have? I'd like to use it with a private git repo, but since we store our hooks as part of the repo I'd technically be distributing it, and don't want to run afoul of licence issues.

@hynekcer
Copy link
Author

hynekcer commented Mar 10, 2017

I missed your old question about the license. I didn't know how to do it correctly on Gist. I hope that the MIT license can be designated by these two lines, without any "(C)" line.

# This work is licensed under the terms of the MIT license.  
# For a copy, see <https://opensource.org/licenses/MIT>.

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