I always do a git pull --rebase even if I do not have a single pending commit.
I just did a pull.
Suddenly, when I run git status, I am seeing that my local master is 11 commits ahead of the remote master.
I dont know where they came from and want to get rid of them.
What do I do?
It's clear that you're a victim of what is usually called an "upstream rebase". You can jump right to the solution below but this background is pretty important.
This why I hate
git pull. It's not
git pull's fault, really, but because
git pull is a convenience command that simply runs
git fetch followed by a second command, it winds up hiding the two underlying Git commands from new Git users. The fact that there are two different second commands, both of which can mess things up in different ways, is spectacularly unhelpful.
Fortunately, the first part—the
git fetch step—almost always works.1 It's the second step where, if all goes well, everyone says "oh that was easy" and thinks that
git pull is great and then when it explodes, as it always does eventually, they're in trouble, because they have never had to deal with the second part failing. And now it's an emergency and they have to spend a bunch of hours learning a bunch of complicated stuff: the way to recover from failures, and how merge and rebase interact with the
git fetch step.
Anyway, this time you are the one stuck with the messy situation, so let's just press on with it. The second half of what
git pull does is either
git merge or
git rebase. Exactly which command it does when is beyond the scope of this answer, except that we can say for sure that if you add
--rebase, it always uses
git rebase. So you only have one complicated Git command to learn in a hurry. (Yay? :-) )
Hence, as Tim Biegeleisen answered, these new mystery commits came from using
git rebase. So it's time now to learn all2 about rebase, and how it interacts with
1There are still a few ways it can go wrong, but usually the one that actually happens is "the network is down and thus we can't get anything from
origin" which is really obvious and makes everything stop right at the beginning, and you just try again once the network is fixed.
2Well, let's not go that far. :-)
Rebase can be complicated but we can sum it all up very simply:
git rebase copies commits.
That's it. Rebase copies commits. That's actually not bad at all, is it? Well, it's not bad when they are your commits, but you just had it copy someone else's commits. The tricky part here is defining precisely which commits get copied, when, and how. This is where
git fetch comes into the picture again.
Tim's drawing here covers the more normal case, when you have made some commits. I'm going to make my own drawing though. Let's say there are a bunch of commits, ending with a series
F--G--H, when you start out. That is, your
origin/master both point to commit
H, which points back to
G, which points back to
F, and so on. You got all these when you did your initial
git clone or your last
git pull --rebase or whatever: it doesn't really matter how you got them, just that you do have them.
...--F--G--H <-- master, origin/master
Now, normally, you might add your own commits, say
I--J <-- master / ...--F--G--H <-- origin/master
Meanwhile someone else, using their own Git, adds their own different commits. You don't have them now. Then they publish those commits, so now
origin has them too. You still don't! But now you run
git fetch and now you get them, and here's what happens in your repository. Let's say they made just one commit, which we'll label
I--J <-- master / ...--F--G--H \ K <-- origin/master
Note how the label,
origin/master, has "moved forward" from
K. Meanwhile your own
master is already moved forward from
J: yours points to your commit
J, which points back to your commit
I, which points back to
This is where you normally bring
git rebase in. You ask it to copy your commits,
J, to new commits that are "just as good" but are based on commit
I--J <-- master / ...--F--G--H I'-J' \ / K <-- origin/master
Let's say the copy goes well, with no problematic merge conflicts and such. You now have new commits that are just like your originals, except for their new "base" commit
K. That's a rebase!
All your Git has to do now is peel your
master label off the old
J and make it point to the new copied
I--J [abandoned] / ...--F--G--H I'-J' <-- master \ / K <-- origin/master
and now that the old commits are officially abandoned, we can straighten the whole picture out:
I'-J' <-- master / ...--F--G--H--K <-- origin/master
There are multiple ways for
git rebase to go awry. Let's ignore some of them and just concentrate on the one that bit you.
Let's draw out more of the stuff that comes before
F--G--H this time. Also, you didn't have your own commits (you said, and I believe you).
A--B--C--D--E--F--G--H <-- master, origin/master
Now, someone else did something upstream to "rebase", i.e., to copy some commits. I don't know exactly what they did, but let's say they discovered that commit
D was Defective, and perhaps even deleted it entirely. They now have:
D--E--F--G--H [abandoned] / A--B--C \ E'-F'-G'-H' <-- master
Now you run your
git fetch. What this does is to pick up their
master and forcibly adjust your
origin/master to match theirs. So you still have
A-...-H as usual, with your
master pointing to that, but now you have
origin/master pointing to
D--E--F--G--H <-- master / A--B--C \ E'-F'-G'-H' <-- origin/master
git fetch step. Now your
git pull runs
git rebase. What rebase does, or tries to do, is to copy commits. Which commits should it copy? The answer here can get complicated, but to simplify things a lot, it will think, at this point, that
D--E--F--G--H are your commits. Those are the obvious copy candidates: they're the commits on your master, that are not on
It does matter that
E'-F'-G'-H' are copies themselves. But let's just ignore that. Whether your Git detects them as copies or not, your Git is at least going to restore commit
D, thinking it's your work, rather than something that got stripped out. In any case, because you're seeing 11 commits, your Git has somehow restored or resurrected or copied 11 commits. Let's just draw all of
H since our solution will be the same either way.
git rebase copies "your" commits (not really yours, it just thinks they're yours) and moves your
master label, and you now have this:
D--E--F--G--H [abandoned] / A--B--C D'-E"-F"-G"-H" <-- master \ / E'-F'-G'-H' origin/master
Suddenly you're five commits "ahead of"
In this case, since you're sure you really have no commits of your own, what you need to do is tell your Git to abandon all these new copies entirely.
The command that does all this for you is
git reset --hard. The thing about
git reset --hard is that it does let you throw away a bunch of your own work, so you must be careful about when you use it.
In this particular case, though, you promised you had no commits of your own here. Remember, it's just this particular case: no commits of your own, no uncommitted work in the work-tree, etc. So it's safe to wipe things out.
So, what you want to do in this case is to tell your Git to move your
master to point to the same commit as
origin/master, abandoning all the copies that your
git rebase made:
D--E--F--G--H [abandoned] / A--B--C D'-E"-F"-G"-H" [abandoned] \ / E'-F'-G'-H' <-- master, origin/master
If we now stop drawing in the abandoned commits, you'll see that your graph is now just:
A--B--C--E'-F'-G'-H' <-- master, origin/master
which is what you want: you're no longer "ahead of"
Suppose, in all that mess, you really did have some commits to keep. In this case, there are a bunch of ways to fix this, but probably the easiest is to use
git rebase -i (interactive rebase: copy selected commits). You can
git rebase -i to get the 11 commits that Git thinks are yours into a set of instructions. Then you delete, from the instruction sheet, all but the ones that really are yours, and your Git copies those yet again, and abandons the un-copied ones.
Since you promised there were no such commits, we were able to use the simpler
git reset --hard. (Depending on your Git version, we might have to use
reset. All versions of Git refuse to let you delete everything from the instruction sheet. Newer versions let you put in a "no-op" instruction so that there's at least one instruction left, even if there are no copy instructions.)