On Sun, Nov 21, 2010 at 10:51:51AM -0800, Yang Zhang wrote: > >> > Âgit rebase --onto temp F'^ branch_name > >> [...] > >> > At that point your original branch should be in the state you want. You > >> > can delete the temp branch with "git branch -D temp". > >> > >> I'm sorry that I can't understand "your original branch should be in > >> the state you want" ? > >> You only create a temp branch, and rebase some commits on it, right ?? > >> What does that related to original branch ?? > > > > The three-argument form of rebase above will switch to branch_name (your > > original branch), consider F'^ as the upstream, and rebase > > F'^..branch_name on top of the commits in "temp". > > > > -Peff > > > > Actually, I missed this detail earlier, and now like Gavin I'm > confused. *temp* is "in the state that you want," not original_branch, > right? temp shouldn't be deleted just yet; master should be updated to > point to this.... No, the first thing rebase will do is switch back to your original_branch, and then it will rebase the extra commits (the rebased versions of things that happened after your initial pull), on top of the new partial history in temp. Yeah, the arguments to rebase are weird. In a simpler world you would do: # assume we're on master, the broken branch; mark the point with a tag git tag broken # go back to just before the broken rewritten commits git reset --hard C' # now re-do the merge git pull origin master # and now grab the other commits from our broken state git cherry-pick F'^..broken except that cherry-pick doesn't actually walk the commit range as you want it to. I think you can do: git cherry-pick F' G' H' these days, so that is another option. Anyway, just for fun I put together a script which graphically shows your situation at each step. You can run it all at once, but it is probably more instructive to cut and paste into a terminal, reading all of the comments. -Peff -- >8 -- #!/bin/sh # clean up any previous invocations rm -rf parent child # short helper function for making our commits commit() { echo $1 >$1 && git add $1 && git commit -m $1 && git tag $1 } # short helper to show state show() { # or gitk "$@" if you prefer git log --oneline --graph --decorate "$@" } # make a parent and child with some shared base mkdir parent && (cd parent && git init && commit base) git clone parent child # now child and parent diverge. child has a-b-c, # parent has d-e (cd child && commit A && commit B && commit C) && (cd parent && commit D && commit E) && # now let's recreate the problem situation. Everything # now happens in the child. cd child # First we pull the parent's commits into the child git pull origin master # And build on top of it commit F && commit G && commit H # And then we "rebase -i", rewriting B GIT_EDITOR='perl -pi -e "s/pick (.* B)/edit \$1/"' git rebase -i base echo changes >>B && git commit --amend -a -m B git rebase --continue # Now we have the broken state, because we rewrote parent's commits during our # rebase. We also failed to preserve merges, so the new history appears linear. # You can see the repeated commits easily by looking at the history graph of # our new state versus our old. # # Let's also go ahead and tag the original history and each of the new commits # so we can recognize and refer to them. Here H-new corresponds to H' in my # other explanation, and so on. git branch original-history master@{1} git tag H-new HEAD git tag G-new HEAD~1 git tag F-new HEAD~2 git tag E-new HEAD~3 git tag D-new HEAD~4 git tag C-new HEAD~5 git tag B-new HEAD~6 show --all # So now let's look at the solution. First we make a temporary branch from the # rewritten commit just prior to the ones from upstream (in this case, C'). git checkout -b temp C-new show temp # Now re-pull from upstream, recreating the merge on top of your rewritten # commits. git pull origin master show temp # And now rebase the rewritten versions of all of the commits that came after # the merge. We know F-new is the first such rewritten commit, so its parent # (F-new^) becomes the upstream. We are rebasing onto the state we have in # temp, and we are rebasing the branch master (and the end result will go on # master). git rebase --onto temp F-new^ master show master -- 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