pre-commit hook in Git - Time & Space Complexity
We want to understand how the time taken by a pre-commit hook changes as the project size grows.
Specifically, how does running checks before each commit scale with the number of files or changes?
Analyze the time complexity of this simple pre-commit hook script.
#!/bin/sh
# Run lint on all staged files
files=$(git diff --cached --name-only --diff-filter=ACM | grep '\.js$')
for file in $files; do
eslint "$file"
done
This hook runs a linter on each staged JavaScript file before allowing a commit.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Looping over each staged JavaScript file to run eslint.
- How many times: Once for each staged .js file in the commit.
As the number of staged JavaScript files increases, the number of eslint runs grows linearly.
| Input Size (n files) | Approx. Operations (eslint runs) |
|---|---|
| 10 | 10 |
| 100 | 100 |
| 1000 | 1000 |
Pattern observation: The work grows directly in proportion to the number of files checked.
Time Complexity: O(n)
This means the time to run the pre-commit hook grows linearly with the number of staged files.
[X] Wrong: "The pre-commit hook runs in constant time regardless of files."
[OK] Correct: Each file adds work because the hook runs eslint on every staged file, so more files mean more time.
Understanding how pre-commit hooks scale helps you write efficient checks that keep your workflow smooth as projects grow.
"What if the hook ran eslint once on all files together instead of one by one? How would the time complexity change?"
Practice
pre-commit hook in Git?Solution
Step 1: Understand what pre-commit hooks do
Pre-commit hooks run scripts before a commit is finalized to check code or enforce rules.Step 2: Identify the correct purpose
They help catch errors early by running checks before saving changes.Final Answer:
To run scripts before a commit is saved to catch errors early -> Option BQuick Check:
Pre-commit hook purpose = run scripts before commit [OK]
- Confusing pre-commit with post-commit hooks
- Thinking hooks automatically push commits
- Believing hooks delete files automatically
pre-commit hook script executable on Linux?Solution
Step 1: Identify how to make scripts executable
On Linux,chmod +xsets execute permission on a file.Step 2: Apply to pre-commit hook script
Runningchmod +x .git/hooks/pre-commitmakes the hook script executable so Git can run it.Final Answer:
chmod +x .git/hooks/pre-commit -> Option AQuick Check:
Make hook executable = chmod +x [OK]
- Using git commands instead of chmod for permissions
- Setting permissions to 000 disables execution
- Assuming hooks run without executable permission
pre-commit hook script content:#!/bin/sh if git diff --cached --name-only | grep -q '\.py$'; then echo 'Python files changed' else echo 'No Python files changed' fi
What will be the output if you commit a changed file named
app.js?Solution
Step 1: Understand the script logic
The script checks staged files for names ending with '.py'. If found, it prints 'Python files changed'. Otherwise, it prints 'No Python files changed'.Step 2: Apply to the committed file
The committed file is 'app.js', which does not end with '.py', so the else branch runs.Final Answer:
No Python files changed -> Option AQuick Check:
File extension check = no match = else output [OK]
- Assuming any changed file triggers 'Python files changed'
- Confusing staged vs unstaged files
- Ignoring the file extension check
pre-commit hook script but it does not run when committing. Which of these is the most likely cause?Solution
Step 1: Check script permissions
If the script is not executable, Git cannot run it.Step 2: Check script name and location
The script must be named exactly 'pre-commit' and placed inside the '.git/hooks' folder to be recognized.Step 3: Combine all issues
Any of these problems will prevent the hook from running, so all are valid causes.Final Answer:
All of the above -> Option CQuick Check:
Hook runs only if name, location, and permissions are correct [OK]
- Ignoring file permissions
- Naming script with extensions like .sh
- Placing script outside .git/hooks folder
pre-commit hook that prevents commits if any staged file contains the word 'TODO'. Which script snippet correctly implements this?Solution
Step 1: Understand the goal
The hook must check staged changes for the word 'TODO' and stop commit if found.Step 2: Analyze each option
#!/bin/sh git diff --cached | grep -q 'TODO' && echo 'Remove TODOs before commit' && exit 1 usesgit diff --cachedto check staged changes and exits with error if 'TODO' is found, which is correct.
#!/bin/sh grep -r 'TODO' . && echo 'TODO found' && exit 1 searches all files recursively, not just staged changes.
#!/bin/sh git commit -m 'Check TODOs' || exit 1 tries to run a commit inside the hook, which is incorrect.
#!/bin/sh git status | grep 'TODO' && exit 1 checks git status output, which does not show file contents.Final Answer:
#!/bin/sh git diff --cached | grep -q 'TODO' && echo 'Remove TODOs before commit' && exit 1 -> Option DQuick Check:
Check staged diff for TODO and exit if found [OK]
- Searching unstaged files instead of staged
- Running git commit inside hook
- Checking git status output for content
Ready to prove it?
Pass the test and this pattern moves unknown
