1

I did an interactive rebase with more commits than I needed to change. I was surprised that the shas of the unnessisary changes were updated. Unfortunately I only realised this happened after I force pushed my updates.

What I did

Starting point

X - Y \
A - B - C  *master (C is a merge commit)
         \
          - D - E *feature-branch
  • ran git rebase -i head~3
  • squashed D and E (we'll call this D1)
  • changed the commit message of the new D1 commit
  • Left A, B, and C as pick and didn't make any changes

My expectation was that everything would look like this:

X - Y \
A - B - C  *master
         \
          - D1 *feature-branch
  • force pushed my branch

When I went to my PR, things actually looked like this:

X - Y \
A - B - C  *master
         \
          - A1 - B1 - C1 - D1 *feature-branch

Where A1, B1, and C1 had the same commit messages and changes as A, B, and C, but with different shas.

Questions

  • How can I remove A1, B1, and C1 from my PR without impacting master's A, B, and C?
  • What's going on with rebase -i? Why did including A, B, and C in my rebase command make any changes since I just left them as pick?

2 Answers 2

4

The easiest way if you just want to delete A1/B1/C1 is to do a git rebase -i C. Mark A1 as 'reword', and B1 through D1 as 'fixup'. Edit the commit message for A1 to be what you want as the final message.

Now, as to what went wrong: C is a merge commit.

That means your history graph probably actually looked like this:

   A - B - C  *master
          / \
...-X-Y-Z    - D - E *feature-branch

When you said HEAD~5, that took the first parent of HEAD five times. Let's say the first parent of C is Z instead of B. That means you're rebasing onto commit X, and one of the commits you're planting there is A. The new A gets a new commit hash because its ancestry (and possibly its content) changed.

You might not have noticed Y and Z showing up in the rebase-interactive editor window and just left them as pick.

Basically, the rebase takes your nonlinear history and squishes it into being a line. I can't say I recommend using a rebase across a merge commit.

Sign up to request clarification or add additional context in comments.

3 Comments

Ah, thanks for the reflog reminder - I updated my question to include the full history from my reflog. Perhaps that makes it clearer what happened?
@LucyBain Thank you for mentioning that C is a merge. That is the source of your issue. Rebase linearly replays commits; if you include a merge commit in the scope of the rebase, the results are not what you might expect. That's why my answer included "with history that looks like your graph".
Ok, thanks for the explanation! I'm sorry I didn't mention it in the original question then, I didn't think it would make such a difference :(
-1

If you run git revert for A1 - B1 - C1 , your new branch will effectively be the one that you desire. And this operation is safer

2 Comments

I believe this will make new commits on my branch for the three reverts (A1', B1', and C1') that would then be in my PR to merge back, effectively undoing the code in A, B, and C on master.
Yes, that is correct. I will suggest to do it this way as it does not break anything for others who pull your branch. Rebasing to remove pushed changes is something I would be against as it also spoils history of other users.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.