© Mariot Tsitoara  2020
M. TsitoaraBeginning Git and GitHubhttps://doi.org/10.1007/978-1-4842-5313-7_11

11. Diving into Project Management: Branches

Mariot Tsitoara1 
(1)
Antananarivo, Madagascar
 

Last chapter, we discovered Issues and used them to plan our project. We also learned how to link our commits to issues, so that we can follow each change in our project. Our way of work was simple: choose an issue, make a commit that can resolve it, and push to GitHub. The issue was then resolved and closed. But this way of work is not very adapted in most real-world projects; the potential of screw-ups is too high.

What if you need more than one commit to resolve an issue? What if other team members pushed a commit that contained changes to the same files you were working on? How to make sure that the pushed commits really resolve the issue? All of these are part of the reasons why making direct changes to the project is not advised, even if you work alone.

As we said in the last chapter, closing an issue by keywords in the commit message is cool, but you should be very careful with it. Only you have seen your work, and it might not resolve the issue. or it might introduce new bugs in the project. That’s why it is better for someone else to review your code before accepting the changes.

It’s that part that we are going to talk about in this chapter. First, you will be introduced to the most common GitHub workflow (how most teams work on GitHub), and then we are going to learn about the concept of Branches.

But before we begin this chapter, here’s a little thing that you should always remember: “You will make mistakes. A lot of the time. So you must make sure to use as many safeguards as possible.” Let’s go!

GitHub workflow

In this section, we will talk about the most common way that developers use GitHub. Keep in mind that each team has its own way of doing things, but each of these ways of working is inspired by the basic workflow that we are going to present.

Remember the little fact about making mistakes? This omnipresent possibility of mistakes is why you need to follow this GitHub workflow, so even if mistakes happen, you isolate its repercussion in a controlled manner. Our way of work from the previous chapter was to commit everything directly to the main project, and this is very dangerous. The main project is most of the time the “production” line, the version that the clients see and use. So, this version must be very clean and should be always exploitable. If any error makes its way to the main version, the clients will experience bugs and it will disrupt every team member.

One way to resolve this issue is to create a copy of the main project and work on this clone. Each change you make to this copy will not affect the main project, so none of your mistakes can impact clients. And when you (and other people) are perfectly sure that the changes to made resolve the issue, you can reproduce those changes in the main version.

Those copies of the main project are called Branches, and the concept of reproducing changes into another branch is called Merging. You can make as many branches as you like, and you can trade commits between them. When you first create a repository, Git creates a new branch for you; it’s called “master.” Most developers put their main or production version in master and only recreate changes there when they are absolutely sure that it’s okay to do so.

Just like tree branches, Git branch can have many ramifications, meaning that you can even create new branches from branches other than master, even it’s difficult to maintain such architecture. Most of the time, you will create a branch when working on an issue and delete it after the issue was resolved.

To put all this into perspective, we are going to learn about the default or common GitHub workflow. As you know, everything should begin by an issue. We already covered this last chapter so you are already familiar with this. So, we are going to talk about each of the next steps of the workflow.

When you are going to resolve an issue by making code changes, you should first make a copy of the current working version of the project: create a new branch.

Then, as usual, you make your changes and commit the state of the project. You can make any number of commits as you need; it won’t affect the main branch. You can also push your commits to GitHub so your code can be seen.

Then, you link your branch to the master one, so others can compare the changes and review your code. This link is called a Pull Request: you are requesting that your commits be applied to the master branch.

Other team members can then review your code and make comments about it on GitHub. You then push more commits addressing those comments until all problems are solved.

If every party (developers, managers, testers, or clients) agrees that your changes are okay and resolve the issue at hand, the pull request is accepted. This means that every commit you made on your branch will be applied to the master branch. You can then delete the branch you created.

And that’s it! You might wonder how is it different from directly pushing in master. It’s very different because mistakes and omissions are caught before applying the changes to the production version; this means that the number of production bugs is reduced to a minimum. It also makes it possible for various members of your team to review to changes before they are applied, which is the standard way of work in most tech companies. Bundling the changes into one pull request also solve the problem about multiple people pushing commits solving different issues at the same time. It keeps the history log clean.

You might be tempted to open pull requests only when you feel that you are done with your work. Unless the work you did was very small and straightforward, don’t wait long before opening a PR. By working a PR early in your development, you can receive feedback before making too many changes. It is very useful for beginners especially because following the wrong path from the start will take a long time to correct and you would wish that you were told the correct way earlier. Opening a pull request doesn’t mean that the work is done; it just means that you are thinking about applying commits from a branch to another.

Note

As previously established, you can create branches from any branch and open pull requests to it. It’s not only reserved for the master.

To summarize all these steps, you can find a little illustration in Figure 11-1.
../images/484631_1_En_11_Chapter/484631_1_En_11_Fig1_HTML.jpg
Figure 11-1

Basic Git workflow

As you can see, we can create branch from any branch in our project. Git created a branch called master for us at the initialization of the repository. We then can create more branches (e.g. a bugfix branch or a feature branch) to introduce changes in the master branch.

Branches

As we said earlier, branches are the main feature behind code reviews. You have to work on your own branch before publishing your work, so that it won’t be bothered by other people’s changes. Put simply, a branch is just your own independent copy of the project at a certain time. Let’s see how they work and let’s create and delete some.

The logic behind branches is simple: take the current state of the project and make a copy of it. In this copy, you can make your changes without impacting other people. You can use branches to have distinct channels of distributions or just to try new things with the project.

When creating a repository, you get a branch by default: master. When working on very small projects, this branch is enough; but most projects need more branches to get the best results. First, they need a production branch, where clients can get the last stable version of the software; this is the master branch. The production branch is only updated when the project is sure to be stable as this is the release branch. Then, there is the development branch, where all the progress is recorded and all the commits tested. You will mostly work on the development branch as it is where most of the fun is. Finally, there is the short-lived patching branches which you will create to hold your commits before merging them to the development branch. Those patching branches live and die with a pull request; you create one when you are solving an issue and delete it afterward.

To summarize a little bit, you will (most of the time) have three sorts of branches:
  • Production branch, where you will release stable versions of your project

  • Development branch, where you will test your latest version

  • Patching branch, where you will work on your issues

Unless there is a VERY urgent major problem that needs solving immediately, you will never commit directly to the production or the development branch. To update those branches, you will use pull requests so that the changes will be reviewed and tested. There are some companies where every developer just commits directly to the development branch, but this is very counterintuitive because if a bug is discovered, they won’t know which commit introduced it. Also, it forces the developer to push “one-do-it-all” commits, which is an anti-pattern. Do-it-all commits are commits that try to resolve many issues at the same time, for example, a commit that fixes a bug and introduces a new feature at the same time. This practice is often caused by the laziness of developers as they don’t want to create a new branch for another issue. This creates very bad pull requests and makes it difficult to track the progress of the project. It also creates a big challenge for the testers as they don’t know which version is the stable one. It’s an all-around bad idea; don’t do it even with your small projects. It may seem tiring to create and delete branches all the time, but it is the best workflow when working with Git.

The one thing to remember about Git branches is that they just are simple references to commits; that’s why creating and deleting them is so fast. Remember when we talked about how Git stores its commits in chained links? Well, a branch is just a reference to one of those commits. A commit contains information about the author, the date, the snapshot, and, most importantly, the name of the previous commit. The name of the previous commit is called parent and every commit except the first one has at least a parent. Thus, each commit is linked to the previous one so that we can recreate the change history of the project.

For now, you only have the default branch called master and it references the last commit of your project. To create a new commit, Git checks where is the reference and uses the info in that commit to build the link between the new commit and the previous referenced one. So, each time you commit, the reference moves to the new commit and the cycle continues. Thus, a branch is just a reference to a commit that is designed to be the parent of the next one.

But how does Git know on which branch are we one? Well, it uses another reference called HEAD that references the current commit. If you are on a branch, HEAD references the last commit of that branch. But if you are checking out a previous version (like we did when we used “git checkout <commit_name>”), the HEAD references that commit, and you are in a state called “detached HEAD.”

Caution

Just like human bodies, never be in a state of “detached HEAD” if you can avoid it. It is a very dangerous situation to find oneself in.

For most situation, you can think of HEAD as the reference to the current branch, and every commit you create will use the last commit in that branch as a parent.

When you merge a branch into another, a new commit is created that has two parents: one parent from each branch. So you can recognize the commit type by its number of parents:
  • No parents: The very first commit

  • One parent: Normal commit in a branch

  • Multiple parents: A commit created by the merge of branches

Creating a branch

Now that you know a lot about branches, let’s create one! It’s very easy; you just need to use the “git branch” command followed by the branch name. Keep in mind that the branch name should only contain alphanumeric values and dashes or underscores; no spaces allowed.
$ git branch <name>
For example, let’s create a development branch for our project. Let’s name it “develop.” Here’s how to do it:
$ git branch develop

After you execute that command, you will notice that nothing has changed in your project. That’s because creating a branch is just about creating a reference to the last commit of the current branch and nothing else. To begin working with a branch, you have to switch to it.

Switching to another branch

We created our development branch and now it’s time to switch to it. But here’s the problem: I’ve forgot the name I gave to the branch. Now, someone might suggest that we could turn back and look at the previous section to look at the name. But I have a better idea: list all our current branches. To do so, just execute the git branch command without any parameters.
$ git branch
This command will give you the list branches you currently have and will put a little star next to the one you’re currently on (the HEAD). Check out Figure 11-2 for an example of branches list.
../images/484631_1_En_11_Chapter/484631_1_En_11_Fig2_HTML.jpg
Figure 11-2

List of branches in our project

You will notice that we still are on the master branch because we haven’t made anything other than creating a branch. Now let’s switch to it.

You already know the command to switch between versions. Well, we will use the same command to navigate between branches. Simply use “git checkout” with the name of the branch as parameter.
$ git checkout <name>
So, if we want to switch to the develop branch, we will have to execute:
$ git checkout develop

Note

Like when we navigated between versions, you can’t switch branches if you have uncommitted changed files. Commit before you move. Or use a technique called “stashing” that we will see in later chapters.

After checking out the new branch, you will get a confirmation message from Git and you can also check the result of git status to make sure. Figure 11-3 shows the result of those commands.
../images/484631_1_En_11_Chapter/484631_1_En_11_Fig3_HTML.jpg
Figure 11-3

Switching branches

EXERCISE: CREATE A TESTING BRANCH

A simple exercise before we move out to the next battle. It’s very straightforward as all the answers are in this section. The exercise is to create a branch named “testing” where we will test our project before merging all the commits to the master branch. You have to
  • Go back to the master branch

  • Create a new branch named “testing”

  • Switch to the new branch

Tip

To immediately switch to a new branch after creating it, use the option “-b” with the git checkout command. For example, “git checkout -b testing” is the same as “git branch testing” and then “git checkout testing.”

Deleting a branch

You had fun creating the testing branch? Good. It’s time to delete it because we already have a testing branch: develop. That’s where we will merge our patching branches and all the testing will be done there.

You can delete a pushed branch, meaning a branch that is present on the remote repository, by checking “delete branch after PR merged” when creating a Pull Request. This will delete the remote branch but your local branches will be unchanged. You will have to delete your local branches manually.

To delete a branch, simply use the same command as to create one but with the option “-d.”
$ git branch -d <name>
So, to delete our testing branch, we will use
$ git branch -d testing
Just like a real tree branch, you don’t cut the Git branch you are currently standing on. Check out another branch before deleting the branch; and for this reason, you can’t have less than one branch in a project. If you try anyway, you will get an error like the one shown in Figure 11-4.
../images/484631_1_En_11_Chapter/484631_1_En_11_Fig4_HTML.jpg
Figure 11-4

Deleting current branch

Thus, you have to check out the master or develop branch before deleting the testing branch. If you did it correctly, you should get a result like mine as shown in Figure 11-5.
../images/484631_1_En_11_Chapter/484631_1_En_11_Fig5_HTML.jpg
Figure 11-5

Deleting of a branch (we hardly knew ye)

Take note of the confirmation message, it gives you the SHA-1 name of the branch you just deleted. Since the branch we created and deleted contained no commits, it just referenced the last commit of the current branch. Let’s check the history log to confirm this. Execute the git log command to get the list of the latest commits, just like in Figure 11-6.
../images/484631_1_En_11_Chapter/484631_1_En_11_Fig6_HTML.jpg
Figure 11-6

Commit name check

You will see that the last commit name and the branch name is the same; this is because we haven’t made any commit in our branch. You will also see on the history log where the branches are originating from. In this example, the develop branch originates from the 80f145c commit; it’s the branch’s parent.

Merging branches

We talked a lot about merging branches in this chapter but we haven’t made a single merge. Let’s change that.

Let’s imagine that you want to improve the README file of the project by adding a few information. This task is already listed in our GitHub issues so no problem about that. The next step is to create a new branch from the development branch so we can merge them later. You have to create a new branch from the develop branch instead of the master because we won’t touch the master branch until everything is properly tested. If everything is clear and clean, we will merge the development branch into the master branch.

It’s clear then, let’s create the new branch where we will work on. Let’s name it “improve-readme-description.” Don’t forget to checkout out the develop branch before creating a new branch from it. We will thus have to execute
$ git checkout develop
$ git branch improve-readme-description
Now that the branch has been created, switch to it so we can begin to work. To switch to the new branch, just use the checkout command.
$ git checkout improve-readme-description

Perfect! Now we have a branch named “improve-readme-description” that originates from the develop branch. We like branches so much that we created a branch from a branch!

Now let’s get to work. Open the README.md file and change its content to
# TODO list
A simple app to manage your daily tasks.
It uses HTML5 and CSS3.
## Features
* List of daily tasks
Now, stage the file and get ready to commit. I’ll let you choose the commit message, but don’t forget to put a reference to the issue you are trying to resolve! The next steps are thus
$ git add README.md
$ git commit
Nothing new here as every command is the same of any branch. The only slight change is that the branch name is different on the commit description. You can see it on my result shown in Figure 11-7.
../images/484631_1_En_11_Chapter/484631_1_En_11_Fig7_HTML.jpg
Figure 11-7

Committing on another branch

After you made the commit, check the Git history to put all of we did in perspective. Execute the git log command to see our project history.
$ git log

Tip

Use the option “--oneline” when using git log to get a prettier result.

Your project history log should look like mine as shown in Figure 11-8 after you committed.
../images/484631_1_En_11_Chapter/484631_1_En_11_Fig8_HTML.jpg
Figure 11-8

History log after committing on a branch

As you can see in the figure, HEAD now points to the last commit of our new branch; it means that every commit we will create will have that as a parent. You will also notice that the master and develop branch didn’t change; that’s because we only worked on our newly created branch.

Now that we are satisfied with our fix, let’s merge the branch to the develop branch so we can test it. To merge our branch into develop, we first have to check it out. So, navigate there by using the git checkout command.
$ git checkout develop
Now let’s try to merge the branch into the develop one. Merging just means reproducing all the commits on one branch on another. To do so, we will use the git merge command followed by the name of the branch be merged.
$ git merge <name>
Since we are looking to merge “improve-readme-description” into “develop,” our command to execute on the develop branch is
$ git merge improve-readme-description
This command will recreate your commits from “improve-readme-description” into “develop.” So, you will get a similar result as a commit confirmation. Check Figure 11-9 for an example.
../images/484631_1_En_11_Chapter/484631_1_En_11_Fig9_HTML.jpg
Figure 11-9

Merge result

Let’s recheck the git log to have a clearer idea of what happened. You will get a similar result to mine after executing “git log --oneline” that is shown in Figure 11-10.

As you can see, HEAD now points to develop because it’s the checked-out branch. You can also notice that develop and improve-readme-description now point to the same commit; that’s because of the merge.
../images/484631_1_En_11_Chapter/484631_1_En_11_Fig10_HTML.jpg
Figure 11-10

History log after merge

Congratulations on your first merge! It won’t be so easy next time (hint: merge conflicts, they appear when the same line of code has been modified in different commits)

Pushing a branch to remote

Branches are not only made for working locally, you can also publish them to the world by pushing them to the remote repository. For example, let’s push our development branch to GitHub so everyone can see our progress.

The command to pushing a branch to remote is (you guessed it!) git push, just like what we learned in a previous chapter. The command is
$ git push <remote_name> <branch_name>
The remote name hasn’t changed; it’s still “origin.” It’s the branch name that is different this time. Instead of master, we are going to push the develop branch. So, the command will be
$ git push origin develop
Since you’ve already pushed to remote before, the result shown in Figure 11-11 is familiar to you.
../images/484631_1_En_11_Chapter/484631_1_En_11_Fig11_HTML.jpg
Figure 11-11

Pushing to a remote branch

As you can see, there is a little difference in the result: it gave us a link to create a pull request, that is, ask for permission to reproduce the commits on develop to master. Take note of the link because we are going to learn about Pull Requests in the next chapter. ☺

If you return to GitHub to check your project page, you will also have the call-to-action button about creating pull requests. Ignore them for now and instead navigate between your master branch and the develop one. You can check Figure 11-12 for an example of a project page after a new branch has been pushed.
../images/484631_1_En_11_Chapter/484631_1_En_11_Fig12_HTML.jpg
Figure 11-12

Our new project page

It is all about branches for now. You now know how to create, merge, and delete them. And most importantly, you have a basic knowledge of the GitHub workflow: create a branch, work on that branch, and create a pull request.

Now, you may ask yourself: “But didn’t you promise us code reviews and pull requests? Did we even use the workflow?” You are absolutely right. We didn’t use the workflow because we used the direct approach: directly messing with the branches. In a real-world project, you won’t commit and push directly to the master or the development branch like we did earlier. Instead, you will use Pull Request to merge branches together. That way, your work can be reviewed by your coworkers before you can merge them to the development or master branch.

Summary

This chapter dealt with what makes Git a powerful tool for project management: branches. Branches are necessary in a fast-paced development as you will probably work on many issues at the same time. Keeping all those changes in the same place is a recipe for disaster. For example, you need to start in a clean environment to fix a bug or introduce a feature; trying to do both at the same time will seriously increase the risk of introducing more bugs.

The main takeaway of this chapter is the importance of using a workflow when developing with Git. And those workflows all use branches to separate the different types of work necessary for a clean issue resolution.

We’ve seen how to create, check out, and delete a branch. Now, let’s learn more about Pull Requests and Code Review, so we can propose changes in our master branch!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.213.128