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