1

I have created a separate branch from master on a git repository. During that time, I made a few dozen commits on my branch, and something like a hundred commits were made to master. Now I want to merge my branch back into master. After first merging master into my branch, git says my branch is 2200 commits ahead of master, which must be wrong somehow. There are about 3000 commits in total in the repository.

What could cause something like this to happen?

Alex Fischer
  • 545
  • 3
  • 11

1 Answers1

1

It's hard to be sure without access to the actual commits and repositories, but this is the sort of thing that happens if your upstream—the people in control of the repository from which you git cloned your own repository—have done a massive history rewrite.

The heart of the issue here is that "ahead" and "behind" don't mean what people want to think they mean at first, because people like to think of history as linear: thing X happened, then thing Y happened later, then thing Z. History in Git is not linear: thing X happened while thing Y was also happening. Thing Z tied X and Y together:

...--X--Y--Z   <-- present-day

is wrong and:

...--X
      \
       Z   <-- present-day
      /
...--Y

is right. Neither X nor Y are "ahead of" or "behind" each other, even though both are quite clearly "behind" Z.

(Don't take this particular analogy too far: it's just meant as an illustration. Starting from Z and working backwards, Git might show you Y first, then X, when Git shows you one commit at a time—but that doesn't mean there's some strong ordering between X and Y. You might see Z then X then Y instead, just as easily.)


With the above in mind, suppose that you clone a repository that has some string of commits in it:

...--F--G--H   <-- master

Because your clone copies the actual commits, you get exactly-identical commits in your own (separate) repository:

...--F--G--H   <-- master, origin/master

The origin/master is your Git's memory of their Git's master: their Git's master pointed to commit H.

You now make your own commits, in your own repository, on your own branch you call feature:

...--F--G--H   <-- master, origin/master
            \
             I--J   <-- feature (HEAD)

Meanwhile, for some reason, the people in control of the repository you cloned decide they hate commits G and H and they replace them with improved commits G' and H'. You now run git fetch origin to update your repository with their new commits, giving you this:

       G'-H'  <-- origin/master
      /
...--F--G--H   <-- master
            \
             I--J   <-- feature

Your branch is now four commits "ahead of" origin/master, and also two commits "behind" origin/master. The four that you are ahead of them are G, H, I, and J—which as far as your Git is concerned, you must have written yourself, because origin/master goes from H' back to G' back to F, skipping over G and H.

(The two that you are "behind" are of course G' and H'.)

In this particular example you wind up just two extra ahead. If they did a massive copy-and-substitute operation, using git filter-branch or the BFG or some such, though, you'll be hundreds or thousands of commits "ahead" of the ones they threw away, which your Git now thinks are your own work. You fix this by, as Git puts it, "recovering from an upstream rebase".

torek
  • 448,244
  • 59
  • 642
  • 775