Chapter 8.7 — post-merge Hook☕ 12 min read

post-merge Hook

Pull karo, aur npm install khud chal jaye. Developer ko manually npm install yaani nahi karna, hook kar dega.

01What is post-merge Hook

The post-merge hook runs AFTER a successful git pull that results in a merge.

It is a NOTIFICATION hook, not a gate — the merge has already happened. You cannot block it.

Exit code doesn't matter — the merge is done regardless of whether the hook succeeds or fails.

Primary use: automate setup tasks after receiving new code from the remote.

Common uses:

  • npm install — when package.json changes
  • Database migrations — when migration files change
  • Clear caches — when build config changes
  • Restart dev server — when core files change

The hook receives NO arguments — it just runs after the merge completes.

Note: post-merge only fires when git pull actually merges. Fast-forward pulls may not trigger it (depends on Git config).

# Create a post-merge hook
cat > .git/hooks/post-merge << 'EOF'
#!/bin/bash
echo "🔄 Merge completed! Checking for changes..."

# Check if package.json changed
CHANGED=$(git diff HEAD@{1} HEAD --name-only | grep "package.json")

if [ -n "$CHANGED" ]; then
  echo "📦 package.json changed! Running npm install..."
  npm install
fi

echo "✅ Post-merge setup complete!"
EOF

chmod +x .git/hooks/post-merge

# Now when you pull and package.json has changed:
git pull
# Updating abc1234..def5678
# Fast-forward
#  package.json | 5 ++---
#  1 file changed, 3 insertions(+), 2 deletions(-)
# 🔄 Merge completed! Checking for changes...
# 📦 package.json changed! Running npm install...
# ✅ Post-merge setup complete!
02Detecting Changed Files

The most common post-merge use case: run npm install when package.json changes.

Without this: developer pulls, code doesn't work, they wonder why. "Oh, I forgot npm install!"

The hook detects changes to package.json (or package-lock.json) and runs install automatically.

Use git diff HEAD@{1} HEAD --name-only to see what files changed in the pull.

For yarn users: check yarn.lock and run yarn install.

For pnpm users: check pnpm-lock.yaml and run pnpm install.

# Smart npm install on dependency changes
cat > .git/hooks/post-merge << 'EOF'
#!/bin/bash
echo "🔄 Checking for dependency changes..."

# Check package.json AND lock file
DEP_CHANGED=$(git diff HEAD@{1} HEAD --name-only | grep -E "package.json|package-lock.json")

if [ -n "$DEP_CHANGED" ]; then
  echo "📦 Dependencies changed! Installing..."
  npm install --silent 2>/dev/null
  
  if [ $? -eq 0 ]; then
    echo "✅ npm install completed"
  else
    echo "⚠️ npm install failed! Run manually: npm install"
  fi
else
  echo "ℹ️ No dependency changes"
fi

exit 0
EOF

chmod +x .git/hooks/post-merge
03Auto-Running npm install

If your team uses database migrations, pulling new code often requires running migrations.

post-merge can detect new migration files and run them automatically.

Pattern: check if migrations/ directory has new files, then run migration command.

  • For Rails: rails db:migrate
  • For Django: python manage.py migrate
  • For Prisma: npx prisma migrate deploy

Always check if the migration command exists before running — don't fail if project doesn't use it.

# Auto-run migrations when migration files change
cat > .git/hooks/post-merge << 'EOF'
#!/bin/bash
CHANGED=$(git diff HEAD@{1} HEAD --name-only)

# Check for migration files
if echo "$CHANGED" | grep -q "migrations/"; then
  echo "🗃️ Migration files changed!"
  
  # Try Prisma migrations first
  if command -v npx &> /dev/null; then
    echo "Running Prisma migrations..."
    npx prisma migrate deploy 2>/dev/null
  fi
  
  # Try Django migrations
  if [ -f "manage.py" ]; then
    echo "Running Django migrations..."
    python manage.py migrate --noinput 2>/dev/null
  fi
fi

exit 0
EOF

chmod +x .git/hooks/post-merge
💡 Pro Tip: post-merge hooks are most valuable when they PREVENT the "works on my machine" problem. When a teammate pulls your code and it doesn't work, it's usually because they forgot npm install, migrations, or cache clear. The post-merge hook automates these steps so code always works after pull.
04Running Migrations

After pulling new code, cached files might be stale or incompatible.

post-merge can clear caches: npm cache clean, rm -rf dist/, rm -rf .next/.

It can also trigger rebuilds if build configuration changed.

Be careful: don't delete files the developer is actively working on. Only clean artifacts, not source files.

# Comprehensive post-merge hook
cat > .git/hooks/post-merge << 'EOF'
#!/bin/bash
echo "🔄 Post-merge setup running..."

CHANGED_FILES=$(git diff HEAD@{1} HEAD --name-only)

# 1. npm install if dependencies changed
if echo "$CHANGED_FILES" | grep -q "package.json\|package-lock.json"; then
  echo "📦 Dependencies changed → npm install"
  npm install --silent 2>/dev/null
fi

# 2. Database migrations if migration files changed
if echo "$CHANGED_FILES" | grep -q "migrations/"; then
  echo "🗃️ Migrations changed → running migrations"
  npx prisma migrate deploy 2>/dev/null || true
fi

# 3. Clear build cache if config changed
if echo "$CHANGED_FILES" | grep -qE "webpack|vite|tsconfig|.babelrc"; then
  echo "🧹 Build config changed → clearing cache"
  rm -rf dist/ .next/ node_modules/.cache/
fi

# 4. Rebuild if needed
if echo "$CHANGED_FILES" | grep -q "package.json"; then
  echo "🏗️ Rebuilding project..."
  npm run build 2>/dev/null || true
fi

echo "✅ Post-merge setup complete!"
exit 0
EOF

chmod +x .git/hooks/post-merge
05Best Practices

post-merge only fires on MERGE pulls, not fast-forward pulls (unless configured).

git config pull.rebase false ensures pulls create merge commits that trigger post-merge.

With pull.rebase true, post-merge does NOT fire — use post-rewrite hook instead.

The hook runs synchronouslygit pull doesn't complete until the hook finishes.

If your hook takes 2 minutes (npm install + build), the developer waits 2 minutes.

Don't put interactive commands — the hook runs automatically, no user input possible.

If the hook fails, the merge still happened — exit code doesn't matter.

# Ensure post-merge fires on every pull
git config pull.rebase false
# Now pulls create merge commits → post-merge fires

# If your team uses rebase:
git config pull.rebase true
# post-merge will NOT fire!
# Use post-rewrite instead:
cat > .git/hooks/post-rewrite << 'EOF'
#!/bin/bash
case "$1" in
  rebase)
    echo "🔄 Rebase detected, running setup..."
    npm install --silent 2>/dev/null
    ;;
esac
exit 0
EOF
chmod +x .git/hooks/post-rewrite
post-merge is a convenience hook, not a safety hook. If it fails, nothing bad happens — the merge is already complete. But if your hook takes too long, developers will be frustrated by slow pulls. Keep it fast, or run long tasks in the background.

Lo kar liya — Key Points:

  • ✅ post-merge hook runs AFTER a successful git pull that results in a merge — it cannot block the merge
  • ✅ The #1 use case: auto-run npm install when package.json changes after pulling
  • ✅ Use git diff HEAD@{1} HEAD --name-only to see what files changed in the pull
  • ✅ Other uses: auto-run migrations, clear caches, warn about .env changes
  • ✅ Exit code doesn't matter — the merge already happened regardless of hook success
  • ✅ Only fires on MERGE pulls — fast-forward pulls may not trigger it
  • ✅ Keep the hook fast or run long tasks in background — slow hooks frustrate developers
Course Search
Search across all chapters & stages
📖

Search the course

Type any topic — branching, stash, rebase, hooks — and jump straight to that chapter.

merge branchesgit stashundo commitrebase