When implementing Git hooks for deployment automation, many developers encounter the frustrating "Not a git repository" error in post-receive hooks. The fundamental issue stems from environment context differences between manual execution and hook execution.
The key difference between your manual test and hook execution lies in the working directory context. While your manual git pull
works because you're in the correct directory, the hook runs with a different working directory - typically the bare repository's directory.
# Check current directory in hook for debugging
echo "Current directory: $(pwd)" >> hook-debug.log
Here's a more reliable way to implement your post-receive hook:
#!/bin/bash
echo "--initializing hook--"
# Explicitly change to the working copy directory
WORK_TREE="~/websites/testing"
GIT_DIR="$WORK_TREE/.git"
echo "--prepare update--"
git --work-tree="$WORK_TREE" --git-dir="$GIT_DIR" pull origin master
echo "--update completed--"
For more complex deployment scenarios, consider these patterns:
# Method 1: Using absolute paths
cd /home/user/websites/testing || exit 1
unset GIT_DIR
git pull
# Method 2: Environment variables
export GIT_WORK_TREE=/home/user/websites/testing
export GIT_DIR=$GIT_WORK_TREE/.git
git pull
Add these debugging lines to your hook to better understand the execution context:
echo "===== ENVIRONMENT DUMP ====="
echo "PWD: $PWD"
echo "USER: $USER"
echo "GIT_DIR: $GIT_DIR"
env | sort
echo "============================"
I recently encountered a peculiar issue while setting up a Git post-receive hook to automatically pull changes to a working directory. The hook executes but fails when attempting to run git pull
, despite working perfectly when run manually.
Here's the hook script I was using:
#!/bin/bash
echo "--initializing hook--"
cd ~/websites/testing
echo "--prepare update--"
git pull
echo "--update completed--"
And here's the error output:
6bfa32c..71c3d2a master -> master
--initializing hook--
--prepare update--
fatal: Not a git repository: '.'
Failed to find a valid git directory.
--update completed--
The fundamental issue here is that Git hooks execute in a different environment than your interactive shell. Three key factors contribute to this problem:
- The working directory isn't properly set
- Environment variables (like GIT_DIR) may be inherited from the hook context
- The shell context changes when executed by Git
Here are three robust approaches to solve this:
1. Full Path Specification
#!/bin/bash
WORKTREE="/home/user/websites/testing"
GIT_DIR="$WORKTREE/.git"
echo "-- Updating work tree --"
git --work-tree="$WORKTREE" --git-dir="$GIT_DIR" pull
2. Environment Reset
#!/bin/bash
unset GIT_DIR
cd ~/websites/testing || exit
git pull
3. Using git-worktree
For more complex setups:
#!/bin/bash
export GIT_WORK_TREE=~/websites/testing
export GIT_DIR=~/repos/testing.git
git pull
- Always use absolute paths in hooks
- Consider error handling and logging
- Verify the executing user has proper permissions
- Use
set -e
to fail on errors
Here's a production-ready version:
#!/bin/bash
set -e
LOG_FILE="/var/log/git/post-receive.log"
REPO_PATH="/home/gituser/repos/project.git"
WORK_TREE="/var/www/production"
exec &>> "$LOG_FILE"
echo "--- $(date) ---"
echo "Starting deployment"
git --work-tree="$WORK_TREE" --git-dir="$REPO_PATH" pull origin master
# Additional deployment steps
cd "$WORK_TREE" || exit
npm install --production
systemctl reload nginx
echo "Deployment completed successfully"