Skip to main content

Illustrated Git commands

Git is an open source distributed version control system that can handle versioning from very small to very large projects efficiently and at high speed, and is the most widely used version management tool available

Although Git is a very powerful tool, I think most people would agree with me that it can also be... A complete nightmare 😐 Always found it useful to imagine in my head what happens when I use Git: how does the branch interact when I execute a certain command, how will it affect the history? Lydia Hallie, a foreign programmer from British Columbia "CS Visualized: Useful Git Commands". In this article, she shows developers how merge, rebase, reset, revert, cherry-pick, and other common Git commands work in a more visual way through animations

Merging

- Fast-forward (--ff)

A fast-forward merge may occur when the current branch has no additional commits compared to the branch being merged, Git first tries to perform the simplest option Fast-forward mode merge does not create a new commit, but instead merges the commits on the merged branch in the current branch

在这里插入图片描述

Now all changes made on the dev branch are available on the master branch. So, what happened to No-fast-foward?

- No-fast-foward (--no-ff)

It would be great if your current branch didn't have any extra commits compared to the branch to be merged, but unfortunately that rarely happens! If we commit changes on the current branch that the branch to be merged does not have, git will perform a No-fast-foward merge. With a No-fast-foward merge, Git creates a new merge commit on the active branch. The commit's parent commit points to the active branch and the branch to be merged! 在这里插入图片描述 No big deal, perfect merge! The 🎉master branch now contains all the changes we made on the dev branch.

Merge Conflicts

While Git is good at deciding how to merge branches and add changes to files, it can't always make that decision on its own 🙂 This can happen when two branches we're trying to merge have changes on the same line in the same file, or if one branch deletes a file modified by the other branch, etc.

In this case, Git will ask for your help in deciding which of the two options we want to keep! Suppose that on both branches we edit README.md. 在这里插入图片描述 If we want to merge dev to master, this will cause a merge conflict: do you want the title to be Hello! or Hey!

When trying to merge a branch, Git will tell you where the conflict occurs. We can manually delete the changes we don't want to keep, save the changes, add the changed files again and then commit the changes 🥳

在这里插入图片描述 Yay! While merge conflicts are often annoying, it makes total sense: Git shouldn't just assume which changes we want to keep.

2.Rebasing

We have just seen how to apply changes from one branch to another by performing a git merge. Another way to add changes from one branch to another is to do a git rebase. 在这里插入图片描述 Perfect, all the changes we make on the branch are now master available to dev on the branch!

One big difference compared to merging is that Git doesn't try to figure out what files to keep and what not to keep. The branch we're basing always has the latest changes we want to keep! This way, you don't run into any merge conflicts and keep a nice linear Git history.

This example shows a master branch based change base. However, in larger projects, you don't usually want to do this. agit rebase changes the project's history because a new hash is created for the replicated commit!

Rebasing is great whenever you are working on a functional branch and the master branch has been updated. You get all the updates on the branch, which will prevent future merge conflicts! 😄

Interactive Rebase

We can modify them before resubmitting the commit! 😃 We can do this with an interactive rebase. Interactive rebases are also useful for branches that you are currently working on and want to modify some commits.

We can perform 6 actions on the commit we are rebasing.

  • reword: change the commit information

  • edit: modifies this commit

  • squash: merge the current commit into the previous commit

  • fixup: merges the current commit into the previous commit, without keeping the commit log message

  • exec: execute a command on each commit that needs to be base changed

  • drop: delete commits

Amazing! This gives us full control over our commits. If we want to delete a commit, we can drop to do so. 在这里插入图片描述 Or, if we want to compress multiple submissions together to get a clearer history, no problem! 在这里插入图片描述 Interactive varbases give you a lot of control over the commits that try to varbases, even on the currently active branch!

Resetting

We may submit changes that we don't want later. Maybe it's a WIP commit, or maybe it's a commit that introduces an error! 🐛 In this case, we can run git reset.

Agit reset gets rid of all the currently staged files and allows us to control where HEAD should point.

Soft reset

Soft reset moves the HEAD to the specified commit (or the index of the commit compared to the HEAD) without removing the changes introduced later in the commit!

Suppose we don't want to keep the commit where 9e78i added the style.css file, or the commit where 035cc added the index.js file. However, we do want to keep the newly added style.css file index.js! A perfect use case for a soft reset.

在这里插入图片描述

Type in git status and you'll see that we still have access to all the changes we made to the previous commit. This is great, because it means we can fix the contents of these files and commit them again later!

Hard reset

Sometimes we don't want to keep the changes introduced by certain commits. Unlike a soft reset, where we no longer need access to them, Git should simply reset its state back to the state it was in when the commit was specified: this even includes changes in the working directory and staging files! 💣

在这里插入图片描述

Git drops the changes 035cc introduced on 9e78i and and resets its state to the state ec5be at commit time.

Reverting

Another way to undo changes is to run git revert. By reverting a commit, we create a new commit that contains the reverted changes!

Let's say ec5be adds an index.js file. Later, we actually realise that we no longer want this change introduced by this commit! Let's restore the ec5be commit.

在这里插入图片描述

Perfect! Commit 9e78i reverts the changes introduced by the ec5be commit. Performing agit revert is very useful for undoing a commit without having to modify the branch history.

Cherry-picking

When a branch contains a commit that introduces the changes we need on the active branch, we can use this command with cherry-picking! With a cherry-picking commit, we create a new commit on the active branch that contains the changes introduced by the cherry-picked commit.

Let's say that the commit dev on branch 76d12 adds changes to the file index.js that we want in the master branch. We don't want this to be the only commit we care about!

在这里插入图片描述

Cool, the master branch now contains the changes introduced by 76d12!

Fetching

If we have a remote Git branch, like a branch on Github, it might happen that the remote branch has commits that the current branch doesn't have! Maybe another branch was merged, your colleague pushed a quick fix, etc.

With git fetch we can get these changes locally by running a on the remote branch! It doesn't affect your local branch in any way: fetch simply downloads the new data.

在这里插入图片描述

We can now see all the changes that have been made since the last push! Now that we have the new data locally, we can decide what we want to do with it.

Pulling

While agit fetch is very useful for getting remote information about a branch, we can also do a git pull. agit pull is actually two commands in one: agit fetch and a git merge. When we pull changes from the source, we first fetch all the data as we would with a git fetch, and then the latest changes are automatically merged into the local branch. then the latest changes are automatically merged into the local branch.

在这里插入图片描述

Great, we're now perfectly synced with the remote branch and have all the latest changes! 🤩

Reflog

Everyone makes mistakes, and that's totally okay! Sometimes you might feel like you've messed up your git repo to the point where you just want to delete it completely.

git reflog is a very useful command for displaying a log of all the actions that have been taken! This includes merges, resets, restores: basically any changes made to a branch.

在这里插入图片描述

If you make a mistake, you can HEAD easily redo this based on the information reflog provided to us!

Let's say we don't actually want to merge the origin branch. When we run the git reflog command, we see that the status of the repo before the merge is at HEAD@{1}. Let's run a git reset to point HEAD back to where it was at HEAD@{1}!

在这里插入图片描述

We can see that the latest action has been pushed to reflog!

Git has so many useful porcelain and plumbing commands, I wish I could go over them all! 😄 I know there are many other commands or changes I don't have time to cover right now - let me know what your favourite/most useful commands are and I'll probably cover them in another post!

As always, feel free to get in touch with me! 😊