Git it! - Simplified Git Tutorial (Part 3).

Advanced Git Topics from merging commits to squashing them.

Posted by Aashish Kumar on May 07, 2020 · 15 mins read

If there is a tool or software that every software developer must know, it is GIT. Everyone will agree that we all struggle with it initially when we start learning it. So I’m here to ease the burden from the shoulders of the beginners, who are just starting with this amazing tool.

Let’s Git it!

We’ll be learning the following topics today:-

  1. Understanding Git (How it Works?)
  2. Installation and Setup
  3. How to Commit!
  4. Git + Github
  5. Branching and Merging
  6. Rebasing
  7. Squashing

Note :- This is the part 3 and contains the last three topics. Head to part 1 and part 2 for earlier topics.

Branching and Merging

Now we know that you understand basic git usage. It’s time to use the most effective feature of git, branching. Branching is mostly used when we want to work on several parts/features of a project simultaneously and don’t want the work on one feature to affect others. Branches can be visualized in the following way:

image alt ><

For this tutorial, this is currently the branch structure that we’re having:

image alt ><

The default branch is called master. To create a new branch, run the following command:

git checkout -b <branchName>

It creates a new branch and sets the HEAD to that branch (checkout). This is shorthand for:

git branch <branchName>
git checkout <branchName>

We’ve created a branch named Feature, after running the mentioned commands this will be the state:

image alt ><

We’re now at the head of the newly created Feature branch. Now make some changes and commit again. The state of the repo will change to:

image alt ><

You can switch between branches by simply using the checkout command:

git checkout <branchName>

Note:- You cannot switch between branches before committing the changes in your current branch.

After switching to the master branch, this will be the state:

image alt ><

Now let’s say we make 2 more commits in the master branch.

image alt ><

Now, what we’ll do is update the Feature branch with the commits done in the master branch. This way we’ll have all the updates of the master branch in the Feature branch. First, checkout the Feature branch:

git checkout Feature

image alt ><

Now to have the commits of the master branch you need to merge master branch into the feature branch. In order to merge the branches, we’ve already checked out the feature branch, now just run the following command:

git merge master

After this, the text editor will pop-up and will ask you to write the merge commit message. Enter the message then save and exit the text editor.

Now, feature branch will also have the commits and the changes done in C4 and C5 from master branch. Also, the new C6 commit is the merge commit, for which you wrote the commit message.

image alt ><

Note:- The commits C4 and C5 in the feature branch are the same ones as the master branch i.e the commit hashes do not change and if you delete any of the commits, it’ll be deleted from both the branches.

Bamm! Now you know the basics of branching and merging. Now it’s time to learn one more important technique, rebasing. But before that let us discuss something that we call as merge conflicts.

Merge Conflicts

Sometimes it may happen that you’ve created a new branch, say sampleBranch, and changed the contents of a file in it, meanwhile, someone else working in the master branch also changes the content of the same file. Now if you try to merge the sampleBranch into master, you’ll get merge conflicts as git will get confused in which changes to keep and which ones to leave. In that case, you need to resolve the merge conflicts before committing the merge.

Rebasing helps in avoiding merge conflicts. So let’s learn how rebasing is done in git.

Rebasing

According to Git-tower:

In Git, the rebase command integrates changes from one branch into another. It is an alternative to the better known “merge” command. Most visibly, rebase differs from merge by rewriting the commit history to produce a straight, linear succession of commits.

Rebase is a better technique than merging because it doesn’t give you a merge commit, just the commits required.

As given by Atlassian, rebase can be visualised as follows:

image alt ><

From a content perspective, rebasing is changing the base of your branch from one commit to another making it appear as if you’d created your branch from a different commit. Internally, Git accomplishes this by creating new commits and applying them to the specified base. It’s very important to understand that even though the branch looks the same, it’s composed of entirely new commits.

Now let’s say we’re in this state:

image alt ><

And in C3 and C5, we’ve worked on the same files as C4, and we want to merge the master branch into feature branch and bring the changes of C4 into feature branch. Now if we do a merge, then there will be merge conflicts and we’ll be having a new merge commit C6, containing the changes of all C3, C4 and C5, like this:

image alt ><

But we don’t want that, we want to reattach our feature branch to the new root C4, like this:

image alt ><

This can be done using the simple rebase command, checkout the feature branch first and then run the following command:

git rebase master

Git might ask you to fix conflicts, this is how you can do it:

Fixing Conflicts

<<<<<<<<<<< HEAD
use changeFromC4;
===========
use changeFromC5;
>>>>>>>>>>> Your Commit

Both the changes are in the same line in the same file, the upper one is done in C4 and the lower one is done in C5, now git is asking you which one to keep. A way to fix this is to include both, so you can delete all the lines from the »> to «<, and replace them with the correct code:

use changeFromC5 changeFromC6;

After fixing all the conflicts, add all the files you edited:

git add <files you edited>
git rebase --continue

You might need to do this action multiple times until every merge conflict is resolved. In case you mess up things, you can always run the abort command to start over:

git rebase --abort

Hurray! You now know rebasing as well (You’re a pro, I’m telling you already!). Now there’s one last technique that we need to learn, which is used a lot when contributing to open source projects, squashing.

Squashing

It may happen sometimes that you’re working on a project and you’re committing a lot, even for a small change you are having a commit, now you have a finished project with more than 100 commits, which is not a good thing as it’ll be difficult for others and you as well to go through your commits and find the changes that you’re looking for. So git provides you a very good feature of merging commits known as squashing, it is similar to merging, the difference is that it’s used to merge commits, not branches. So without wasting any more time, let’s squash!

For this tutorial we’ll be working entirely in feature branch, let’s say we’re in the following state:

image alt ><

And we want to squash C4, C5 and C6 into one commit, say C7. We can do that simply by the following steps:

  1. Open git log and copy the hash of the commit C3.

  2. Run the rebase command:

     git rebase -i <hash of C3>
    

    This will open in a text editor:

     pick <hash of C4> C4
     pick <hash of C5> C5
     pick <hash of C6> C6
    
     # Rebase f181e0e..f9c96cf onto f181e0e (2 command(s))
     #
     # Commands:
     # p, pick = use commit
     # r, reword = use commit, but edit the commit message
     # e, edit = use commit, but stop for amending
     # s, squash = use commit, but meld into previous commit
     # f, fixup = like "squash", but discard this commit's log message
     # x, exec = run command (the rest of the line) using shell
     # d, drop = remove commit
     #
     # These lines can be re-ordered; they are executed from top to bottom.
     #
     # If you remove a line here THAT COMMIT WILL BE LOST.
     #
     # However, if you remove everything, the rebase will be aborted.
     #
     # Note that empty commits are commented out
    
    
  3. Now keep the first commit and change the rest from pick to squash:

     pick <hash of C4> C4
     squash <hash of C5> C5
     squash <hash of C6> C6
    
     # Rebase f181e0e..f9c96cf onto f181e0e (2 command(s))
     # ......
    
    
  4. Save and exit the text editor. The rebase will run till the end and all the commits after C4 will get squashed into one.

  5. After the rebase is done, the text editor will pop-up again, now you can write the commit message for the new commit C7. The commits are now squashed.

    image alt ><

  6. Now if you want to push this to your remote repo, run the following command:

git push <remoteName> <branchName> -f

where -f flag means force push.

Booyah! You now know how to use git, remember, this is just the beginning and only practice can help you learn git well. With this ends our git tutorial series Git it. We hope that you understood the concepts well.

If there’s still something that you think that is missing or needs to be modified, you can comment down below or let us know by raising an issue.

Also if you haven’t checked out our previous tutorials in this series, you can check the part 1 and part 2.

Dasvidaniya!!