Bird
Raised Fist0
Gitdevops~15 mins

Creating custom hook scripts in Git - Mechanics & Internals

Choose your learning style10 modes available
Overview - Creating custom hook scripts
What is it?
Git hook scripts are small programs that run automatically at certain points in the Git workflow. They let you add custom actions like checks or notifications when you commit, push, or receive code. Creating custom hook scripts means writing your own scripts to automate tasks or enforce rules in your Git projects. These scripts live inside your Git repository and run without manual triggers.
Why it matters
Without custom hooks, developers must remember to do checks or tasks manually, which can lead to mistakes or inconsistent workflows. Custom hooks automate these steps, saving time and reducing errors. They help teams enforce code quality, run tests, or update documentation automatically, making collaboration smoother and more reliable.
Where it fits
Before learning custom hooks, you should understand basic Git commands like commit, push, and clone. After mastering hooks, you can explore continuous integration tools that automate testing and deployment based on Git events.
Mental Model
Core Idea
Custom Git hook scripts are automatic helpers that run your own code at key moments in Git to customize and control your workflow.
Think of it like...
It's like setting up automatic reminders or alarms on your phone that go off when you start a task, so you never forget important steps.
┌───────────────┐
│ Git Workflow  │
│               │
│  commit, push │
└──────┬────────┘
       │ triggers
       ▼
┌─────────────────────┐
│ Custom Hook Scripts  │
│ (pre-commit, post-push)│
└─────────┬───────────┘
          │ run your code
          ▼
┌─────────────────────┐
│ Automated Actions   │
│ (checks, notifications)│
└─────────────────────┘
Build-Up - 7 Steps
1
FoundationWhat are Git hook scripts
🤔
Concept: Introduce the idea of Git hooks as scripts triggered by Git events.
Git hooks are scripts stored in the .git/hooks directory of a repository. They run automatically when certain Git actions happen, like committing or pushing. For example, a pre-commit hook runs before a commit is saved, letting you check code or stop the commit if needed.
Result
You understand that Git hooks are automatic scripts tied to Git events inside your project.
Knowing that Git hooks run automatically helps you see how Git can be customized beyond manual commands.
2
FoundationLocating and enabling hook scripts
🤔
Concept: Learn where hooks live and how to activate them.
Inside your Git project folder, there's a hidden .git/hooks directory. It contains sample scripts with .sample extensions. To enable a hook, remove the .sample extension and make the script executable. For example, rename pre-commit.sample to pre-commit and give it execute permission.
Result
You can find and activate existing hook scripts in your Git repository.
Understanding the location and activation process is key to starting with custom hooks.
3
IntermediateWriting a simple pre-commit hook
🤔Before reading on: do you think a pre-commit hook can stop a commit if a condition fails? Commit to your answer.
Concept: Create a basic script that runs before commit to check something and prevent commit if needed.
#!/bin/sh # pre-commit hook example # Check for TODO comments if git diff --cached | grep -q 'TODO'; then echo "Error: TODO comments found. Please remove before committing." exit 1 fi exit 0
Result
If the staged changes contain 'TODO', the commit is stopped with an error message.
Knowing hooks can block Git actions lets you enforce rules automatically.
4
IntermediateUsing environment variables in hooks
🤔Before reading on: do you think Git passes information like commit message or branch name to hooks via environment variables? Commit your guess.
Concept: Learn how hooks receive information from Git through environment variables.
Git sets environment variables like GIT_COMMITTER_NAME inside hooks. For example, you can use $GIT_BRANCH to know the current branch and run branch-specific checks or actions.
Result
Hooks can adapt behavior based on Git context using environment variables.
Understanding environment variables lets you write smarter, context-aware hooks.
5
IntermediateSharing hooks across team members
🤔
Concept: Explore ways to distribute custom hooks to all developers on a project.
Git does not share hooks automatically. To share, you can store hooks in a folder inside the repo (like scripts/hooks) and add setup scripts to copy them into .git/hooks. Alternatively, use Git's core.hooksPath config to point to a shared hooks directory.
Result
Teams can use the same hooks to keep workflows consistent.
Knowing how to share hooks prevents 'works on my machine' problems.
6
AdvancedCreating complex multi-step hook scripts
🤔Before reading on: do you think hook scripts can call other programs or scripts to perform complex tasks? Commit your answer.
Concept: Combine multiple commands and external tools inside hooks for advanced automation.
#!/bin/sh # pre-push hook example # Run tests before push if ! ./run_tests.sh; then echo "Tests failed. Push aborted." exit 1 fi # Notify team via messaging API curl -X POST -H 'Content-type: application/json' --data '{"text":"Code pushed to branch $GIT_BRANCH"}' https://example.com/api/notify exit 0
Result
Push is blocked if tests fail; team gets notified on successful push.
Hooks can integrate with other tools to automate complex workflows.
7
ExpertAvoiding pitfalls and performance issues in hooks
🤔Before reading on: do you think slow or buggy hooks can block Git commands and frustrate developers? Commit your prediction.
Concept: Understand how hook script design affects developer experience and how to optimize them.
Hooks run synchronously and block Git commands until they finish. Slow scripts cause delays. Bugs can stop commits or pushes unexpectedly. To avoid this, keep hooks fast, handle errors gracefully, and log issues instead of blocking when possible. Use asynchronous notifications or background jobs for non-critical tasks.
Result
Hooks improve workflow without annoying delays or unexpected failures.
Knowing hook performance impact helps maintain smooth developer workflows.
Under the Hood
Git hooks are executable scripts placed in the .git/hooks directory. When a Git event occurs, Git looks for a corresponding hook script by name and runs it synchronously. The script's exit code determines if Git continues or aborts the operation. Git passes context via environment variables and standard input/output. Hooks can be written in any language as long as they are executable.
Why designed this way?
Hooks were designed as simple executable scripts to allow flexibility and language choice. This avoids locking users into a specific language or framework. Running hooks synchronously ensures Git operations respect the hook's outcome, enforcing rules reliably. The design keeps hooks local to each repository to avoid security risks and maintain control.
┌───────────────┐
│ Git Command   │
│ (commit, push)│
└──────┬────────┘
       │ triggers
       ▼
┌───────────────┐
│ .git/hooks/   │
│ hook script   │
└──────┬────────┘
       │ runs
       ▼
┌───────────────┐
│ Script logic  │
│ (checks, etc) │
└──────┬────────┘
       │ exit code
       ▼
┌───────────────┐
│ Git continues │
│ or aborts    │
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Do you think Git hooks are shared automatically when you clone a repository? Commit yes or no.
Common Belief:Git hooks are shared automatically with the repository when cloned.
Tap to reveal reality
Reality:Git hooks are not shared by default; the .git/hooks folder is local and not part of the repository content.
Why it matters:Assuming hooks are shared leads to inconsistent workflows and missed checks across team members.
Quick: Do you think a hook script can run asynchronously without blocking Git commands? Commit your answer.
Common Belief:Hook scripts run asynchronously and do not block Git commands.
Tap to reveal reality
Reality:Hooks run synchronously and block Git commands until they finish or exit.
Why it matters:Misunderstanding this causes slow or buggy hooks to frustrate developers by delaying or stopping Git operations.
Quick: Can you use any programming language for Git hooks? Commit yes or no.
Common Belief:Git hooks must be written in shell script only.
Tap to reveal reality
Reality:Hooks can be written in any language as long as the script is executable and has the correct shebang line.
Why it matters:Limiting yourself to shell scripts restricts flexibility and integration with other tools.
Quick: Do you think hooks can modify the commit content after the commit is made? Commit your guess.
Common Belief:Hooks can change the commit content after the commit is finalized.
Tap to reveal reality
Reality:Hooks run before or after events but cannot change a commit once created; changes require new commits.
Why it matters:Expecting hooks to modify commits post-creation leads to confusion and broken workflows.
Expert Zone
1
Hooks run in the context of the local repository, so environment differences can cause inconsistent behavior across machines.
2
Using core.hooksPath allows centralized hook management but requires careful setup to avoid conflicts with local hooks.
3
Hooks should avoid side effects that alter repository state unexpectedly, as this can confuse Git and developers.
When NOT to use
Avoid using hooks for heavy tasks like full test suites or deployments; instead, use CI/CD pipelines triggered by Git events. Also, do not rely on hooks for security enforcement since they can be bypassed by users with local access.
Production Patterns
Teams often use pre-commit hooks to enforce code style and run quick checks, while pre-push hooks run tests. Post-receive hooks on servers trigger deployments or notifications. Hooks are combined with shared scripts and configuration management for consistency.
Connections
Continuous Integration (CI)
Builds-on
Understanding hooks helps grasp how CI systems automate testing and deployment triggered by Git events.
Event-driven programming
Same pattern
Git hooks are an example of event-driven design where code runs in response to specific triggers.
Home automation systems
Similar concept
Like Git hooks automate tasks on events, home automation runs actions when sensors detect changes, showing automation principles across domains.
Common Pitfalls
#1Writing hook scripts that are too slow and block Git commands.
Wrong approach:#!/bin/sh sleep 10 exit 0
Correct approach:#!/bin/sh # Quick checks only exit 0
Root cause:Not realizing hooks run synchronously and delay Git operations.
#2Assuming hooks are shared automatically and not distributing them properly.
Wrong approach:No setup to share hooks; relying on .git/hooks folder only.
Correct approach:Store hooks in repo folder and use setup script or core.hooksPath to share.
Root cause:Misunderstanding Git's local-only hook storage.
#3Writing hooks without executable permissions or wrong filenames.
Wrong approach:Naming script pre-commit.sample and not making it executable.
Correct approach:Rename to pre-commit and run chmod +x pre-commit.
Root cause:Not following Git's hook activation requirements.
Key Takeaways
Git hook scripts automate custom actions at key points in the Git workflow to improve consistency and quality.
Hooks live locally in the .git/hooks directory and must be enabled and shared deliberately.
Hooks run synchronously and can block Git commands, so they should be fast and reliable.
You can write hooks in any language and use environment variables to access Git context.
Hooks complement but do not replace CI/CD pipelines and should be used thoughtfully to avoid workflow disruptions.

Practice

(1/5)
1. What is the main purpose of creating a custom Git hook script?
easy
A. To delete branches remotely
B. To change the Git commit message manually
C. To create new Git repositories
D. To run scripts automatically at specific Git events

Solution

  1. Step 1: Understand Git hooks

    Git hooks are scripts that run automatically at certain points in Git's workflow, like before a commit or after a push.
  2. Step 2: Identify the purpose of custom hooks

    Custom hooks let you automate tasks or enforce rules during these Git events without manual intervention.
  3. Final Answer:

    To run scripts automatically at specific Git events -> Option D
  4. Quick Check:

    Git hooks = automatic scripts at Git events [OK]
Hint: Hooks run scripts automatically at Git events [OK]
Common Mistakes:
  • Thinking hooks manually change commit messages
  • Confusing hooks with branch deletion
  • Assuming hooks create repositories
2. Which of the following is the correct way to make a Git hook script executable on Linux or macOS?
easy
A. chmod +x .git/hooks/pre-commit
B. git hook enable pre-commit
C. chmod 777 .git/hooks/pre-commit
D. git config hook.pre-commit true

Solution

  1. Step 1: Understand file permissions for hooks

    Git hooks must be executable files to run automatically.
  2. Step 2: Use the correct command to make a file executable

    The command chmod +x adds execute permission without changing other permissions.
  3. Final Answer:

    chmod +x .git/hooks/pre-commit -> Option A
  4. Quick Check:

    Make hook executable = chmod +x [OK]
Hint: Use chmod +x to make hook scripts executable [OK]
Common Mistakes:
  • Using git commands that don't exist for hooks
  • Setting overly permissive permissions like 777
  • Trying to enable hooks via git config
3. Given this pre-commit hook script placed in .git/hooks/pre-commit and made executable:
#!/bin/sh
if git diff --cached --quiet; then
  echo "No changes staged for commit."
  exit 1
fi
What happens when you try to commit without staging any changes?
medium
A. The commit is blocked with message 'No changes staged for commit.'
B. The commit proceeds normally without any message
C. The commit is blocked with a syntax error
D. The commit proceeds but shows a warning

Solution

  1. Step 1: Analyze the script logic

    The script checks if there are no staged changes using git diff --cached --quiet. If true, it prints a message and exits with code 1.
  2. Step 2: Understand Git hook exit codes

    Exiting with code 1 in a pre-commit hook stops the commit process and shows the message.
  3. Final Answer:

    The commit is blocked with message 'No changes staged for commit.' -> Option A
  4. Quick Check:

    Exit 1 in pre-commit = block commit [OK]
Hint: Exit non-zero in pre-commit stops commit [OK]
Common Mistakes:
  • Assuming commit proceeds despite exit 1
  • Confusing staged vs unstaged changes
  • Expecting syntax errors from correct shell script
4. You wrote this post-commit hook script but it does not run after commits:
#!/bin/sh
echo "Commit done!"
Which is the most likely reason?
medium
A. The script filename is incorrect
B. The script is not executable
C. Git hooks cannot echo messages
D. The script must be in the project root, not .git/hooks

Solution

  1. Step 1: Check common hook issues

    Hooks must be executable files inside .git/hooks/ with correct names.
  2. Step 2: Identify the most common cause

    Often, scripts don't run because they lack execute permission, even if named correctly.
  3. Final Answer:

    The script is not executable -> Option B
  4. Quick Check:

    Hooks must be executable to run [OK]
Hint: Make hook scripts executable with chmod +x [OK]
Common Mistakes:
  • Placing scripts outside .git/hooks directory
  • Assuming echo is not allowed in hooks
  • Using wrong hook filenames
5. You want to create a custom Git hook that prevents commits if the commit message does not contain the word 'JIRA'. Which script placed in .git/hooks/commit-msg will achieve this?
hard
A. #!/bin/sh if grep -q 'JIRA' "$1"; then exit 1 fi
B. #!/bin/sh grep 'JIRA' "$1" || echo "Commit message missing JIRA"
C. #!/bin/sh if ! grep -q 'JIRA' "$1"; then echo "Commit message must include 'JIRA'." exit 1 fi
D. #!/bin/sh echo "Checking commit message for JIRA"

Solution

  1. Step 1: Understand commit-msg hook argument

    The commit message file path is passed as the first argument ($1) to the script.
  2. Step 2: Check script logic for enforcing 'JIRA'

    #!/bin/sh if ! grep -q 'JIRA' "$1"; then echo "Commit message must include 'JIRA'." exit 1 fi uses grep -q to check if 'JIRA' is missing, then prints a message and exits with 1 to block the commit.
  3. Step 3: Evaluate other options

    #!/bin/sh grep 'JIRA' "$1" || echo "Commit message missing JIRA" only echoes but does not block commit. #!/bin/sh if grep -q 'JIRA' "$1"; then exit 1 fi blocks if 'JIRA' is present (wrong logic). #!/bin/sh echo "Checking commit message for JIRA" just echoes without checks.
  4. Final Answer:

    #!/bin/sh if ! grep -q 'JIRA' "$1"; then echo "Commit message must include 'JIRA'." exit 1 fi -> Option C
  5. Quick Check:

    Exit 1 if 'JIRA' missing blocks commit [OK]
Hint: Use commit-msg hook with exit 1 to block bad messages [OK]
Common Mistakes:
  • Not exiting with non-zero to block commit
  • Checking for presence instead of absence
  • Only printing message without blocking
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard