3

Lets say I have a branch based on master which ends with merge commit:

--A---C<master]---D---E---F<my-feature]
   \ / 
    B

Adding a commit X between D and E with interactive rebase is simple - I run

git rebase -i master

, set commit D operation to edit, rebase stops after rebasing D. I just create the new commit at that moment and then continue rebase. The branch now looks like

...C<master]---D---X---E'---F'<my_freature].

Now I want to add a commit between C and D. Desired result:

C<master]---X---D'---E'---F'<my_freature]

I tried

git rebase -i master~

where I wanted to set the merge commit C to edit, but interactive rebase somehow ignores the merge commit C and offers me only chain A--B--D--E, so the rebase results in loss of merge commit C.

Is there a simple way prepend a commit to a branch with interactive rebase like this?

Please note that I can figure a bit more complex solution like creating new branch tmp on master, committing X to it then rebase my-feature onto tmp, I'm just curious if there is a simple and straightforward way with interactive rebase.

amik
  • 5,613
  • 3
  • 37
  • 62
  • This is an interesting workflow. I would not have thought to add a new commit in the middle of a rebase operation in the first place. I don't know the answer to your question, but my approach would have been to create commit X after F and then interactively rebasing it between C and D or between D and E, wherever it is desired. – joanis Feb 22 '19 at 14:48
  • For what it's worth, rebasing is not friendly to merges: it frustruates me how you could not rebase A^..F to another branch without losing the fact that there was a merge in that history. I have used cherry-picking and redone merges manually in the past when I wanted to do this. – joanis Feb 22 '19 at 14:49
  • OK, I should have read the manual... `git rebase -h` tells me that the `--preserve-merges` or `-p` option tries to recreate merges instead of ignoring them. Maybe that would solve your problem too? – joanis Feb 22 '19 at 14:52
  • yep, `-p` is the solution. What you suggest in first comment is quite unhandy, you get more quite worse or "weird" merge conflicts when you move a commit over a changing codebase than if you directly checkout old master, insert a new commit then continue interactive rebase on top of it. – amik Feb 22 '19 at 19:39
  • Good point, doing the patch where it's going to live in the end can be a lot simpler and reduce conflicts if you have a lot of commits in your feature branch. – joanis Feb 22 '19 at 19:59

1 Answers1

1

I have just successfully reproduced your scenario and inserted commit X between C and D by adding the -p option (--preserve-merges) to `git rebase:

git rebase -i -p master^

the rest of the workflow is as you describe: tell rebase to edit the merge commit, manually insert the new one and finish with git rebase --continue.

Cool workflow, by the way! I think I'll use it.

Edit: I tested this solution with Git 2.4. If you have a more recent version of Git, @torek recommends using the safer --rebase-merges option instead of --preserve-merges. See the comments below for the explanation.

joanis
  • 10,635
  • 14
  • 30
  • 40
  • 1
    There's a general bit of advice about using `-i` and `--preserve-merges` (or `-p`), which is: don't. :-) The new `--rebase-merges` mode can deal with this correctly, but `-p` (ab)uses the interactive machinery to do *implied* merging and rearranging the sequence of pick commands can cause the interactive code to do the wrong merge. Obviously if it worked for your particular test case, that one didn't trigger the problem, but if you use `--rebase-merges` you get an interactive session with labels, and the labels build the new topology, so you can make sure it works in all cases. – torek Feb 22 '19 at 15:51
  • @torek thanks for the info. My Git must be too old, I don't see option `--rebase-merges`. For the OP's question, interactive rebasing is used to insert a commit, and no reordering is used. If I understand your comment correctly, this means my solution should be safe for this specific use case. I'll edit my answer to suggest using `--rebase-merges` instead for more recent versions of Git. – joanis Feb 22 '19 at 15:56
  • Thanks, this is what I looked for. I think the `-p` option is safe in this case, because I actually do not touch the merge commit or anything before it, I just needed an alternative way of interactive rebase that is able to stop right after checking out the base commit. – amik Feb 22 '19 at 19:37