Git is a very powerful tool and It has a long list of capabilities available at your disposition. Some commands provide slightly similar results and it is worth understanding and comparing them in order to choose the one that satisfies your needs and improves your workflow. This post is going to define and compare the following commands: revert, checkout, reset, merge, and rebase.
Revert vs. checkout vs. reset
These tools allow you to undo and manipulate changes in your repository. The problem is that they are very similar, therefore it is really easy to get them confused. We will define each of them in detail and list their similarities and differences.
Git revert
This is an unconventional and safe way to revoke an operation as it prevents you from losing history. Git revert inverts the changes that were added in a commit and adds a new commit with the inverted content. This command is especially helpful when you have already pushed your changes to a remote repository as it keeps your original commit intact.
To revert using commit hashes: git revert [SHA]
To revert using ranges: git revert HEAD~[num-of-commits-back]
Git checkout
This is a versatile tool, it allows you to switch in between branches, inspect older commits, and undo local uncommitted changes by moving HEAD and updating your working directory accordingly.
To switch in between branches: git checkout [branch-name]
To inspect an older commit using commit hashes: git checkout [SHA]
To inspect an older commit using ranges: git checkout HEAD~[num-of-commits-back]
Notes:
- When moving HEAD to a different branch or commit, you are going to need to commit or stash any uncommitted changes that could be lost.
- You will be in a detached HEAD state by switching to an old commit, which is great for inspection but not for modifications. In other words, you are not in your branch anymore so don’t add any commits on a detached HEAD because you are going to lose them when you switch to another branch. If you are planning to commit changes on a detached HEAD, make sure to create a new branch from it.
To undo all local uncommitted changes: git checkout .
To undo a specific local uncommitted change: git checkout -- [file-name]
Git reset
This is a powerful but complex way to undo an operation. There are three available arguments:
--mixed
This is the default mode so git reset --mixed
is the same as git reset
. By using any of these commands you will move HEAD to the latest commit and all the changes that were added after that commit will be available as untracked changes in your working directory.
--soft
This operation is similar to the one executed using the --mixed argument. HEAD is moved to the latest commit, however, the changes that were added after that commit are left staged.
--hard
Use the command git reset --hard
only when you know what you are doing as it is very dangerous. By resetting the hard way, you will move HEAD to the latest commit and destroy the changes that were added after. This cannot be undone so use it wisely.
You should not use git reset
when you have already pushed to a remote repository. Removing a commit that other team members have continued building upon is hard and it would disrupt your team member’s workflow.
Bonus action: Use git reset -- [file-name]
to unstage a file that hasn't been committed yet.
Merge vs. rebase
When multiple people are working in a project you will need to combine your code at some point. Git rebase and merge have different approaches to consolidate the changes from one branch into another one.
Git merge
It uses a non-destructive operation to combine two branches’ histories without changing them. In addition, it creates a new “merge commit” every time it’s used. This is a great way to consolidate changes, however your commit history could get several merge commits depending on how active your master branch is, which can get cumbersome.
To combine the latest changes from master into your branch:
git checkout [branch-name]
git merge master
Git rebase
This is a destructive operation as it moves an entire branch’s history on top of another one by rewriting the project history with new commits.
This command is useful if you prefer a clean and linear project history. However, it is not safe to rebase on changes that have been pushed to a remote repository master branch because you would be changing the master branch’s history while your team members continue working on a diverged version of it.
In addition, Git will not allow you to easily push a rebased branch back to a remote repository. You are going to need to force it by using git push --force
, which overwrites the remote branch and could cause issues with other collaborators. In other words, stop yourself from confusing your team members and creating tedious conflicts by only using rebase to cleanup in-progress features and not the master branch.
I hope you found these comparisons helpful and easy to follow. I explore, define, and explain git concepts every Saturday!
If you are new to git, checkout my previous post Git Explained: The Basics.
Top comments (18)
Hi Milu,
your Git introductions seems to be great, but I have real issue with that "git merge" graph. When you merge, Git doesn't "flatten" the graph, only creates a new commit that will have two parents (green commit #3 and orange commit #3). Green commit 3 will never have orange commit 1 as its parent commit. If so, the green commit 3 would have different hash and the rest of the commits (orange 2 and 3) as well and you would be in same situation as with rebase.
Please, redo that graph.
Thanks.
Hi Richard,
Your comment made me realized my visualization was definitely misleading. I've updated it to reflect that a new merge commit has two parents. Thank you for the feedback!
That is a really great topic, especially since I've also been in that situation in the past (probably most developers have experienced it too). I will make sure to add it in a future post.
Thanks for the suggestion Javier!
Thank you for taking the time to ready my post, Javier! I'm glad the illustrations are helping. Please let me know if there is anything else about git you would like to learn more in a future post :)
"This is a destructive operation as it moves an entire branch’s history on the tip of another one by rewriting the project history with new commits." - there is a typo, 'on the top'.
Thanks for catching that typo, Vitaly! I fixed it :)
Thanks, Milu! I find Git a bit scary and it's great to see commands so clearly and simply explained. The drawings make it so much easier to understand.
Hi! I'm glad you are finding my explanations and drawings easy to follow. Thank you for reading and the kind words!
Amazing post! this was the simplest explanation about Merge and Rebase differences that I have seen so far!
Thank you Francisco! :)
Very nice post by creating a 5 part series which is easy to learn 👍
Glad you found it easy to understand Aftab! And thank you for reading :)
Thanks for sharing. I love it.
Good job
Thanks for the support and encouragement Edelberto! I truly appreciate it.
Incredibly Milu! I like the way that you explained. I never use a reset (just reset HEAD to undo changes of staged before commit) but now I understand it and I'll try to use it. Thanks for all.
Thank you Juan! I'm happy you found my git reset explanations useful, I find it to be a very powerful command and personally enjoy using git reset --soft often. Let me know if there is anything else about git you would like me to explain in a future post! :)
what tools did you use to make that illustrations/visualization ?
Hi Monesul, I used an app called Paper Pro and Photoshop to make my cover image.