Skip to content

Git Hooks

Git hook system for automatic code indexing, maintaining synchronized knowledge base across projects.

Overview

Git hooks automatically trigger incremental indexing when code changes. Two hooks ship in the platform's hooks/ directory:

  • post-commit: Index files changed in the new commit
  • post-merge: Index files changed by a pull/merge

Both hooks POST the changed file list to the indexer's HTTP service. There is no post-checkout hook and no index_changes.py script — indexing goes through the running wdg-indexer service.

Hook Installation

Automatic Installation

Hooks are installed into a repository's .git/hooks/ by hooks/install-hooks.sh, which the CLI runs when a project or repository is set up:

bash
# Creating a new project with Wikit
wdg create my-site --init-wikit

# Adding / cloning a repository into a project
wdg my-site repo add https://github.com/client/repo

# Re-install hooks for a specific repo
wdg my-site repo hooks <repo-name>

Manual Installation

bash
# From the platform root, run the installer against a repo
hooks/install-hooks.sh /path/to/repository

# Or copy the two hooks directly
cp hooks/post-commit hooks/post-merge /path/to/repository/.git/hooks/
chmod +x /path/to/repository/.git/hooks/post-commit /path/to/repository/.git/hooks/post-merge

Hook Implementations

Both hooks follow the same shape: locate the WDG platform root, derive the project name from the repo path, skip silently if the wdg-indexer container is not running, translate host paths to the container's /workspace, and fire a backgrounded curl at the indexer.

post-commit Hook

bash
#!/usr/bin/env bash
# .git/hooks/post-commit

REPO_DIR=$(git rev-parse --show-toplevel)
REPO_NAME=$(basename "$REPO_DIR")

# Walk up to find the platform root (dir containing docker-compose.yml + projects/)
find_wdg_root() { ... }
WDG_ROOT=$(find_wdg_root)
[ -z "$WDG_ROOT" ] && exit 0   # not inside a WDG checkout

# Derive the index target from the repo's location
if [[ "$REPO_DIR" == */repositories/* ]]; then
    INDEX_PROJECT="$REPO_NAME"
elif [[ "$REPO_DIR" == */projects/* ]]; then
    INDEX_PROJECT=$(echo "$REPO_DIR" | sed 's|.*/projects/\([^/]*\).*|\1|')
else
    exit 0
fi

# Skip if the indexer service isn't running (no blocking, no errors)
docker ps --format '{{.Names}}' | grep -q "wdg-indexer" || exit 0

# Changed files in this commit, with host paths rewritten to the container's /workspace
CHANGED_FILES=$(git diff-tree --no-commit-id --name-only -r HEAD \
    | while read -r file; do echo "$REPO_DIR/$file"; done)
CHANGED_FILES=$(echo "$CHANGED_FILES" | sed "s|${WDG_ROOT}|/workspace|g")
FILES_JSON=$(echo "$CHANGED_FILES" | jq -R -s -c 'split("\n") | map(select(length > 0))')

# Fire-and-forget: POST to the indexer in the background so the commit isn't blocked
(curl -s --max-time 300 -X POST http://localhost:8666/index/incremental \
    -H "Content-Type: application/json" \
    -d "{\"files\": $FILES_JSON, \"project\": \"$INDEX_PROJECT\"}" \
    > /dev/null 2>&1) &

Key behaviors:

  • No file-extension filtering in the hook — the indexer service decides what is indexable (unsupported extensions are skipped server-side).
  • Host → container path translation${WDG_ROOT} is rewritten to /workspace, matching the read-only source mounts in the indexer service so the paths resolve inside the container.
  • Backgrounded, 300 s cap — large changesets can take 60–120 s; the request is detached so the commit returns immediately.

post-merge Hook

Identical to post-commit except for how it computes the changed-file set. It diffs from the pre-merge head:

bash
ORIG_HEAD=$(git rev-parse ORIG_HEAD 2>/dev/null || git rev-parse HEAD~1)
CHANGED_FILES=$(git diff --name-only "$ORIG_HEAD" HEAD \
    | while read -r file; do echo "$REPO_DIR/$file"; done)
# ...same /workspace rewrite and backgrounded curl to /index/incremental

Logging

The hooks themselves write only two echo lines (a "indexing N files (background)" notice). Indexing output goes to the indexer service logs:

bash
wdg logs indexer            # or: docker logs wdg-indexer

Troubleshooting

Hooks Not Running

bash
# Check the two hooks are present and executable
ls -la .git/hooks/post-commit .git/hooks/post-merge

# Make executable
chmod +x .git/hooks/post-commit .git/hooks/post-merge

# Re-install via the platform installer
hooks/install-hooks.sh "$(git rev-parse --show-toplevel)"

# Test manually (no-op if wdg-indexer isn't running)
.git/hooks/post-commit

Nothing Gets Indexed

bash
# The hooks exit silently if the indexer container isn't up
docker ps --format '{{.Names}}' | grep wdg-indexer

# Confirm the service is reachable on the host
curl http://localhost:6666/health     # default host port (container 8666)

# Hit the endpoint the hooks use, by hand
curl -X POST http://localhost:6666/index/incremental \
  -H "Content-Type: application/json" \
  -d '{"files": ["/workspace/projects/my-site/repositories/my-site/functions.php"], "project": "my-site"}'

Inside a container the indexer listens on 8666; the hooks target localhost:8666 because they translate paths for the container, but the service is published to the host on 6666 — use 6666 for manual checks from your machine.

Hook Debugging

Add debug output to hooks:

bash
#!/bin/bash
set -x  # Print commands as they execute

# Rest of hook...

Hook Management Commands

Disable Hooks Temporarily

bash
# Rename hooks to disable
mv .git/hooks/post-commit .git/hooks/post-commit.disabled

# Re-enable
mv .git/hooks/post-commit.disabled .git/hooks/post-commit

Skip Hooks for Single Commit

bash
git commit --no-verify -m "Skip hooks for this commit"

Reinstall Hooks

bash
# Via CLI
wdg my-site repo hooks custom-theme

# Manual (the two shipped hooks)
hooks/install-hooks.sh /path/to/repo
# or
cp hooks/post-commit hooks/post-merge /path/to/repo/.git/hooks/
chmod +x /path/to/repo/.git/hooks/post-commit /path/to/repo/.git/hooks/post-merge

Best Practices

  1. Keep hooks fast - Run indexing in background if needed
  2. Add logging - Track what gets indexed and when
  3. Error handling - Don't block commits on indexing failures
  4. Conditional logic - Skip indexing when appropriate
  5. Version control - Keep hook templates in repository

Custom Hooks

Creating Custom Hook

bash
#!/bin/bash
# .git/hooks/pre-push

# Run linting before push
echo "Running linter..."
wdg theme lint $(basename $(pwd))

if [ $? -ne 0 ]; then
    echo "Linting failed! Fix errors before pushing."
    exit 1
fi

echo "✓ Linting passed"

Shared Hook Logic

bash
# hooks/common.sh
get_project_name() {
    basename $(dirname $(dirname $(git rev-parse --show-toplevel)))
}

get_repo_name() {
    basename $(git rev-parse --show-toplevel)
}

# Source in hooks
source "$(dirname $0)/common.sh"
PROJECT=$(get_project_name)

See Also: