Git: Rewriting History

Git internals

When you run git init in a new or existing directory, Git creates the .git directory, which is where most of the things that Git stores and manipulates are located. This is what you will see in the folder by default:

  • HEAD
  • config*
  • description
  • hooks/
  • info/
  • objects/
  • refs/

Git uses a simple key-value data store. Git stores all the content as Tree or Blob objects. Trees can be thought of as directories and blobs are bits of content. The following object types exist in Git:

  1. commit
  2. tree
  3. blob
  4. annotated tag

In order to understand undoing things in Git let’s take a deeper look into refs and HEAD.

Refs

A ref is an indirect way of referencing to a commit. You can think of it as a user-friendly alias for a commit hash. This is Git’s internal mechanism of representing branches and tags. You can also refer to the commits directly using their SHA-1 hash, you can view this information by running git log

HEAD

When you create a new branch, git uses the last commit of the current branch as reference for the new branch and all new commits will be applied on top. But how does git know what the latest commit is? Git uses the HEAD file to store this information. The HEAD file is a symbolic reference to the branch you’re currently on. By symbolic reference, we mean that unlike a normal reference, it doesn’t generally contain a SHA-1 value but rather a pointer to another reference. When committing new changes, git creates a commit object and sets that parent of this commit to be the SHA-1 value of whatever the reference points to in the HEAD file.

Turning back time

git reset

“Crap, I forgot to branch!”

When you have accidentally committed changes to master instead of a branch you can use:

  • git reset --soft HEAD^

All your changes will be unstaged but still there, you can now make a new branch and commit your changes there instead.

Crap, I want to undo the last 3 commits?

  • git reset HEAD^3

All your changes will be unstaged but still there, you can now make a new branch and commit your changes there instead.

“Crap, I deleted or changed a file accidentally?”

  • git reset path/to/filename

git checkout

“I want to undo the changes to a file”

Git will restore the file to latest version on HEAD, this is the exact opposite of git add. This will get the difference in hunks of file and reset them all. The changes in the file will still be preserved tho, but not marked for a commit.

  • git checkout path/to/filename

This will drop your changes completely and restore the file to the latest version.

Rewriting History

git amend (rewriting history)

“Oops, didn’t mean to commit just yet!”

  • git commit --amend

Premature commits happen, sometimes you forgot to add a file to a commit or made a typo in the commit message. Git allows you to amend your previous commit: If you want to just amend the commit message running command below will let you edit the last commit message.

  • git commit --amend

If you want to just add a new file that you forgot to include:

  1. git add filename
  2. git commit --amend --no-edit

This will add the missing file to the last commit. If you want to amend the commit message at the same time simply don’t provide the --no-edit option.

git revert

“Ah ha! Found what introduced this bug, now to undo this change.”

  • git revert commit-hash

Git revert can help you undo a specific commit that may be no longer needed, it doesn’t actually remove the commit from history but instead figures out how to undo the commit by creating a new commit. This is useful for tracking down and fixing bugs by undoing the commit where the bug was introduced. But also because it doesn’t amend history this is a ‘safe’ way to undo things once the changes are published to a shared repo.

If you get the hang of these few commands you are virtually invincible in Git. There is nothing to worry about with mistakes as most things are fixable. However when re-writing history be careful and make sure this is what you want to do.

🔥 If you enjoyed this post then you can keep up to date with my latests blogs posts & courses by following me on Twitter and checking out my code school for some hands on guided coding practice.