Git push rejected "non-fast-forward"

Learn git push rejected "non-fast-forward" with practical examples, diagrams, and best practices. Covers git, push, rebase development techniques with visual explanations.

Resolving Git Push Rejected: 'non-fast-forward' Errors

Hero image for Git push rejected "non-fast-forward"

Learn why Git rejects pushes with 'non-fast-forward' errors and how to resolve them using git pull, git rebase, or git push --force safely.

The 'non-fast-forward' error is one of the most common issues Git users encounter, especially when collaborating on a shared repository. It occurs when your local branch history has diverged from the remote branch history. In simpler terms, someone else has pushed changes to the same branch on the remote repository since you last pulled, and your local branch is no longer a direct ancestor of the remote branch. Git, by default, prevents you from overwriting these changes to protect the remote history.

Understanding the 'non-fast-forward' Error

When you attempt to git push, Git compares your local branch's history with the remote branch's history. A 'fast-forward' push is possible only if the remote branch can be updated by simply moving its pointer forward to include your new commits, without losing any existing commits. If the remote branch contains commits that are not present in your local branch (meaning the histories have diverged), Git cannot perform a fast-forward merge and rejects your push to prevent accidental data loss. This mechanism ensures that no work is silently overwritten.

Hero image for Git push rejected "non-fast-forward"

Visualizing a 'non-fast-forward' Git history

Resolving the 'non-fast-forward' Error

There are several strategies to resolve a 'non-fast-forward' error, each with its own implications for your commit history. The most common and recommended approach is to integrate the remote changes into your local branch before pushing. This can be done using git pull (which performs a fetch and a merge by default) or git pull --rebase.

Method 1: Git Pull (Fetch + Merge)

The simplest way to resolve a 'non-fast-forward' error is to first pull the remote changes into your local branch. By default, git pull is a shorthand for git fetch followed by git merge FETCH_HEAD. This will create a new merge commit in your local history that combines your changes with the remote changes. After the merge, your local branch history will include all remote commits, allowing for a fast-forward push.

git pull origin <branch-name>
git push origin <branch-name>

Pulling remote changes and then pushing

Method 2: Git Pull --rebase (Fetch + Rebase)

Alternatively, you can use git pull --rebase. This command fetches the remote changes and then reapplies your local commits on top of the updated remote branch. This effectively rewrites your local history, making it appear as if your changes were made after the remote changes. The result is a linear history, which many developers prefer for its cleanliness. However, rebasing rewrites commit history, so it should be used with caution, especially on branches that others have already pulled.

git pull --rebase origin <branch-name>
git push origin <branch-name>

Pulling remote changes with rebase and then pushing

Method 3: Git Push --force (Use with Extreme Caution)

The git push --force (or git push -f) command is a powerful tool that should be used with extreme caution. It bypasses the 'non-fast-forward' check and overwrites the remote branch with your local branch's history, regardless of whether it's a fast-forward change. This means any commits on the remote branch that are not in your local branch will be lost forever. This command is typically reserved for specific scenarios, such as correcting a mistake on a private branch or after a git rebase on a branch that only you are working on and you are certain no one else has pulled from it.

git push --force origin <branch-name>

Forcing a push (use with extreme caution)

1. Step 1: Fetch Remote Changes

Before attempting to push, always fetch the latest changes from the remote to see if there are any updates you're missing. This doesn't merge anything, just updates your remote-tracking branches.

2. Step 2: Check Status

After fetching, run git status to see if your local branch is behind, ahead, or diverged from the remote branch. This will inform your next action.

3. Step 3: Integrate Remote Changes

If your branch is behind or diverged, integrate the remote changes using either git pull origin <branch-name> (for a merge commit) or git pull --rebase origin <branch-name> (for a linear history, but be cautious on shared branches).

4. Step 4: Resolve Conflicts (if any)

If there are merge conflicts during the pull/rebase, resolve them manually. Git will guide you through the process. After resolving, commit the changes (for git pull) or continue the rebase (for git pull --rebase).

5. Step 5: Push Your Changes

Once your local branch is up-to-date with the remote and all conflicts are resolved, you can safely git push origin <branch-name>.