Create a Git Pre-commit Hook to Check Commit Messages
📖 Scenario: You are working on a team project using Git. Your team wants to make sure every commit message starts with a capital letter and is at least 10 characters long. To help everyone follow this rule automatically, you will create a Git pre-commit hook script.
🎯 Goal: Build a Git pre-commit hook script that checks the commit message before the commit is saved. If the message does not start with a capital letter or is shorter than 10 characters, the commit will be stopped with a clear message.
📋 What You'll Learn
Create a pre-commit hook script file in the .git/hooks directory
Add a configuration variable to set the minimum commit message length
Write the core logic to check the commit message format
Print a message to allow or block the commit based on the check
💡 Why This Matters
🌍 Real World
Teams use pre-commit hooks to enforce commit message standards automatically, improving code history clarity.
💼 Career
Knowing how to write Git hooks is useful for DevOps engineers and developers to automate quality checks in version control.
Progress0 / 4 steps
1
Create the pre-commit hook script file
Create a file called .git/hooks/pre-commit and add the first line #!/bin/sh to specify the shell interpreter.
Git
Hint
The first line of a shell script should be #!/bin/sh to tell Git how to run it.
2
Add a minimum length configuration variable
Inside the pre-commit script, create a variable called MIN_LENGTH and set it to 10 to define the minimum commit message length.
Git
Hint
Use MIN_LENGTH=10 to store the minimum length number.
3
Write the logic to check the commit message
Add code to read the commit message from .git/COMMIT_EDITMSG into a variable called MSG. Then check if the first character is uppercase and if the message length is at least $MIN_LENGTH. If either check fails, print Commit message invalid and exit with status 1 to block the commit.
Git
Hint
Use head -n1 .git/COMMIT_EDITMSG to get the first line of the commit message. Use shell string length and grep to check conditions.
4
Print success message if commit message is valid
At the end of the script, add a line to print Commit message valid and exit with status 0 to allow the commit.
Git
Hint
Use echo to print the success message and exit 0 to allow the commit.
Practice
(1/5)
1. What is the main purpose of a pre-commit hook in Git?
easy
A. To push commits to the remote repository automatically
B. To run scripts before a commit is saved to catch errors early
C. To delete files from the repository before committing
D. To automatically merge branches after a commit
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 B
Quick Check:
Pre-commit hook purpose = run scripts before commit [OK]
Hint: Pre-commit hooks run before saving commits to catch issues [OK]
Common Mistakes:
Confusing pre-commit with post-commit hooks
Thinking hooks automatically push commits
Believing hooks delete files automatically
2. Which of the following is the correct way to make a pre-commit hook script executable on Linux?
easy
A. chmod +x .git/hooks/pre-commit
B. git enable pre-commit
C. chmod 000 .git/hooks/pre-commit
D. git hook run pre-commit
Solution
Step 1: Identify how to make scripts executable
On Linux, chmod +x sets execute permission on a file.
Step 2: Apply to pre-commit hook script
Running chmod +x .git/hooks/pre-commit makes the hook script executable so Git can run it.
Final Answer:
chmod +x .git/hooks/pre-commit -> Option A
Quick Check:
Make hook executable = chmod +x [OK]
Hint: Use chmod +x to make hook scripts executable [OK]
Common Mistakes:
Using git commands instead of chmod for permissions
Setting permissions to 000 disables execution
Assuming hooks run without executable permission
3. Given this 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?
medium
A. No Python files changed
B. Python files changed
C. Syntax error in script
D. Hook will not run
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 A
Quick Check:
File extension check = no match = else output [OK]
Hint: Check file extensions in staged files to predict output [OK]
Common Mistakes:
Assuming any changed file triggers 'Python files changed'
Confusing staged vs unstaged files
Ignoring the file extension check
4. You wrote a pre-commit hook script but it does not run when committing. Which of these is the most likely cause?
medium
A. The script is placed outside the .git/hooks directory
B. The script is named pre-commit.sh instead of pre-commit
C. All of the above
D. The script is not executable
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 C
Quick Check:
Hook runs only if name, location, and permissions are correct [OK]
Hint: Check name, location, and execute permission for hooks [OK]
Common Mistakes:
Ignoring file permissions
Naming script with extensions like .sh
Placing script outside .git/hooks folder
5. You want a pre-commit hook that prevents commits if any staged file contains the word 'TODO'. Which script snippet correctly implements this?
hard
A. #!/bin/sh
git commit -m 'Check TODOs' || exit 1
D. #!/bin/sh
git diff --cached | grep -q 'TODO' && echo 'Remove TODOs before commit' && exit 1
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 uses git diff --cached to 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 D
Quick Check:
Check staged diff for TODO and exit if found [OK]
Hint: Use git diff --cached to scan staged changes for keywords [OK]
Common Mistakes:
Searching unstaged files instead of staged
Running git commit inside hook
Checking git status output for content
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.