Fixing mistakes with Git

Photo by Sarah Kilian on Unsplash

Bob is my uncle…

He dropped his ice cream.

He didn’t know how to git.

Now he’s dead.

Lucky for you I am here to share some ways to fix your mistakes on your project. This is assuming you already know git, if not read these articles:

If you prefer video: Git and GitHub for Beginners — Crash Course — YouTube

How git can fix my project?

Well, git has a full history(from the day of git init to today) of your project development. All you have to do is view the history and select the day you wanna go back and boom. This all will workout assuming you’ve named your commits properly😅.

You can not fix the mistakes once you pushed the changes to remote, theoretically of course. I mean you could, but it will mess up everyone else working on the branch so it is not advised not to fix something that is already on the remote unless all the contributors agree to it.

reset

git reset undo’s changes by removing the commits from the branch.

git reset --soft
git reset --mixed
git reset --hard

Each command above moves your current version of your project to the last recent version. You can go back to a specific commit by appending HEAD~n where n is the number of commits to go back.

i.e., git reset --soft HEAD~3 to go back in 3 commits.

  • — -soft flag only moves the HEAD pointer to the commit but doesn’t affect the working directory and staged changes, meaning if you have created some files but that doesn’t exist on the older commit now it will be there because it still exists in the staging area and the working directory.
  • --mixed flag is the default and this moves the HEAD but it resets the staging area but not the working directory. So, if you have issued agit add . before reset it will be removed from the staging area but it will still be in the working directory.
  • --hard flag will do a factory reset to the specific commit. Anything and everything and between is vaporized.

Please do not do this in a public branch(a branch that is already pushed to remote) instead use the safer version revert.

You can also use git reset <filename> or git reset <commit-hash> <filename> to unstage a file without removing it from the filesystem.

git reset by Visualizing Git (git-school.github.io)

revert

git revert is a safer version of undoing a commit. Revert works by finding a way to create a new commit without the changes introduced by the specified commit and appends it to the current tree. Meaning it will not delete any commits instead it will create an inverse version of the specified commit.

git revert HEAD
git revert <commit-hash>

Unlike reset, revert requires a commit hash to act.

git revert by Visualizing Git (git-school.github.io)

You can see in the above image that unlike reset it doesn’t just remove the previous commits instead creates a new commit and preserves the commits and doesn’t create problems with other branch contributors.

If revert and reset do the same which should I use?

Reset:

  • Don’t use it in a public branch.
  • Will remove all the commits after the specified commit (i.e., resetting to two days old commit will remove all the commits made in the last two days).
  • Use it if you are the only one using the branch or if the commits haven’t reached the remote repo.

Revert:

  • Use it anywhere. Afterall it just gonna look like a new commit…

Edit commit messages

Sometimes you make a silly spelling mistake in your most recent commit message and if you want to edit you can re-commit with the--amend flag. You can also add new files and use amend to update the most recent commit snapshot.

git commit --amend -m "new message that doesn't trigger your OCD"

Again, do not amend a commit that is pushed to a remote.

But the --amend the flag will only work for the most recent commit, what if you want to edit a commit message that is older than the most recent commit?

You can use rebase to change older commit messages. Rebase is also used to integrate changes from other branches just like git merge but rebase gives you finer control on how the history of the base branch should look after integrating.

git rebase -i HEAD~n n is the number of commits to go back.

This will open your default editor and show n number of commits with the work “pick” before it.

git rebase -i HEAD~5

Now change the word “pick” to “reword” from the commits that you want to change the message. DO NOT CHANGE THE COMMIT MESSAGE HERE YET… Just change the word “pick” -> “reword”.

Like this👆

Save the file and close the editor.

Now you will get a new editor with the commit message. Change it to your new commit message and save it, then close the editor. If you have are trying to reword multiple commits, then you will get each editor windows one by one. That’s it. Remember, rebase will rewrite the history not just update the message so avoid it in remote branches.

Move a commit to a new branch

Sometimes you wanna work on a specific commit but you don’t want to mess with the main/master branch by performing a reset. For this, you can create a branch that contains that specific commit and work there and merge it later.

git branch -b fix
git checkout fix
git reset --hard <commit-hash>

Or you can do it in one line: git checkout -b fix <commit-hash>.

cherry-pick

git cherry-pick is used to pick a specific commit from a branch and place it in the current branch.

Why in the world would I do that?

  • You created a commit in the wrong branch. Oops.
  • You want to include a commit from your branch “fix_contrast” to your main/master branch but you don’t want to merge the whole branch just yet.

Checkout to your base branch where you want the picked commit to be and then issue the command.

git cherry-pick <commit-hash-from-other-branch>

git cherry-pick by Visualizing Git (git-school.github.io)

This will copy that commit from the target branch to your current/base branch. This will not delete the commit on the target branch, it just makes a copy. This will have the same commit message as the target branch commit message, if you want to edit it you can use -edit the flag to rename it before cherry-picking finishes. Or if you don’t want to commit the target branch commit, use --no-commit the flag to copy only the changes to the working directory.

Even though the reset did remove the commits it looked like it left a phantom of the commits behind…

spooky ghost boi…

If the commits are removed then it shouldn’t have its hash right? YES and NO.

Although you reset your branch history every time you make critical actions like reset or merge git stores these actions in a special record called reference logs (aka reflog).

So, if for some reason you think you made a mistake by hard resetting a branch and if you want the commits back, you can get it back.

Issue the command git reflog and it will return the log of all critical mistakes you’ve done so far.

You can again use the git resetto get back to the previous stage but this time the syntax is a little different, git reset HEAD@{n} where n is the number shown in reflog.

And that’s it. You can fix mistakes and fix the fixed mistakes that turned out to be a mistake by themselves😂. Also, remember to avoid any of these operations on a public branch with multiple collaborators working on it.

There are some other ways too but I only used the above commands for the most part and I hope this article should give you an intro to cleaning up yours's and your colleges’ mess.

That’s it baby [giphy.com]

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store