Fixing mistakes with Git
--
Bob is my uncle…
He dropped his ice cream.
He didn’t know how to git.
Now he’s dead.
DONT BE LIKE BOB
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 .
beforereset
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.
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.
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.
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”.
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>
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…
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 reset
to 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.