๐ง Setting Up Git Hooks in Alpine Linux: Simple Guide
Git hooks help your code stay clean automatically! ๐ป This tutorial shows you how to set up useful Git hooks easily. Donโt worry - itโs simpler than you think! ๐
๐ค What are Git Hooks?
Git hooks are like automatic helpers that run when you do Git actions. Think of them as smart reminders that check your work!
Git hooks can:
- ๐ Check your code before commits
- โ Run tests automatically
- ๐ Format your code nicely
- ๐ Deploy code when you push
๐ฏ What You Need
Before we start, you need:
- โ Alpine Linux system running
- โ
Git installed (
apk add git
) - โ A Git repository to work with
- โ Basic knowledge of terminal commands
๐ Step 1: Understanding Git Hooks Basics
๐ Where Git Hooks Live
Letโs start by looking at where Git stores its hooks. Every Git repo has them! ๐
What weโre doing: Finding the hooks directory in your Git repository.
# Go to your Git repository
cd /path/to/your/repo
# Check if you're in a Git repo
git status
# Look at the hooks directory
ls -la .git/hooks/
# See what hook examples exist
ls -la .git/hooks/*.sample
What this does: ๐ Shows you all the hook examples that Git provides by default.
Expected Output:
-rwxr-xr-x 1 user user 424 Jun 7 14:00 applypatch-msg.sample
-rwxr-xr-x 1 user user 896 Jun 7 14:00 commit-msg.sample
-rwxr-xr-x 1 user user 3327 Jun 7 14:00 pre-commit.sample
-rwxr-xr-x 1 user user 1348 Jun 7 14:00 pre-push.sample
What this means: Git has prepared example hooks for you to use! โ
๐ก Important Tips
Tip: Hook files must be executable and have no file extension! ๐ก
Warning: Hooks with
.sample
extension donโt run - remove.sample
to activate! โ ๏ธ
๐ ๏ธ Step 2: Creating Your First Hook
๐ Simple Pre-commit Hook
Now letโs create a useful hook that checks your code before every commit. This prevents mistakes! ๐
What weโre doing: Creating a pre-commit hook that runs basic checks on your code.
# Go to your Git repository
cd /path/to/your/repo
# Create a simple pre-commit hook
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
echo "๐ Running pre-commit checks..."
# Check for files larger than 1MB
echo "๐ Checking file sizes..."
large_files=$(find . -type f -size +1M -not -path "./.git/*" 2>/dev/null)
if [ -n "$large_files" ]; then
echo "โ ๏ธ Warning: Large files found:"
echo "$large_files"
echo "โ Continue anyway? (y/n)"
read answer
if [ "$answer" != "y" ]; then
echo "โ Commit aborted"
exit 1
fi
fi
# Check for TODO comments in staged files
echo "๐ Checking for TODO comments..."
staged_files=$(git diff --cached --name-only)
if [ -n "$staged_files" ]; then
todos=$(git diff --cached | grep -i "TODO\|FIXME\|XXX" || true)
if [ -n "$todos" ]; then
echo "๐ TODO comments found in staged changes:"
echo "$todos"
echo "๐ก Consider fixing these before committing"
fi
fi
echo "โ
Pre-commit checks complete!"
exit 0
EOF
# Make the hook executable
chmod +x .git/hooks/pre-commit
# Test the hook
echo "Testing hook..." && git add . && git commit -m "Test commit" --dry-run
Code explanation:
#!/bin/sh
: Makes it a shell scriptfind . -type f -size +1M
: Finds files larger than 1MBgit diff --cached
: Shows staged changeschmod +x
: Makes the file executableexit 1
: Stops the commit if thereโs a problem
Expected Output:
๐ Running pre-commit checks...
๐ Checking file sizes...
๐ Checking for TODO comments...
โ
Pre-commit checks complete!
What this means: Your hook is working and will check every commit! ๐
๐ฎ Letโs Try It!
Time for hands-on practice! This is the fun part! ๐ฏ
What weโre doing: Creating an advanced pre-commit hook with code formatting and testing.
# Create advanced pre-commit hook
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
echo "๐ Advanced Pre-commit Hook"
echo "=========================="
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Function to print colored messages
print_status() {
echo "${GREEN}โ
$1${NC}"
}
print_warning() {
echo "${YELLOW}โ ๏ธ $1${NC}"
}
print_error() {
echo "${RED}โ $1${NC}"
}
echo ""
print_status "Starting pre-commit checks..."
# 1. Check file sizes
echo ""
echo "๐ Checking file sizes..."
large_files=$(find . -type f -size +1M -not -path "./.git/*" -not -path "./node_modules/*" 2>/dev/null)
if [ -n "$large_files" ]; then
print_warning "Large files detected:"
echo "$large_files"
fi
# 2. Check for sensitive information
echo ""
echo "๐ Checking for sensitive information..."
sensitive_patterns="password|secret|api_key|private_key|token"
if git diff --cached | grep -iE "$sensitive_patterns" >/dev/null; then
print_error "Potential sensitive information found in staged changes!"
git diff --cached | grep -iE "$sensitive_patterns" --color=always
echo ""
print_error "Please remove sensitive data before committing"
exit 1
fi
# 3. Check for proper file formatting (if files exist)
echo ""
echo "๐ Checking file formatting..."
staged_files=$(git diff --cached --name-only)
for file in $staged_files; do
if [ -f "$file" ]; then
# Check for trailing whitespace
if grep -q '[[:space:]]$' "$file" 2>/dev/null; then
print_warning "Trailing whitespace found in: $file"
fi
# Check for tabs instead of spaces (for certain file types)
case "$file" in
*.py|*.js|*.json|*.yaml|*.yml)
if grep -q $'\t' "$file" 2>/dev/null; then
print_warning "Tabs found in: $file (consider using spaces)"
fi
;;
esac
fi
done
# 4. Run basic syntax checks
echo ""
echo "๐ Running syntax checks..."
for file in $staged_files; do
if [ -f "$file" ]; then
case "$file" in
*.sh)
if command -v shellcheck >/dev/null 2>&1; then
if ! shellcheck "$file" >/dev/null 2>&1; then
print_warning "Shell script issues found in: $file"
print_warning "Run 'shellcheck $file' for details"
fi
else
print_warning "shellcheck not installed - skipping shell script checks"
fi
;;
*.json)
if command -v jq >/dev/null 2>&1; then
if ! jq empty "$file" >/dev/null 2>&1; then
print_error "Invalid JSON syntax in: $file"
exit 1
fi
fi
;;
esac
fi
done
# 5. Check commit message length (for interactive commits)
echo ""
echo "๐ Commit message guidelines:"
print_status "Keep subject line under 50 characters"
print_status "Use present tense ('Add feature' not 'Added feature')"
print_status "Separate subject and body with blank line"
echo ""
print_status "All pre-commit checks passed! ๐"
echo ""
EOF
# Make it executable
chmod +x .git/hooks/pre-commit
# Test the advanced hook
echo "# Test file with TODO" > test.txt
echo "TODO: Fix this later" >> test.txt
git add test.txt
git commit -m "Test advanced hook" --dry-run
You should see:
๐ Advanced Pre-commit Hook
==========================
โ
Starting pre-commit checks...
๐ Checking file sizes...
๐ Checking for sensitive information...
๐ Checking file formatting...
๐ Running syntax checks...
๐ Commit message guidelines:
โ
Keep subject line under 50 characters
โ
All pre-commit checks passed! ๐
Awesome work! ๐
๐ Quick Summary Table
Hook Type | When It Runs | Use For |
---|---|---|
๐ง pre-commit | Before commit | โ Code quality checks |
๐ ๏ธ commit-msg | After commit message | โ Message format validation |
๐ pre-push | Before push | โ Final tests and builds |
๐ฏ post-commit | After commit | โ Notifications and logging |
๐จ Step 3: Creating a Commit Message Hook
๐ Enforcing Good Commit Messages
Letโs create a hook that helps you write better commit messages! ๐
What weโre doing: Making sure all commit messages follow good practices.
# Create commit message hook
cat > .git/hooks/commit-msg << 'EOF'
#!/bin/sh
echo "๐ Checking commit message format..."
commit_regex='^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .{1,50}'
if ! grep -qE "$commit_regex" "$1"; then
echo ""
echo "โ Invalid commit message format!"
echo ""
echo "๐ Valid format:"
echo " type(scope): description"
echo ""
echo "๐ท๏ธ Valid types:"
echo " feat: New feature"
echo " fix: Bug fix"
echo " docs: Documentation"
echo " style: Code formatting"
echo " refactor: Code restructuring"
echo " test: Adding tests"
echo " chore: Maintenance tasks"
echo ""
echo "๐ Examples:"
echo " feat: add user authentication"
echo " fix(api): resolve login timeout issue"
echo " docs: update installation guide"
echo ""
echo "๐ก Keep description under 50 characters"
echo ""
exit 1
fi
echo "โ
Commit message format is good!"
EOF
# Make it executable
chmod +x .git/hooks/commit-msg
# Test with a good commit message
echo "Test change" > test.txt
git add test.txt
git commit -m "feat: add test functionality"
Code explanation:
commit_regex
: Pattern for valid commit messagesgrep -qE
: Checks if message matches pattern$1
: First argument (the commit message file)- Types like
feat
,fix
help organize changes
Expected Output:
๐ Checking commit message format...
โ
Commit message format is good!
What this does: Ensures all your commits have clear, organized messages! ๐
๐ Step 4: Creating a Pre-push Hook
๐งช Running Tests Before Push
What weโre doing: Creating a hook that runs tests before you push code to make sure everything works.
# Create pre-push hook
cat > .git/hooks/pre-push << 'EOF'
#!/bin/sh
echo "๐ Running pre-push checks..."
# Get the remote and URL
remote="$1"
url="$2"
echo "๐ค Pushing to: $remote ($url)"
# Check if we're pushing to main/master branch
current_branch=$(git rev-parse --abbrev-ref HEAD)
if [ "$current_branch" = "main" ] || [ "$current_branch" = "master" ]; then
echo "โ ๏ธ Pushing to main branch - running extra checks..."
# Run tests if test directory exists
if [ -d "tests" ] || [ -f "package.json" ]; then
echo "๐งช Running tests..."
# For Node.js projects
if [ -f "package.json" ]; then
if npm test >/dev/null 2>&1; then
echo "โ
Tests passed!"
else
echo "โ Tests failed! Push aborted."
exit 1
fi
fi
# For shell script projects
if [ -d "tests" ]; then
for test_file in tests/*.sh; do
if [ -f "$test_file" ]; then
echo " Running $test_file..."
if ! sh "$test_file" >/dev/null 2>&1; then
echo "โ Test failed: $test_file"
exit 1
fi
fi
done
echo "โ
All shell tests passed!"
fi
fi
# Check for untracked files
untracked=$(git ls-files --others --exclude-standard)
if [ -n "$untracked" ]; then
echo "๐ Untracked files found:"
echo "$untracked"
echo "๐ญ Consider adding them or updating .gitignore"
fi
fi
echo "โ
Pre-push checks complete! Pushing..."
EOF
# Make it executable
chmod +x .git/hooks/pre-push
echo "โ
Pre-push hook created!"
What this does: Runs tests and checks before pushing to make sure your code is solid! ๐
๐ฎ Practice Time!
Letโs practice what you learned! Try these simple examples:
Example 1: Backup Hook ๐ข
What weโre doing: Creating a post-commit hook that creates automatic backups.
# Create post-commit backup hook
cat > .git/hooks/post-commit << 'EOF'
#!/bin/sh
echo "๐พ Creating automatic backup..."
# Create backup directory
backup_dir="/tmp/git-backups/$(basename $(pwd))"
mkdir -p "$backup_dir"
# Create backup with timestamp
timestamp=$(date +%Y%m%d_%H%M%S)
backup_file="$backup_dir/backup_$timestamp.tar.gz"
# Create backup (exclude .git directory)
tar -czf "$backup_file" --exclude='.git' .
echo "โ
Backup created: $backup_file"
EOF
chmod +x .git/hooks/post-commit
What this does: Automatically backs up your project after every commit! ๐
Example 2: Notification Hook ๐ก
What weโre doing: Creating a hook that sends notifications about commits.
# Create notification post-commit hook
cat > .git/hooks/post-commit << 'EOF'
#!/bin/sh
echo "๐จ Sending commit notification..."
# Get commit info
commit_hash=$(git rev-parse HEAD)
commit_message=$(git log -1 --pretty=%B)
author=$(git log -1 --pretty=%an)
timestamp=$(git log -1 --pretty=%cd)
# Log to file
log_file="/tmp/git-commits.log"
echo "[$timestamp] $author: $commit_message ($commit_hash)" >> "$log_file"
# Simple desktop notification (if available)
if command -v notify-send >/dev/null 2>&1; then
notify-send "Git Commit" "Successfully committed: $commit_message"
fi
echo "โ
Commit logged and notification sent!"
EOF
chmod +x .git/hooks/post-commit
What this does: Keeps track of all commits and sends notifications! ๐
๐จ Fix Common Problems
Problem 1: Hook not running โ
What happened: Git hook doesnโt seem to execute. How to fix it: Check permissions and file naming!
# Check if hook file is executable
ls -la .git/hooks/pre-commit
# Make sure it's executable
chmod +x .git/hooks/pre-commit
# Check if filename is correct (no .sample extension)
mv .git/hooks/pre-commit.sample .git/hooks/pre-commit 2>/dev/null || echo "File already correct"
# Test the hook directly
.git/hooks/pre-commit
Problem 2: Hook blocks all commits โ
What happened: Hook prevents you from committing anything. How to fix it: Add bypass option or fix the hook logic!
# Temporarily disable hook
mv .git/hooks/pre-commit .git/hooks/pre-commit.disabled
# Or bypass hooks for emergency commits
git commit --no-verify -m "Emergency commit"
# Fix and re-enable hook
mv .git/hooks/pre-commit.disabled .git/hooks/pre-commit
Donโt worry! Hooks are supposed to help, not block you. Adjust them as needed! ๐ช
๐ก Simple Tips
- Start simple ๐ - Begin with basic hooks, add features later
- Test thoroughly ๐ฑ - Make sure hooks work before relying on them
- Share with team ๐ค - Put hooks in version control for everyone
- Document purpose ๐ช - Add comments explaining what each hook does
โ Check Everything Works
Letโs make sure all your hooks are working perfectly:
# Test pre-commit hook
echo "test" > test.txt
git add test.txt
git commit -m "feat: test pre-commit hook" --dry-run
# Check all hooks are executable
ls -la .git/hooks/ | grep -v sample
# Test commit message hook
git commit -m "bad message" --dry-run 2>&1 | grep -q "Invalid" && echo "โ
Commit message hook works" || echo "โ Hook needs fixing"
echo "๐ง Git hooks are ready! โ
"
Good output:
โ
Commit message hook works
๐ง Git hooks are ready! โ
๐ What You Learned
Great job! Now you can:
- โ Create and configure Git hooks
- โ Set up pre-commit code quality checks
- โ Enforce good commit message formats
- โ Run automated tests before pushing
๐ฏ Whatโs Next?
Now you can try:
- ๐ Sharing hooks across multiple repositories
- ๐ ๏ธ Creating more advanced testing hooks
- ๐ค Setting up team-wide hook standards
- ๐ Learning about Git hook managers like pre-commit!
Remember: Git hooks automate good practices! Youโre making your development workflow better! ๐
Keep practicing and youโll become a Git automation expert too! ๐ซ