1

The goal

I want to modify a recent commit, using rebase. The magic command is git rebase -i

Let's say you're trying to delete the commit-in-question

  • First, find out how far back that commit is (approximately). Then do:
    • git rebase -i HEAD~10


-Source:
Greg Hewgill's answer to a less complicated git question


The problem

That works wonderfully, unless you've recently done any --no-ff merges

If you happen to follow git flow, you do --no-ff merges all the time

  • Check the "Sources" section below for examples on the how & why of rebase -i blowing up --no-ff merges
  • For now, just trust me (or try it yourself): It aint pretty


The actual question

If we look at this page we see a --preserve-merges (or simply -p) option that we can try replacing -i with

The problem is, if we do that, we're no longer given that nice -i pop-up from before
-> The one with choices for "edit this commit, sqaush that one", etc.
--> And so, we can't meet our original goal: modify/delete some recent commit using rebase :(

So, what do we do?




Sources

Problem section:

  • First example of rebase murdering --no-ff commits
  • Second example
    • His quote: "The TL;DR version is this: When rebasing, always use the -p flag"
Community
  • 1
  • 1
Bukov
  • 650
  • 8
  • 19

2 Answers2

1

-p and -i are not mutually exclusive - you can use both at the same time. However be very very careful when you do this - changing the order of commits is a bad idea. You should also not try to remove merge commits this way; it's very easy to get things into an improper state.

git rebase -p -i HEAD~10
Amber
  • 507,862
  • 82
  • 626
  • 550
  • I can't believe I didn't think of that. I believe I was scared to try because of [this page](https://www.kernel.org/pub/software/scm/git/docs/git-rebase.html) saying: "combining [-p] with the --interactive option explicitly is generally not a good idea unless you know what you are doing". It looks like you've covered the "know what you're doing" part for me tho :) So I can use both, just **no reordering** and **no deleting merge commit rows**, and I'm safe? – Bukov Apr 21 '13 at 03:14
  • I'm not going to blanket say that you're safe, but if you're only editing commits, you'll probably be okay. – Amber Apr 21 '13 at 03:17
  • Hrm, gotcha. And the "generally not a good idea" thing is a pretty scary warning. Are there **any** other alternatives to solve this problem, though? Or are we stuck with "use `-p` and `-i` together, risky though that may be"? – Bukov Apr 21 '13 at 04:32
  • In general, rebasing merges is going to be risky; that's just a consequence of how Git works. Rebase mostly tries to deal with linear history, and (non-fast-forward) merge mostly deals with non-linear history, hence why there are the rough edges when you try to combine the two. You might want to consider how important it is to you to edit the existing commit versus just creating a new commit with the fix. – Amber Apr 21 '13 at 16:41
  • 1
    Also note that "risky" here is relative - as long as you have the reflog enabled, you can always essentially hit "undo" on a rebase. So you can try it out and see if it works out properly, and if not, just use the reflog to find your old SHA and reset back to it. – Amber Apr 21 '13 at 16:44
  • Fantastic advice, thanks! I'm going to check out reflog in a minute. The points on "rebase in general being somewhat risky" are well taken. Like you said, "just do it" with `-p -i` it sounds like, and keep our finger over the shiny git undo button you've just told us about, just in case of funkyness. Great stuff! – Bukov Apr 21 '13 at 17:12
  • On "you might want to just create a new commit/new branch with the corrections there": That's certainly an option to consider. For example. I thought of going back to the earliest "good" commit, & starting a new branch called "theGoodBranch". Then I could cherry-pick the commits from old "theBadBranch" one at a time, and SKIP the commit I'd wanted to delete. The problem? I've heard bad things about cherry-pick. [This page](http://dan.bravender.us/2011/10/20/Why_cherry-picking_should_not_be_part_of_a_normal_git_workflow.html) for example. I don't know an alternative to cherry-pick though – Bukov Apr 21 '13 at 17:51
  • @Bukov cherry-picking is fine *if* you discard whatever branch you were cherry-picking *from* once you're done (this is basically what `rebase` does - it cherry picks each of the commits in order from the old branch, and then throws the old branch away, replacing it with the new version). The problems with cherry picks arise if you don't throw the old branch away, so you have versions of the change in both your old and new branches that have different SHAs. – Amber Apr 22 '13 at 03:51
1

The above using -p and -i together is correct - however I wanted to point out that you dont need to use interactive more to get rid of a commit. You can use the --onto instead to explicitly state where you want your base to be. Assuming you want to get rid of HEAD~10,...

git rebase --onto HEAD~11 HEAD~9 HEAD

This says, take any commits that are in HEAD, but **are not* in HEAD~9, and apply them to the end of HEAD~11. That would mean it skips HEAD~10. The solution above works just fine, but sometimes, for getting rid of larger swaths of history, you may want to use --onto. Keep in mind that as is the case with -p, you can also use interactive mode with --onto.

With regard to non-fast-forward merges and rebasing, take a look at this answer I gave to another question. It mostly explains the use of --onto, but if you read through, you'll find an explanation regarding --no-ff merges and rebasing.

Community
  • 1
  • 1
eddiemoya
  • 6,713
  • 1
  • 24
  • 34