On Mon, Feb 19, 2018 at 11:35:25AM -0800, Hilco Wijbenga wrote:

> git rebase --onto base-branch HEAD~7
> commit A --> conflicts
> ... lots of work ...
> commit B --> conflicts
> ... lots of work ...
> commit C (Git handles conflicts)
> commit D (no conflict)
> commit E --> conflicts
> ... er, that should have been fixed in commit C
> 
> How do I keep all the work I did for commits A and B? I get the
> impression that rerere does not help here because I did not finish the
> rebase succesfully (and that makes perfect sense, of course). Is there
> a way at this point in the rebase to "go back" to commit C (so without
> "git rebase --abort")?

rerere should help, since the resolutions are stored when you run "git
commit". Of course, sometimes there are changes outside of the
conflicted regions that are necessary.

One thing you can do is to repeat the rebase, but simply pick the
resolved state at each step. E.g.:

  # remember the failed attempt; you could also store the sha1 in an
  # environment variable, or even store individual commits.
  git tag failed

  # now abort and retry the rebase
  git rebase --abort
  git rebase -i

  # we should have stopped on commit A with conflicts. Now we can say
  # "make the tree just like the other time we saw A".
  git checkout failed~4 -- .

  # or if you want to review the changes, try this:
  git checkout -p failed~4

And so on. You visit each commit as before, but you can always grab your
previous work (or parts of it, with pathspec limiting or "-p") instead
of repeating the work.

I often do something like this for complicated merges (e.g., of two
long-running branches). I try the merge first, only to find that some
preparatory steps would make it a lot easier. So I commit the merged
result (even sometimes half-finished), "reset --hard" back to the
original, do the early steps, and then re-merge. And then I "checkout
-p" to pick my work out of the earlier failed attempt.

> (Surely, it's not as simple as doing a "git reset --hard
> sha-of-commit-C" is it?)

Not quite that simple, but that's another approach. If you "git reset
--hard" you'll lose D and E, since the rebase has already applied them.
But you could then replay them manually, like this:

  # go back to C and fix it
  git reset --hard C
  fix fix fix
  git commit --amend -m 'fixed C'

  # now replay the other commits on top
  git cherry-pick D
  git cherry-pick E

  # and then continue on with any other rebased patches
  git rebase --continue

-Peff

Reply via email to