Re: How to fix “Your branch and 'origin/master' have diverged” after editing a commit that came before a pull?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Nov 19, 2010 at 04:36:46PM -0800, Yang Zhang wrote:

> In the following scenario:
> 
> 1. Make commits A, B, C
> 2. Pull, getting commits D, E
> 3. Make more commits F, G, H, ...
> 4. Realize that you need to tweak B
> 5. Tweak B using git rebase -i and git commit --amend
> 
> Now git status says:
> 
>   Your branch and 'origin/master' have diverged.
> 
> How should I fix this? Thanks.

When you change a commit, you also change every commit after it (since
each points to its predecessor by a parent pointer). So you create an
alternate history. IOW, you had this:

  A--B--C

and pulled to get this:

  A--B--C--D--E

or maybe this:

  A--B--C--Merge
          /
      D--E

depending on how those other commits relate to what you have. Then you
made more commits, like (let's look at the non-merge case):

  A--B--C--D--E--F--G--H

Then you tweaked B. The rebase replayed every commit after that, but
each one is not exactly the same as the other. So now you have:

    B--C--D--E--F--G--H
   /
  A--B'--C'--D'--E'--F'--G'--H'

where the top branch of history is what you used to have (and is
accessible via the reflog as branch@{1}). But your actual branch is at
H'. So if you "git pull" again, as you tried, it will try to merge D and
E from upstream. So:

                            D--E
                                \
  A--B'--C'--D'--E'--F'--G'--H'--Merge

which is definitely not what you want. The problem is that you have
rewritten upstream's commits, because you rebased across a set of
commits that contained things you had pulled.

To fix it, what you want to do is recreate the history on top of B' as
it happened on top of B. So first you go back to C', the last commit
just before the commits from upstream that were rewritten. (you will
have pick its sha1 out of the log):

  git checkout -b temp B'

You should then have:

  A--B'--C'

on a temporary branch. Now re-pull from upstream (you could also
manually rebase those commits, but this is probably simpler, especially
if there actually was a merge):

  git pull remote_name branch_name

Note that you need to explicitly mention where you pulled from, since
the temp branch will not be configured to pull in the same way (if you
don't have any special config set up, it should be "git pull origin
master").

And now you have:

  A--B'--C'--D--E

at which point we can rebase the last bit of your branch on top:

  git rebase --onto temp F'^ branch_name

where "branch_name" is the name of the branch where this mess happened
(presumably "master"), and F' is the first commit that is worth saving
after you pulled from upstream. And that gives you:

  A--B'--C'--D--E--F''--G''--H''

where F'' corresponds to the original F, but actually has a different
commit id (because of different parentage) than F or F'.

At that point your original branch should be in the state you want. You
can delete the temp branch with "git branch -D temp".

So that's the most general way to do it. It's a little convoluted
because of the way rebase works (you can't say "rebase those commits on
top of me", but rather have to say "rebase me on top of these commits",
which leads us to use the temporary branch).

Depending on the relationship of F, G, and H to D and E, it could be
much simpler to just re-order history. So from your your broken state,
which remember is:

  A--B'--C'--D'--E'--F'--G'--H'

do a "git rebase -i", and just _delete_ all of the commits you pulled
from upstream (D and E in this case). Now you have:

  A--B'--C'--F''--G''--H''

and now repeat your pull to get:

  A--B'--C'--F''--G''--H''--D--E

Which is very simple and straightforward. But it relies on it being
acceptable for F, G, and H to come before D and E in the history.


Whew, that turned out long. Hopefully it helps, and did not just confuse
you more. :)

-Peff
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]