I like starting a git repository separately, once locally and once remotely. This has given me some headaches especially when git doesn’t kindly lay out the rest of the process for me. I decided to write this note once and for all so I don’t repeat the same mistake!

When I create a git repository locally by git init and do something like git add ., I am creating a history with this repository.

Then if I go create a remote repository and do something extra like adding a .gitignore file, I am creating a separate history with the corresponding remote repository.

These two histories have **no common ancestor`, so Git refuses to merge them automatically.

Remote:  [initial commit: .gitignore]
                ↑
          (no connection)
                ↓
Local:   [add all: your files]

The safest approach to merge them is with --allow-unrelated-histories as in

git pull origin master --allow-unrelated-histories

This tells Git “I know these histories are unrelated. Merge them anyway.” Git will create a merge commit combinding both. If there is a conflict on .gitignore because you also have one locally, then just resolve it and commit. Then push by

git push -u origin master

If I do just git pull then git doesn’t know my strategy for reconciling divergent branches.

  • merge (--no-rebase) creates a merge commit joining the two histories
  • rebase replays my local commits on top of the remote commit
  • fast-forward only fails if histories have diverged

Let’s say this is the shared history before anyone diverged:

A --- B (common starting point, both local and remote agree here)

scenario 1: Only the remote has new work (I have nothing new locally)**

Remote: A --- B --- C --- D
Local:  A --- B

All three strategies suceed here, and they all produce the same result. My local just moves forward to D. This is called a fast-forward: no merging needed, just sliding my pointer ahead.

Scenario 2: Both sides have new work (diverged)

Remote: A --- B --- C
Local:  A --- B --- X --- Y
  1. The merge (--no-rebase) strategy creates a new merge commit M that ties the two histories together:

     A --- B --- C ----------- M
                 \           /
                 X --- Y ---
    

    History is preserved exactly as it happened. The downside is it adds a merge commit that can clutter the log.

  2. The rebase strategy takes my local commits (X, Y) and replays them on top of the remote’s tip (C), rewriting them as new commits (X’, Y’):

     A --- B --- C --- X' --- Y'
    

    History looks linear and clean, as if I had started my work after C. The downside: it rewrites commit hashes, which causes problems if others are already working from X and Y.

  3. The fast-foward only strategy refuses to do anything because the histories have diverged. It only works in Scenario 1 where no rewriting or merging is needed. I get the fatal: Not possible to fast-foward error.

Which strategy to use?

Situation Recommendation
Solo project Either works; rebase keeps a cleaner log
Team project, unshared branch Rebase
Team project, shared branch Merge (never rewrite shared history)
Unrelated histories (my case) Merge with --allow-unrelated-histories