GitScrum / Docs

Git Hooks

Automate task management with Git hooks. Auto-update tasks on commits, start timers on checkout, and enforce branch naming with GitScrum CLI.

Open Source β€” GitScrum CLI is open source under the MIT license. Available on GitHub and all major package managers. Built for developers β€” Tasks, timers, sprints, and analytics in your terminal. Git-aware. CI/CD ready.

Automate your workflow with Git hooks. Update task status on commits, start timers on checkout, enforce branch naming conventionsβ€”all without thinking about it.


Quick Reference

gitscrum hooks install           # Interactive hook setup
gitscrum hooks list              # Show installed hooks
gitscrum hooks remove            # Remove hooks
gitscrum hooks test              # Test hook execution

Installation

Interactive Setup

gitscrum hooks install

Walks you through each hook:

? Install commit-msg hook?
  Prepends task ID to commit messages
  ❯ Yes
    No

? Install post-checkout hook?
  Switches timer to new branch's task
  ❯ Yes
    No

? Install pre-push hook?
  Updates task status on push
  ❯ Yes
    No

βœ“ Installed hooks: commit-msg, post-checkout, pre-push
  Location: .git/hooks/

Install Specific Hooks

gitscrum hooks install commit-msg
gitscrum hooks install pre-push post-checkout
gitscrum hooks install --all

Dry Run

Preview without installing:

gitscrum hooks install --dry-run

Available Hooks

commit-msg

Automatically prepends task ID to commit messages.

Trigger: After you write a commit message, before commit is finalized.

# Branch: feature/GS-123-auth-flow
$ git commit -m "add OAuth token refresh"

# Commit message becomes: [GS-123] add OAuth token refresh

Configuration:

# .gitscrum.yml
hooks:
  commit_msg:
    enabled: true
    format: "[{id}] "           # Prefix format
    skip_if_present: true       # Don't add if ID exists
    require_task_id: false      # Block commits without task ID
    exclude_branches:           # Skip on these branches
      - main
      - develop

Behavior:

Original MessageBranchResult
"add login"feature/GS-123-auth[GS-123] add login
"[GS-123] add login"feature/GS-123-auth[GS-123] add login (unchanged)
"add login"mainadd login (excluded)
"add login"hotfix-quickadd login (no task ID)

pre-commit

Runs before commit is created. Use for validation.

Trigger: Before commit, after staging.

hooks:
  pre_commit:
    enabled: true
    require_timer_running: false  # Block if no timer
    require_time_logged: false    # Block if <15 min logged
    check_branch_naming: true     # Validate branch format

Use Cases:

  • Enforce timer usage during work hours
  • Validate branch naming conventions
  • Check for uncommitted time entries

post-commit

Runs after commit is created.

Trigger: After successful commit.

hooks:
  post_commit:
    enabled: true
    log_commit: true      # Log commit in task activity
    auto_comment: false   # Add commit message as task comment

pre-push

Runs before push to remote.

Trigger: After git push, before data is sent.

hooks:
  pre_push:
    enabled: true
    update_status: true      # Set task to "In Progress"
    stop_timer: false        # Stop timer on push
    create_backup: false     # Backup timer data before push

Example Flow:

$ git push origin feature/GS-123-auth

Running pre-push hook...
βœ“ Task GS-123 status updated to "In Progress"
βœ“ Push completed

post-checkout

Runs after branch checkout.

Trigger: After git checkout or git switch.

hooks:
  post_checkout:
    enabled: true
    switch_timer: true    # Switch timer to new branch's task
    show_task: true       # Display task info after checkout
    auto_start: false     # Auto-start timer if task found

Example Flow:

$ git checkout feature/GS-456-payment

Running post-checkout hook...
βœ“ Timer switched from GS-123 to GS-456

πŸ“‹ GS-456: Implement payment gateway
   Status: In Progress | Sprint 15
   Estimate: 8 pts | Logged: 2h 15m

post-merge

Runs after successful merge.

Trigger: After git merge or git pull with merge.

hooks:
  post_merge:
    enabled: true
    log_merge: true       # Log merge in task activity
    close_task: false     # Close task if merging to main
    stop_timer: true      # Stop timer after merge

post-rewrite

Runs after commits are rewritten (rebase, amend).

Trigger: After git rebase or git commit --amend.

hooks:
  post_rewrite:
    enabled: true
    update_references: true  # Update task commit references

Hook Configuration

Global Configuration

Apply to all repositories:

# ~/.gitscrum/config.yml
hooks:
  commit_msg:
    enabled: true
    format: "[{id}] "
  post_checkout:
    enabled: true
    show_task: true

Project Configuration

Override for specific project:

# .gitscrum.yml
hooks:
  commit_msg:
    enabled: true
    format: "{id}: "  # Different format for this project
    require_task_id: true

Disable Specific Hooks

hooks:
  post_checkout:
    enabled: false

Managing Hooks

List Installed Hooks

gitscrum hooks list
πŸ”— Installed Hooks

Hook            β”‚ Status   β”‚ Source
────────────────┼──────────┼────────────────
commit-msg      β”‚ Active   β”‚ gitscrum
post-checkout   β”‚ Active   β”‚ gitscrum
pre-push        β”‚ Active   β”‚ gitscrum
pre-commit      β”‚ Active   β”‚ husky (external)

Test Hooks

Simulate hook execution:

gitscrum hooks test commit-msg --message "add feature"
Testing commit-msg hook...

Input:   "add feature"
Branch:  feature/GS-123-auth
Output:  "[GS-123] add feature"

βœ“ Hook would execute successfully

Remove Hooks

# Remove specific hook
gitscrum hooks remove commit-msg

# Remove all GitScrum hooks
gitscrum hooks remove --all

Temporarily Disable

Skip hooks for a single command:

git commit --no-verify -m "emergency fix"
git push --no-verify

Or set environment variable:

export GITSCRUM_HOOKS_DISABLED=1
git commit -m "skip hooks"

Hook Scripts

GitScrum hooks are shell scripts in .git/hooks/:

$ cat .git/hooks/commit-msg
#!/bin/sh
# GitScrum CLI hook - commit-msg
# Installed: 2026-02-07 09:00:00

exec gitscrum hooks run commit-msg "$@"

Manual Editing

You can edit hooks directly, but changes may be overwritten:

# Add custom logic before GitScrum hook
#!/bin/sh

# Custom: Check commit message length
if [ $(cat "$1" | wc -c) -lt 10 ]; then
  echo "Error: Commit message too short"
  exit 1
fi

# GitScrum hook
exec gitscrum hooks run commit-msg "$@"

Hook Order

If you have existing hooks, GitScrum appends rather than replaces:

$ gitscrum hooks install commit-msg

Existing commit-msg hook detected.
? How to handle:
  ❯ Append (run both)
    Replace (backup existing)
    Skip (keep existing)

Integration with Other Tools

Husky

GitScrum works alongside Husky:

// package.json
{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged && gitscrum hooks run pre-commit",
      "commit-msg": "gitscrum hooks run commit-msg"
    }
  }
}

Lefthook

# lefthook.yml
commit-msg:
  commands:
    gitscrum:
      run: gitscrum hooks run commit-msg {1}

Pre-commit Framework

# .pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: gitscrum-commit-msg
        name: GitScrum Commit Message
        entry: gitscrum hooks run commit-msg
        language: system
        stages: [commit-msg]

Troubleshooting

Hook Not Running

# Check if hook is executable
ls -la .git/hooks/commit-msg
# Should show: -rwxr-xr-x

# Make executable if needed
chmod +x .git/hooks/commit-msg

Hook Errors

# Run hook manually to see errors
gitscrum hooks run commit-msg .git/COMMIT_EDITMSG

Debug Mode

export GITSCRUM_DEBUG=1
git commit -m "test"
# Shows detailed hook execution

Reset Hooks

# Remove and reinstall
gitscrum hooks remove --all
gitscrum hooks install --all

Best Practices

  1. Start minimal. Install only hooks you'll use. Add more as needed.
  2. Test first. Use --dry-run and hooks test before committing to a workflow.
  3. Document for team. Add hook setup to README for new team members.
  4. Use project config. Put hook settings in .gitscrum.yml for team consistency.
  5. Handle failures gracefully. Hooks shouldn't block valid commits on network errors.

Example Workflows

Strict Tracking

Enforce time tracking on every commit:

hooks:
  pre_commit:
    enabled: true
    require_timer_running: true
  commit_msg:
    enabled: true
    require_task_id: true
  post_checkout:
    enabled: true
    switch_timer: true
    auto_start: true

Light Touch

Just add task IDs to commits:

hooks:
  commit_msg:
    enabled: true
  post_checkout:
    enabled: true
    show_task: true

CI-Friendly

Disable hooks in CI while keeping local:

# CI environment
export GITSCRUM_HOOKS_DISABLED=1