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: