Rebase panic

Posted: 17 November, 2018 Category: code Tagged: git

Git Rebase to fix old/historical commits

Had to do this a few months ago for the totally vanity reason of hiding an exposed email address embedded in a bunch of commits which for some reason google's search engine was now picking up. Grrr...

Anyhow... in the process I learned a bit about how rebasing worked, and wrote these notes for my future self and anyone else it might help!

Remember that the following steps basically rewrite history! Therefore always begin by creating a new branch for any rebasing activities. git checkout -b <branchname>. OK? Also, If anything goes pear-shaped and you need to restart, git rebase -–abort is your best friend. Ready? Here goes:

Use Case 1 – Change a historical commit that is NOT the root commit

  1. git rebase –i <parent-sha>

    ...where the parent-sha is the commit prior to the commit you want to modify. The -i means interactive. This command basically opens up your default editor (eg vi/vim)... and you change the 'pick' string to 'edit' for the commits that you wish to alter, then save and quit (eg for vi editor, :wq)).

  2. Interactively fix any conflicts that arise. This usually involves:

    • the occasional git add ... to stage a file that was added historically, or
    • editing a file to fix merge conflicts (those pesky '>>>>>>' and '<<<<<' blocks of text).
  3. After everything is cleaned up, do git rebase --continue. Tadaaa!!! You're done.

    Remember you can always do git rebase -–abort to just back the hell out of everything and try again!

Use Case 2 – Change everything from the root commit onwards

In this case, you provide both:

  • the root commit sha, and
  • the sha for the tip of your new git tree... so unless you want to mysteriously cull several commits, the last arg (the "tip" sha) should be the sha of the very latest commit.

Steps

  1. git rebase –i --root <root-sha> <latest-sha>
  2. Follow the rest of the steps in Use Case 1 above. That's it!

Use Case 3 – Surgically modify the root commit only

I found this link very helpful. In this case, you basically:

  • modify the root commit, (you can find the root sha# with git reflog or visually browse to your first ever commit in github/gitlab whatever)... and then
  • stack all the subsequent changes that happened thereafter onto the top of your new root.

Steps

  1. git checkout –b <brch>

  2. git checkout <root-sha>

  3. Make whatever edits you like to the commit, e.g.: git commit --amend --author "blahblah"

  4. Then, based on answers I found in StackOverflow, this is what worked for me: git rebase --onto HEAD HEAD master

    WARNING: This obviously messes with your MASTER branch... hope you noticed.

    UPDATE: Actually, it appears you can tack on whatever branch has modifications you want to apply, not just HEAD. But if you run it as above, it actually modifies master and you will find yourself back in the master branch!! In my case, that's what I wanted. Magic!!

  5. Next, push this new source tree back up to your remote: git push origin master --force

    Explanation: If you've just rebased right from the root, then natch all the commit SHAs will now be different and github will deem your remote master irreconcilable with your local, recently-messed-with master... hence the --force switch.

A brute force swiss-army-knife rule

Side note on merging branches with unrelated histories: When tree of SHAs differ, github will not let you do a PR and merge because now master and (for example) the rebased branch have entirely different histories. I found another answer on SO that deals with I guess the general case of all these scenarios. Haven't had to try this yet (tho, give it time! lol), but the swiss-army-knife, "just do what I tell you to do" command seems to be:

git merge –s ours master –allow-unrelated-histories

This forces a merge even though the 2 branches now have unrelated histories, using the "ours" strategy (-s) in which things in our current branch trumps whatever's in the other branch.)


Well that's all I have on this topic, folks! I hope it helps someone out there! :o)