How to fix remote: error: refusing to update checked out branch: refs/heads/main in Git

GitINTERMEDIATELOWUpdated Dec 6, 2025· 287 views

This error occurs when you try to push to a branch that is currently checked out in a non-bare remote repository. Git prevents this to avoid making the remote working directory inconsistent. The fix involves either converting the remote to a bare repository or pushing to a different branch.

Quick fix

Fixes remote: error: refusing to update checked out branch: refs/heads/main

cd /path/to/repo
git rev-parse --is-bare-repository
  1. Determine the repository type on the remote
  2. Option A: Convert to a bare repository (recommended for servers)
  3. Option B: Checkout a different branch on the remote
  4. Option C: Use receive.denyCurrentBranch=updateInstead (Git 2.3+)
git — error
cd /path/to/repo
git rev-parse --is-bare-repository
remote: error: refusing to update checked out branch: refs/heads/main

What this error means

When you push changes to a Git repository, the receiving repository must update its branch references. If the remote repository is a "non-bare" repository (one with a working directory and checked-out files), Git refuses to update the branch that is currently checked out there. This protection exists because updating a checked-out branch would cause the remote's working directory and index to become out of sync with the branch HEAD. Anyone working in that remote repository would suddenly find their files in an inconsistent state, potentially losing uncommitted work. This error typically appears in two scenarios: 1. **Development server setups** - Pushing to a repository on a server where you've manually cloned and checked out files 2. **Peer-to-peer workflows** - Pushing directly between developer machines rather than through a central bare repository The error message specifically mentions `refs/heads/main` (or `master`) because that's the branch being rejected. You can push to any other branch of the same repository without issues—the restriction only applies to the currently checked-out branch.

Typical symptoms

  • git push fails with 'refusing to update checked out branch' error
  • Error mentions refs/heads/main or refs/heads/master specifically
  • Push works to other branches but fails to the default branch
  • The remote repository has a working directory with files checked out
  • Push was working before but started failing after someone checked out a branch on the remote

Common causes

  1. The remote repository is non-bare and has the target branch checked out (most common)
  2. You initialized the remote with 'git init' instead of 'git init --bare'
  3. The remote was created by cloning another repository, not as a central server
  4. Someone manually checked out a branch on what should be a bare repository
  5. Your deployment workflow expects to push to a branch where files are served from

How to fix "remote: error: refusing to update checked out branch: refs/heads/main"

1Determine the repository type on the remote

First, check if the remote repository is bare or non-bare. SSH into the remote server and run:

bash
cd /path/to/repo
git rev-parse --is-bare-repository

If it returns false, the repository is non-bare and has a working directory. This is the root cause of the error.

You can also check by looking for a .git folder:
- Non-bare repository: Has a .git subdirectory and checked-out files
- Bare repository: Contains Git data directly (objects, refs, HEAD) without a working directory

2Option A: Convert to a bare repository (recommended for servers)

If this repository is meant to be a central server that receives pushes, convert it to bare. On the remote server:

bash
cd /path/to/repo
git config --bool core.bare true

Then remove the working directory files (keep them backed up if needed):

bash
# First, back up if you have uncommitted work
cp -r . ../repo-backup

# Remove working directory files, keeping .git
rm -rf !(*.git)
# Or move everything from .git to the repo root
mv .git/* .
rm -rf .git

For a cleaner approach, create a fresh bare clone:

bash
cd ..
git clone --bare repo repo.git
# Then update your remote URL to point to repo.git
3Option B: Checkout a different branch on the remote

If you need to keep the non-bare repository (e.g., for deployment), switch the remote to a different branch. SSH into the remote and run:

bash
cd /path/to/repo
git checkout -b temp-branch
# Or checkout an existing branch
git checkout develop

Now you can push to main because it's no longer checked out. After pushing, you can switch back:

bash
git checkout main

This is a temporary workaround—consider using a deployment branch or proper CI/CD instead.

4Option C: Use receive.denyCurrentBranch=updateInstead (Git 2.3+)

Git 2.3.0 introduced a safer way to push to checked-out branches. On the remote repository, run:

bash
git config receive.denyCurrentBranch updateInstead

This tells Git to update both the branch AND the working directory when receiving a push. The working directory will be updated to match the pushed content if it's clean.

Important caveats:
- This only works if the remote working directory is clean (no uncommitted changes)
- If there are uncommitted changes, the push will still be rejected
- This is safe for deployment scenarios but not for repositories with active development

5Option D: Push to a different branch, then merge remotely

If you can't modify the remote configuration, push to a different branch:

bash
git push origin main:deploy-staging

Then SSH into the remote and merge:

bash
cd /path/to/repo
git merge deploy-staging

This is useful when you don't have admin access to change the remote's Git configuration.

6Future prevention: Always use bare repositories for central servers

When setting up a new remote repository that will receive pushes, always create it as bare:

bash
git init --bare /path/to/repo.git

Or clone an existing repository as bare:

bash
git clone --bare https://github.com/user/repo.git

Bare repositories:
- Have no working directory or checked-out files
- Can receive pushes to any branch without restrictions
- Are the standard for Git servers (GitHub, GitLab use bare repos)
- Convention: name them with .git suffix (e.g., myproject.git)

Advanced notes

### Understanding Bare vs Non-Bare Repositories

| Feature | Non-Bare | Bare |
|---------|----------|------|
| Working directory | Yes | No |
| .git folder | Subdirectory | Root level |
| Can checkout branches | Yes | No |
| Can receive pushes | Limited | Any branch |
| Use case | Development | Server/central |

### The receive.denyCurrentBranch Options

| Value | Behavior |
|-------|----------|
| refuse (default) | Reject pushes to checked-out branch |
| warn | Allow push but print warning |
| ignore | Allow push silently (dangerous!) |
| updateInstead | Allow push and update working directory |

Never use `ignore` - it leaves the working directory completely out of sync with HEAD, causing confusion and potential data loss.

### Deployment Workflows

For deployment scenarios where you want to push and have files automatically update, consider these alternatives:

1. Git hooks: Use a post-receive hook in a bare repo to checkout files elsewhere:

bash
#!/bin/bash
GIT_WORK_TREE=/var/www/mysite git checkout -f

2. CI/CD pipelines: Push to a bare repo, trigger a deployment script

3. Pull-based deployment: Have the server pull changes instead of receiving pushes

### Why This Error Exists

Git's design philosophy is that pushing is for synchronizing bare repositories. Non-bare repositories should use git pull to receive changes. This model avoids:
- Overwriting uncommitted work
- Index/working directory desynchronization
- Confusion about which changes are local vs received

Frequently asked questions

What does "remote: error: refusing to update checked out branch: refs/heads/main" mean?
When you push changes to a Git repository, the receiving repository must update its branch references. If the remote repository is a "non-bare" repository (one with a working directory and checked-out files), Git refuses to update the branch that is currently checked out there. This protection exists because updating a checked-out branch would cause the remote's working directory and index to become out of sync with the branch HEAD.
How do I fix "remote: error: refusing to update checked out branch: refs/heads/main"?
This error occurs when you try to push to a branch that is currently checked out in a non-bare remote repository. Git prevents this to avoid making the remote working directory inconsistent. The fix involves either converting the remote to a bare repository or pushing to a different branch.
What causes "remote: error: refusing to update checked out branch: refs/heads/main"?
The remote repository is non-bare and has the target branch checked out (most common) You initialized the remote with 'git init' instead of 'git init --bare' The remote was created by cloning another repository, not as a central server
Is the "remote: error: refusing to update checked out branch: refs/heads/main" error serious?
It is a low-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading