Git & Server Workflow

Git pull fails: understand diverging branches, merge and rebase

Understand the history locally first

Status and history comparisons read local Git data. Fetch and pull contact the configured remote. Commits, paths and diffs can contain personal information.

In this article
  1. What fast-forward means
  2. Check the working tree first
  3. Compare local and remote history
  4. Choose between merge and rebase
  5. Preserve a local reference and rebase
  6. Resolve conflicts or abort deliberately
  7. Understand regular server updates and their limits
  8. References

You want to deploy a website update, but git pull --ff-only stops. This often is not a download failure: the local branch and remote have acquired different new commits. A simple fast-forward cannot integrate both developments.

That happened to my worldnode checkout on 6 October 2026. The server had its own World Observer dashboard commit while GitHub contained a website change. A subsequent rebase succeeded. This real example makes the terminology easier to understand.

What fast-forward means

A fast-forward moves the local branch pointer along an existing history. It requires no additional local development that needs to be integrated with the target.

When a local commit and a remote commit both appear after a shared starting point, neither automatically replaces the other. They are not yet arranged in one sequence. --ff-only requires the simple case and stops otherwise.

State What an update needs
Only remote commits are new A fast-forward may be possible
Only local commits are new The remote may already be included
Both sides have their own commits A deliberate integration choice
Uncommitted local files exist Understand their state and purpose first

Check the working tree first

For my website checkout, the read-only check is:

git -C /srv/www/dennishilk.github.io status

This path belongs to my server; adapt it to your checkout. A clean working tree is a useful prerequisite. First decide what uncommitted changes mean: commit them deliberately or preserve them separately. Automatically staging everything can include unrelated or sensitive files.

Then retrieve remote information:

git -C /srv/www/dennishilk.github.io fetch origin main

fetch updates known remote data without integrating it into the current working tree. Check that origin identifies the intended repository. An outdated origin/main can make a comparison misleading.

Compare local and remote history

List commits unique to either side:

git -C /srv/www/dennishilk.github.io log --oneline --left-right -15 HEAD...origin/main

My recorded case contained these two entries:

< 843d8827 world-observer: publish dashboard 2026-10-06
> 3fa0277a Restore homepage styling and unify the site language toggle

< identified the local HEAD side and > the origin/main side. These hashes and titles describe the observed 6 October case, rather than expected output on every server. The objective was clear: retain the dashboard change and add the website update.

Inspect the actual changes before selecting an integration method when needed. Commit titles alone do not explain every file or effect.

Choose between merge and rebase

A merge connects histories while preserving existing commit identities. For genuinely diverged histories, it normally adds a merge commit. This suits work where the original branching history should remain visible.

A rebase reapplies local commits onto the selected new base. The resulting commits receive new identities. In the server case, the dashboard change followed the website update afterwards.

Choice Typical purpose
Merge Preserve history already shared with others
Rebase Place your unshared local commits on a new base
--ff-only Allow only the simple fast-forward path

Do not casually rebase published commits: other computers may already build on them. The server approach suited that local commit; it does not imply that every diverged shared history should be rewritten.

Preserve a local reference and rebase

With a clean status, you can create a local reference before integration. Choose an unused name:

git -C /srv/www/dennishilk.github.io branch backup-vor-update-20261008

This preserves the current commit as a comparison point. It does not preserve uncommitted files or provide an independent data backup.

The actual server integration used:

git -C /srv/www/dennishilk.github.io rebase origin/main

If the changes fit together, Git completes successfully. Then check git status, the relevant website behaviour and the history. Successful Git integration does not establish that every application feature was tested.

Resolve conflicts or abort deliberately

If Git stops, git status identifies conflicted files. Read both changes and decide on the intended final result. For HTML, resolving a conflict involves preserving navigation, language links and structure as well as removing markers.

Stage each deliberately resolved file individually. PATH/TO/FILE is a placeholder:

git -C /srv/www/dennishilk.github.io add PATH/TO/FILE

Continue the running rebase:

git -C /srv/www/dennishilk.github.io rebase --continue

To return to the beginning of that ongoing rebase instead:

git -C /srv/www/dennishilk.github.io rebase --abort

--abort applies to an unfinished rebase. It is not a universal undo command after every completed update. --skip omits a change; do not use it merely to dismiss a conflict.

Understand regular server updates and their limits

If the server intentionally creates its own unshared dashboard commits, an explicitly selected pull with rebase is understandable:

git -C /srv/www/dennishilk.github.io pull --rebase origin main

This can still stop at conflicts or local changes. It is not a reason to use reset --hard, force-push or delete files wholesale. Inspect the update, retain useful local work and test the result.

References

The server example is from 6 October 2026; references were checked on 8 October 2026. Run commands only in the checkout you have inspected.