An Idiosyncratic Blog

🧙‍♂️ Git sorcery

Published on
·
3 minutes read

It was a fine Friday afternoon. I was working on a feature ticket, clacking away on my keyboard. The feature was pretty simple to implement. I had fleshed out the implementation on a whiteboard, and I was done coding in under an hour.

I complete the feature and then test it. Everything works, great! Let's commit and push.

git commit -m "feat(its-alive): the monster is stirring"
git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 12 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 305 bytes | 305.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
remote: error: GH006: Protected branch update failed for refs/heads/main.
remote: error: 3 of 3 required status checks are expected.

Uh-oh! I forgot to switch to a feature branch. All my commits are now on main.

Well, thankfully Git is forgiving.

Moving to an existing branch

If I had an existing local branch, all I need to do is:

  • checkout the branch
git checkout feature-frankenstein
  • merge with main
git merge main
  • remove the commits from main
git checkout main
git branch -f main HEAD~3 # make master point to some older commit
  • continue the work on existing branch
git checkout feature-frankenstein

Moving to a new branch

In this particular scenario, I did not have an existing local branch. So I had to create one.

  • create a new branch, from main
git branch feature-frankenstein
  • remove the commits from main
git checkout main
git branch -f main HEAD~3 # make master point to some older commit
  • continue the work on the newly created branch
git checkout feature-frankenstein

Alternatively, there's git reset --hard <commit-id> instead of git branch -f, to reset to a particular commit id. Use this with caution because, if you don't merge your changes first, they will be lost.

Another one with Stash

Using git reset HEAD~n we can undo the last n commits (and their messages) to main, yet leave all working files intact. Then we can stash away all the working file changes, switch to a new branch, and pop the stash.

git reset HEAD~3
git stash
git checkout -b feature-frankenstein # git branch create && git checkout branch
git stash pop

When to use this?

  • If your primary purpose is to roll back master
  • You want to keep file changes
  • You don't care about the messages on the mistaken commits
  • You haven't pushed yet
  • You want this to be easy to memorize
  • You don't want complications like temporary/new branches, finding and copying commit hashes, and other headaches

It doesn't preserve the mistaken commit messages, so you'll need to add a new commit message to this new commit. (getting this should be easy by using command history)