Practical Git: Branches

· git

A version control system is one where it leaves engineers happy continuing to code while code is getting organized by it. In this article will look at how branches work and why they are needed in Git and the general development workflow.

I expect you to know basic Git, how to stage, commit, push and pull.

Let’s get started, git init to make a new repository.

Branching out

By default you work on a default branch that is called master. A branch is like a single path of work. As a tree branches up as it grows, the branch gets longer, the history of the project gets older. Branches are nothing but a single line of Git history.

A single developer working on his/her project commits changes to a the master branch. As projects get more mature you may want a release branch that you call it whatever. The release branch will only have what is in production and the master branch will be for development. Once you want to release new features you merge those features into the release branch. In this way there are technically two projects off a single codebase.

Naming the branches doesn’t matter as long you have standards.

In development teams, branches are the savior. If everyone worked on the same branch there would be a disaster every 5 minutes. Why is that? because a branch holds history of the project. Any piece of code can be changed by 2 people and when they push their changes to a central shared repository, problems will arise that are hard to solve and unnecessary. Plus the fact that this does not even allow for code reviewing because all code is going straight to history (no gate keepers). Not to say standards get lost due to no accountability.

To solve this and not worry about unnecessary nightmares. People branch out of a single agreed upon branch and create their own branch. That feature will have the code necessary to implement a feature, fix a bug or both and then ask to branch back into the original branch. In this way gate keepers are in place, when you want to merge (return with new code into original branch) you can wait for code review where other engineers will look at the code and approve you to merge that code into the original branch.

Ok so we solved the problem of people working on the same things at the same time, how do we do the magic that merges everything back? Well Git got you covered. Git does the heavy lifting so you continue writing code.

This seems magical and yeah. That’s how and why modern software systems are moving forward fast. It gives freedom to debug your own code and makes sure it works on your branch or else if everyone shared the same branch everyone would’ve been blocked due to issues you have caused in your changes.

Current branch

To know your current branch name, hit the following command:

git branch --show-current

Or if you want the local branches that you have hit git branch, will highlight your current branch.

The history of your branch can be seen using git log. All commits are recorded.

Why we can merge branches back

It is possible to merge a branch back to it’s parent easily. Since you branched out of your parent branch. Your current and parent branches have a common history. Once you come to merge, different merge strategies can happen. All are done automatically by Git. A simple scenario is the fast-forward merge is when the same parent of both branches is still the same parent of the original branch. Why so you might say? If in that time no other branch was merged into the same original branch then it is still the same parent that is shared. Other merging strategies exist and you will not want to worry about them unless you get a merge conflict.

A merge conflict happens when some/all of your code happens to be merged into a code that was modified and merged before you came to merge or the other way around. In other words, you worked on a feature A and another engineer worked on feature B, then engineer B merged his feature before you did. Both features were branched off the same parent branch. And yet both engineers touched a particular code in their branches. When engineer A comes to merge to the original branch, since things are different to when branch A was initially started, a merge conflict occurred.

To resolve a merge conflict, it can be either done on the original branch or on the child branch. Doing it on the original branch is dangerous and Git doesn’t allow it to be done unless you do a rebase merge is done which is also dangerous and should be avoided when possible. The other way is to update your child branch by merging the parent branch into yours then fix the merge conflict and then commit the fix and then merge back to the parent.

Wouldn’t merging parent to child then to parent create another commit as I said above? Yeah it would. But Git doesn’t worry about that, since it tracks the changes in files and not the commits. The commits represent steps in history.

More often than not you will face the choice of losing commits when merging, since history of the parent has moved on and you are still developing the feature. Not to worry. Squash commits come to the rescue, a single commit will be merged into the parent only. This commit holds off all the changes introduced by your branch. A squash commit is a 2 step process, first merging into the parent to resolve any merge conflicts and then committing.

Working with branches

Ok let’s start, we have our hypothetical project consisting of many feature. I have a bug to fix. So will start a new branch named bugfix/fix-image-not-showing:

git checkout -b bugfix/fix-image-not-showing

Cool we checked out to the new branch. We can confirm by calling:

git branch --show-current

We can also view the history using git log and see it to be the same as the parent branch when pre checking out.

Now I have fixed the bug. Will stage all changes and commit:

git commit -a -m "Fixed xyz bug"

Note I must provide a message using -m flag. -a makes sure to stage changes in tracked files rather than doing it in 2 steps, -a does it in one.

Cool will checkout back to the main branch in my case it is called master:

git checkout master

Now I am in, will check my history using git log and see that I have not fixed the bug in the current branch as intended. Will merge that other branch back in using:

git merge bugfix/fix-image-not-showing

Done. Will push my changes to main remote repository. Cool.

Also will delete my bug fix branch, I can keep it or delete and nothing will change in master. Deleting it will just keep the number of open branches low and keep Git performing fast.

Deleting it:

git branch -d bugfix/fix-image-not-showing

Done.

Code reviews

Ok. Above we didn’t see any code review being done? Wait for it. When you are finished with your branch, you are essentially free to share your branch with your fellow developers to code review. In the code review process, comments maybe made to tell you how to better correct your code, follow team standards and other things you may have not known about. You may get approval right away or maybe requested to change the code and commiting again and ask for a review another time. This is essentially it.

The question is how do you code review? you can always push your branch up to main repository so that other developers can do git pull to update their local version and be able to checkout your repository and see the changes using other Git commands such as git diff, git show, git log and others. However that is a boring way of reviewing where a developer has to leave his/her current working branch and switch to yours. It is usually done using a tool operated by your Git repository provider. A pull/merge request is created by you on the branch and saying which branch you are targeting to merge into. Not only that but you can write using a WYSIWYG editor the changes you made. You can attach images, add comments over code, others comment and can be shared and viewed on the browser without touching the codebase.

Once approved you can merge. Once merged your code is in the main development branch, in this case master.

Forgot to branch out but committed

It sometimes happens where you are on your local development branch and you commit changes and you forgot you didn’t branch out. Don’t panic! Just checkout to a new branch and all the changes will carry over. Go back to master branch and just reset your local history so that changes are always pulled from the main remote repository. To do so, just use git log and find the commit hash which is the id of the commit that was before you started working. Do a:

git reset --hard <hash of commit>

master is back to where it was, checkout to your working branch and continue working just like before.

Remarks

All Git is made to help you. Getting to know Git is really important, it eliminates nightmares of copying code around while it does it for you so seamlessly. The concepts in Git may seem tough at first glance, anything is.

Branches are very powerful and don’t usually get left behind, at the core of Git is branching out of history and writing concurrent histories. This allows for the ease of multiple developers working on many features simultaneously and not only that but also makes the ability to work on many different features per person at the same time easy. Let’s say you are experimenting with a new library, you can make a branch separate from the feature you are working on and see how you can fit that library into your project. When an urgent bug fix is needed you can then go make another branch fix the bug and continue working on your feature/s.

But remember to always branch off the correct parent branch. Why do I say that? because you can branch off another branch and that branch can also have it’s own branches and so on. Why would you do that? Perhaps features and sub-features? Perhaps to have a release and development branches. Perhaps your hot bug fix is temporary until a complete fix is done. The opportunities are endless.

An interesting thing you may not have known is that a git pull means 2 things, first git fetch to fetch and download all changes and then a git merge assuming changes have been done to your current working branch.