This error occurs when Git's pre-rebase hook script exits with a non-zero status code, preventing the rebase operation from proceeding. The hook is intentionally blocking the rebase, often to protect published branches or enforce repository policies.
The "pre-rebase hook exited with error code 1" error indicates that a Git hook script located at `.git/hooks/pre-rebase` has rejected your rebase attempt. This is actually the hook working as designed - it's preventing a rebase that violates whatever policy the hook enforces. Git hooks are scripts that run automatically at specific points in the Git workflow. The pre-rebase hook specifically runs before `git rebase` changes anything, giving you an opportunity to abort the operation if conditions aren't right. When this hook exits with a non-zero status (like 1), Git interprets this as "do not proceed" and stops the rebase. Common reasons for pre-rebase hooks to reject a rebase include: - **Protecting published branches**: Rebasing commits that have already been pushed to a shared repository rewrites history, which causes problems for other developers - **Preventing rebase on main/master**: Some teams prohibit rebasing the main branch entirely - **Enforcing workflow policies**: The hook might check if the branch has been merged into a protected branch - **Custom team rules**: Organizations often implement specific policies through hooks The sample pre-rebase hook that comes with Git (located at `.git/hooks/pre-rebase.sample`) is designed to prevent rebasing commits that have already been merged into the "next" or "mainline" branch, following the Git project's own development workflow.
When the pre-rebase hook fails, it typically outputs a message explaining why. Read this message carefully:
$ git rebase main
pre-rebase: Rebasing published commits is not allowed.
error: pre-rebase hook exited with error code 1The message before the error line comes from the hook itself and explains the rejection reason. This tells you what policy you're violating.
If there's no descriptive message, you can examine the hook script directly:
cat .git/hooks/pre-rebaseThis will show you exactly what the hook is checking for.
Verify whether the pre-rebase hook is intentionally active or was accidentally enabled:
# List hooks in the repository
ls -la .git/hooks/
# Check if pre-rebase exists (without .sample extension)
ls -la .git/hooks/pre-rebase 2>/dev/null && echo "Hook is active" || echo "No active pre-rebase hook"
# Check for sample hooks
ls -la .git/hooks/pre-rebase.sample 2>/dev/nullIf you find a pre-rebase file but expected no hook, someone may have accidentally renamed pre-rebase.sample to pre-rebase.
To disable an accidentally activated hook:
# Rename it back to sample (preserves the hook for reference)
mv .git/hooks/pre-rebase .git/hooks/pre-rebase.sample
# Or make it non-executable
chmod -x .git/hooks/pre-rebase
# Or remove it entirely
rm .git/hooks/pre-rebaseGit can use hooks from a global directory instead of or in addition to repository hooks. Check if global hooks are configured:
# Check if a global hooks path is set
git config --global core.hooksPath
# Check all hook configurations
git config --list | grep -i hookIf core.hooksPath is set, hooks are loaded from that directory:
# Example: if core.hooksPath is ~/.git-hooks
ls -la ~/.git-hooks/pre-rebase 2>/dev/nullTo temporarily disable global hooks:
# Unset for the current repository only
git config --local core.hooksPath ""
# Or temporarily override for one command
git -c core.hooksPath="" rebase mainIf you understand why the hook is blocking and have a legitimate reason to proceed anyway, you can bypass it:
# Skip the pre-rebase hook for this rebase
git rebase --no-verify main
# Also works with interactive rebase
git rebase -i --no-verify HEAD~3Warning: The --no-verify flag bypasses both the pre-rebase hook and any commit-msg hooks during the rebase. Only use this if you understand the implications.
Common legitimate reasons to bypass:
- You're rebasing a local branch that was never pushed
- You're the only developer working on this branch
- You're cleaning up commits before the first push
- The hook logic is outdated or doesn't apply to your situation
A non-invasive way to disable hooks temporarily without modifying them:
# Point hooks to a non-existent or empty directory
git config core.hooksPath /dev/null
# Now run your rebase
git rebase main
# Restore hooks afterward
git config --unset core.hooksPathFor a single command only:
# Temporarily override hooks path for just this command
git -c core.hooksPath=/dev/null rebase mainThis approach is safer than modifying or removing hook files because:
- It doesn't change any files
- It's easily reversible
- Other team members' hooks remain unaffected
Git ships with a sample pre-rebase hook that's well-documented. Understanding it helps you work with similar custom hooks:
# View the sample hook
cat .git/hooks/pre-rebase.sampleThe sample hook checks:
1. If rebasing onto a protected branch: It defines a "publish" branch (default: "next") and a "mainline" branch (default: "master")
2. If commits are already merged: Uses git merge-base to determine if commits have been integrated
The logic essentially asks: "Has this topic branch been merged into the mainline? If so, rebasing would rewrite published history."
To customize the sample hook for your workflow:
# Copy and activate the sample
cp .git/hooks/pre-rebase.sample .git/hooks/pre-rebase
# Edit to match your branch names
# Change 'next' to your integration branch
# Change 'master' to 'main' if neededThe hook parameters are:
- $1: The upstream branch that the series was forked from
- $2: The branch being rebased (empty if rebasing current branch)
If the pre-rebase hook is blocking your rebase for valid reasons (protecting published history), consider alternatives:
Use merge instead of rebase:
# Instead of rebase, merge to incorporate changes
git checkout feature-branch
git merge mainMerging preserves history and is safe for published branches.
Create a new branch for the rebase:
# Create a fresh branch from your work
git checkout -b feature-branch-v2 feature-branch
# Rebase the new branch (hasn't been pushed yet)
git rebase main
# The old branch remains intact for referenceUse cherry-pick for specific commits:
# Create a new branch from main
git checkout -b feature-clean main
# Cherry-pick specific commits you want
git cherry-pick abc123 def456 ghi789This achieves a similar result to rebase without rewriting the original branch's history.
If the hook's logic doesn't match your team's workflow, modify it:
# Open the hook in your editor
code .git/hooks/pre-rebase
# or
vim .git/hooks/pre-rebaseExample: Allow rebase on feature branches only:
#!/bin/bash
# pre-rebase hook - allow rebasing only on feature/* branches
branch=$(git rev-parse --abbrev-ref HEAD)
if [[ "$branch" == "main" || "$branch" == "master" || "$branch" == "develop" ]]; then
echo "pre-rebase: Rebasing $branch is not allowed."
echo "Create a feature branch first: git checkout -b feature/my-feature"
exit 1
fi
exit 0Example: Detect if we're in a rebase and allow it:
#!/bin/bash
# Check if we're in the middle of a rebase already
if [ -d ".git/rebase-merge" ] || [ -d ".git/rebase-apply" ]; then
exit 0 # Allow continuing rebases
fi
# Your normal hook logic here...Make sure the hook is executable:
chmod +x .git/hooks/pre-rebaseUnderstanding pre-rebase hook parameters:
The pre-rebase hook receives up to two arguments:
- $1: The upstream branch that the series was forked from
- $2: The branch being rebased (empty when rebasing the current branch)
#!/bin/bash
echo "Rebasing onto: $1"
echo "Branch being rebased: ${2:-current branch}"Using git branch --contains for smart protection:
The sample hook uses git branch --contains to check if commits have been merged:
# Check if commit is in any remote branch
git branch -r --contains HEAD
# Check if commit is in a specific branch
git branch --contains HEAD | grep -q "main" && echo "Already in main"Hook execution order during rebase:
1. pre-rebase - Runs once before rebase starts (can abort)
2. During rebase, for each commit:
- pre-commit - Runs before each commit is applied
- commit-msg - Can modify commit message
- post-commit - Runs after each commit
3. post-rewrite - Runs once after all commits are rewritten (with "rebase" argument)
Note: Git does NOT run hooks during git rebase --continue after conflict resolution by default. This can cause issues with pre-commit hooks.
Sharing hooks with your team:
Hooks in .git/hooks/ are not tracked by Git. To share hooks:
# Create a hooks directory in your repo
mkdir -p .githooks
# Add your pre-rebase hook
cp .git/hooks/pre-rebase .githooks/
# Have team members configure Git to use it
git config core.hooksPath .githooksOr use a setup script:
#!/bin/bash
# setup-hooks.sh
for hook in .githooks/*; do
ln -sf "../../$hook" ".git/hooks/$(basename $hook)"
doneDebugging hooks:
# Add debug output to your hook
#!/bin/bash
set -x # Enable debug tracing
echo "Hook running with args: $@"
# Or log to a file
exec >> /tmp/pre-rebase-hook.log 2>&1
date
echo "Args: $@"Hooks and Git GUIs:
Some Git GUIs (GitKraken, Sourcetree, VS Code) may not always respect hooks or may not show hook output clearly. If hooks work on command line but not in your GUI:
- Check the GUI's settings for hook support
- Some GUIs have options to enable/disable hooks
- Try the operation from command line to see full hook output
warning: BOM detected in file, this may cause issues
UTF-8 Byte Order Mark (BOM) detected in file
fatal: Server does not support --shallow-exclude
Server does not support --shallow-exclude
warning: filtering out blobs larger than limit
Git partial clone filtering large blobs warning
fatal: Server does not support --shallow-since
Server does not support --shallow-since in Git
kex_exchange_identification: Connection closed by remote host
Connection closed by remote host when connecting to Git server