From 3d85c4379149889e22c2c17f39d852dc4a64fb7d Mon Sep 17 00:00:00 2001 From: Chris Kuehl Date: Wed, 29 Jul 2015 01:54:54 -0400 Subject: [PATCH] Don't run hooks on submodule roots --- pre_commit/git.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/pre_commit/git.py b/pre_commit/git.py index 83714bde..0a74f9eb 100644 --- a/pre_commit/git.py +++ b/pre_commit/git.py @@ -10,6 +10,11 @@ from pre_commit.errors import FatalError from pre_commit.util import cmd_output from pre_commit.util import memoize_by_cwd +# octal constants for git file modes +GIT_MODE_FILE = 0o100644 +GIT_MODE_EXECUTABLE = 0o100755 +GIT_MODE_SYMLINK = 0o120000 +GIT_MODE_SUBMODULE = 0o160000 logger = logging.getLogger('pre_commit') @@ -69,7 +74,28 @@ def get_staged_files(): @memoize_by_cwd def get_all_files(): - return cmd_output('git', 'ls-files')[1].splitlines() + """Return a list of all actual files in the git repository. + + There are some types of content we want to exclude. In order to exclude + submodules, which git tracks similarly to files, we call `git ls-files + --stage` and grep out entries with the special submodule file mode. + + http://stackoverflow.com/a/24122304 + """ + # The output format of the command is: + # [file mode] [object hash] [stage number]\t[file path] + split_regex = re.compile('^([0-7]{6}) [0-9a-f]{40} [0-9]+\t(.+)$') + + def split(line): + match = split_regex.match(line) + return int(match.group(1), 8), match.group(2) + + output = cmd_output('git', 'ls-files', '--stage')[1] + return [ + path for mode, path in [ + split(line) for line in output.splitlines() + ] if mode != GIT_MODE_SUBMODULE + ] def get_files_matching(all_file_list_strategy):