6

The following series of git commands is leading to repos to diverge. What am I doing wrong?

  1. Fork project from GitLab

    call the parent project 'upstream'

  2. Clone repo from forked project
  3. Make edits locally in branch master
  4. Commit local edits, push to forked repo
  5. upstream repo has commits from other developers
  6. grab latest commits from upstream repo

    git pull --rebase upstream master

  7. incorporate the latest commits from upstream that are now local into forked repo

    git push origin master

  8. git says my branch has diverged by x commits and y commits, respectively. Asks me to do a git pull which ultimately clutters the history.

What is the right way to do this?

BigBrownBear00
  • 1,378
  • 2
  • 14
  • 24

1 Answers1

10

Lets work this through.

There are 3 repositories: Your local clone, upstream, your fork (origin to your local clone)

After step 2, they look something like this:

upstream

o---o---o
a   b   c

fork

o---o---o
a   b   c

local

o---o---o
a   b   c

After step 5, the repos look something like this:

upstream

o---o---o---o---o
a   b   c   d   e

fork

o---o---o---o---o---o
a   b   c   f   g   h

local

o---o---o---o---o---o
a   b   c   f   g   h

That is, upstream has new commits d and e, and you've made new commits f, g and h

Now, you do git pull --rebase upstream master

The repositories now look like this:

upstream

o---o---o---o---o
a   b   c   d   e

fork

o---o---o---o---o---o
a   b   c   f   g   h

local

o---o---o---o---o---o---o---o
a   b   c   d   e   f'  g'  h'

Where f and f' are not the same commit - f' is supposed to be equivalent to f, but it has a different parent.

You can see here, that local has a different history now to fork; pushing to it isn't simply a case of adding new commits. Both think a different commit comes after c, and the two branches do not converge; if you added all the commits, you'd end up with this graph:

        ,-----------o---o---o
        |           f   g   h
o---o---o---o---o---o---o---o
a   b   c   d   e   f'  g'  h'

And what would be the current HEAD? h or h'? Neither preserve the history of the other.

You could merge these, but that would be wrong because you have equivalent changes in f and f', g and g' etc.

You could do

git push -f

This would throw away f, g and h from fork and make it look like local (you'd have f', g' and h' still), which is probably fine if no one else has cloned from fork

At step 6, instead of doing the rebase, you could have done

git pull upstream master

Which would have resulted in a merge, so the repos would look like this:

upstream

o---o---o---o---o
a   b   c   d   e

fork

o---o---o---o---o---o
a   b   c   f   g   h

local

        ,---o---o---o---,
        |   f   g   h   |
o---o---o---o---o-------o
a   b   c   d   e       m

Where m is a merge commit. This could then by trivially pushed to fork because it's just adding extra commits.

If you're planning to issue a pull request to upstream, though, maybe better not to merge their changes in, and let them pull and handle the merge.

SpoonMeiser
  • 19,918
  • 8
  • 50
  • 68
  • First off, you should get an award for that explanation. That was fantastic. `git push -f` is what I want b/c no one else will clone the forked repo. And ultimately I want all 3 repos to stay in sync. If I do git push -f, can I then pull/push from upstream without any diverge issues? – BigBrownBear00 Sep 21 '17 at 11:58
  • 1
    Yes. You can push if it's a _fast forwards_ for the repo you're pushing to. That is, you can add the new commits and advance HEAD to the latest one trivially. Repos have diverged if the HEAD of the remote repo is not an ancestor of the HEAD you're pushing. This all makes sense when your mental model of how git works is accurate-ish, but can be hard to explain. – SpoonMeiser Sep 21 '17 at 12:04
  • I'll give it a shot and make sure it works. And then accept the answer accordingly. Thank you again! – BigBrownBear00 Sep 21 '17 at 12:07
  • 2
    `push -f` worked like a charm. exactly what I needed. THANK YOU. – BigBrownBear00 Sep 21 '17 at 13:16
  • This is best answer i found to explain upstream, fork, local development – Huan Jiang Oct 23 '22 at 00:03