Author avatar

Gabriel Cánepa

Create a Git Repository and Branching Code

Gabriel Cánepa

  • Mar 4, 2019
  • 13 Min read
  • 291 Views
  • Mar 4, 2019
  • 13 Min read
  • 291 Views
Revision Control
Git

Introduction

Today, it is not unusual to have programmers spread across buildings, cities, countries (and several time zones) while collaborating on one or more tasks. Distributed version control systems, such as Git, are what makes this possible - from the creation of an app all the way to adding, testing, and shipping new features.

This guide is not intended as a complete reference on Git, but as an overview of creating and working with repositories. As such, it assumes that the utility is installed on your system and that you are using a Unix-based operating system. If you are on Windows, Git commands are identical, and you will only need to modify some of the examples.

Introducing Git

Up until the early 2000s, software developers used to share their work from person to person. As more individuals were involved in the same projects, this approach became time-consuming, error-prone, and far from effective. Version control systems, a set of software tools that help teams share files and track changes over time, were born to address those needs.

In 2002, the Linux kernel community was among the first to adopt a version control system known as BitKeeper. Git was later devised by Linus Torvalds and launched in May 2005 after an open and public conflict on licensing terms between these parties. Two months later, a Japanese software engineer named Junio Hamano was appointed as the maintainer, a role that he still fills to this day.

Before we dive any further, it is worthy and well to define some common terms we will encounter later:

  • Web-based solutions, such as GitHub, Bitbucket, or GitLab, must not be confused with Git itself. These tools only provide space to store code in the cloud and a friendly interface to perform several operations. In this guide, we will use GitHub, but the process is very similar if you choose another solution.

  • A repository is a folder that contains the files and subdirectories of a project. It can be either public or private, depending on who should have access (anyone or only members of a team, respectively).

  • A branch is a separate development path (in the same repository) that is often used to work on new features without interfering with the main project. Once the code is reviewed and tested, a repository administrator can merge the changes into the master branch.

  • A commit is a snapshot of a repository at a point in time. It allows users to include comments and ask for feedback from other people. Using its hash, one can easily return to a previous state of the project if needed. Before file and directories can be committed, we need to instruct Git to track them. We usually refer to this step simply as adding or staging files.

  • A pull request is a method to inform other developers about and discuss recent changes before incorporating them into the main development path.

  • A fork is an independent project which is based off a given repository. Unlike branches, it is not local to the latter, but it can also be merged into it through a proper pull request.

  • A .gitignore file can be used to indicate which local content should not be committed to the repository. This is particularly useful to avoid pushing temporary files to or exposing sensitive information (such as passwords, SSH or API keys, and credit card numbers) in a web-based solution.

With that in mind, let us learn how to use Git and leverage GitHub for a software development project. Albeit simple, the following example will help us illustrate the basics of these utilities.

Creating a Repository

To begin, we will need to create a separate directory and then initialize Git on it:

1
2
3
    mkdir learn-git
    cd learn-git
    git init .
bash

As shown in Fig. 1, the last command automatically placed us in the master branch and generated a hidden subdirectory called .git. This folder contains all the files and directories that allow Git to manage the repository.

Figure 1 - Creating a Git repository

At this point, we have a local working repository but have not added or committed any files yet. Before we do that, we will follow these steps to create an empty remote repository in GitHub where we will push our code.

  1. Click on the plus sign in the top right corner and choose New repository as seen in Fig. 2:

Figure 2 - Creating a new repository in GitHub

  1. Enter a repository name, an optional description, and choose Public as illustrated in Fig. 3. Do not initialize the repository with a README or add a .gitignore file at this point, as we will do that later - along with the license. Finally, click on Create repository.

Figure 3 - Entering repository settings

  1. Copy the remote repository URL and take note of the suggested commands to push the local one over to GitHub through the command line but do not run them yet. Fig. 4 shows this step in our case.

Figure 4 - Copying the repository URL and initial commands

We are now prepared to start adding files to our staging area and committing them.

Our First Commit

For this test, we will create a short Python file named disk_info.py with the following content:

1
2
3
4
5
6
7
8
    import shutil

    def disk_percent_usage(directory):
            '''
            Return percent usage of disk where directory resides
            '''
            disk_info = shutil.disk_usage(directory)
            return round(disk_info.used * 100 / disk_info.total, 2)
python

When this module is used, it is compiled to byte code in a file with the .pyc extension, usually in the same directory or in a subdirectory called __pycache__. In any event, we certainly want to include disk_info.py in our repository but not the associated .pyc file - and that is where .gitignore enters the picture.

To avoid keeping track of byte code files, we can add a single line to .gitignore as follows:

1
    echo "*.pyc*" >> .gitignore
bash

With that, let us add both files (disk_info.py and .gitignore) to the staging area. Fig. 5 shows the difference in the output of git status before and after this step.

1
    git add disk_info.py .gitignore
bash

Figure 5 - Staging files

The next step consists of committing the files to the repository. The -m option allows to include a message to describe the operation.

1
    git commit -m "Initial commit for Pluralsight guide"
bash

Until files are committed as explained above, they are not part of the repository although they reside in the same directory where it is initialized.

Finally, push the local repository over to GitHub. Note that you will be prompted for your credentials as seen in Fig. 6:

1
2
    git remote add origin https://github.com/gacanepa/learn-git.git
    git push -u origin master
bash

Figure 6 - Pushing files to GitHub

If we now browse to our GitHub repository, we should see the files as shown in Fig. 7. The commit hash is enclosed in a red rectangle and should be identical to the one that was returned by git commit earlier.

Figure 7 - Viewing files in GitHub

You can always view the changes that were introduced in a given commit via the URL for that commit. In the example above, it is https://github.com/gacanepa/learn-git/commit/1cbe0f3. Additionally, the full commit list (including messages, dates, hashes, and the user account who was responsible for each change) is available through git log.

Branching Code

So far, we have only used the master branch, which is where our production-ready program resides. If we want to add a new feature, we should consider creating a separate branch called development, although you can choose another name if you wish, and make changes there to start.

1
    git checkout -b development
bash

The above command not only created the branch but switched us to it, as you can see in Fig. 8:

Figure 8 - Creating and switching to a new branch

We can now open our text editor and create a new file named system_info.py with the following lines:

1
2
3
4
5
6
7
8
    import platform

    def kernel_info():
            '''
            Return Linux kernel information
            '''
            kernel_info = platform.uname()
            return {'release': kernel_info.release, 'version': kernel_info.version}
python

Next, we will proceed to stage the file, commit the change, and push it to the remote repository.

1
2
3
    git add system_info.py
    git commit -m "Added function to retrieve kernel information"
    git push -u origin development
bash

To switch between branches in GitHub, we can use the dropdown list as illustrated in Fig. 9. If we select development, we should see the file we just added. Additionally, we can compare branches and create a pull request to merge development into master, but we will leave that for later.

Figure 9 - Overview of two branches

Once our code is in GitHub, other developers can clone our repository to start working on it on their local machines.

Cloning a Repository

Before another developer can contribute to our repository, we need to add him or her as a collaborator in GitHub. To do so, we should go to Settings, click on Collaborators, and type the username or email address to send an invitation. Once our colleague accepts it, he or she will be able to:

  1. Clone the repository:
1
    git clone https://github.com/gacanepa/learn-git.git
bash
  1. Switch to the development branch:
1
    git checkout development
bash
  1. Make a change. In this case, we will add a README file using Markdown format:
1
2
    echo "# learn-git" > README.md
    echo "Check out my guide at Pluralsight" >> README.md
bash
  1. Stage the file:
1
    git add README.md
bash

If you need to add several files at once, you may want to stage the entire current directory with git add . instead.

  1. Make the commit:
1
    git commit -m "Added README.md"
bash
  1. Push the file:
1
    git push
bash

After making all these changes in the development branch, it is time to create a pull request for merging them into master.

Creating a Pull Request

To incorporate the latest changes to the master branch, we will raise a pull request. Although this can also be done through the command line, it is much easier in GitHub. When you click on Pull request, you will be taken to a page where you can view the list of the commits in development to be included and add comments as you can see in Fig. 10. Next, click on Create pull request to continue:

Figure 10 - Creating a new pull request

Finally, go to Pull requests and click on Merge pull request as shown in Fig. 11. Note that you will still be asked to Confirm merge afterward:

Figure 11 - Merging a pull request

At this point, the master branch should be up to date when compared to development as you can confirm in Fig. 12:

Figure 12 - Viewing the master branch

Although it was not the case in this example, Git also provides a method to resolve conflicts between commits in the same branch if needed, as we will see next.

Resolving Merge Conflicts and Returning to Previous Commits

If a developer attempts to do a git pull after committing a file and there are discrepancies between his local repository and the remote one, a merge conflict occurs.

Generally speaking, a merge conflict arises whenever more than one person edits one or more lines in a file at the same time.

When this happens, an indication is added to the offending file(s) as you can see in Fig. 13. To resolve the conflict, you need to edit the file leaving the line(s) you want to keep, commit again, and push.

Figure 13 - Viewing a merge conflict

As we mentioned previously, Git also allows us to return to a previous commit if we wish. To do so, we can do git log to view the history and choose a specific snapshot using its hash. For example, to reset the status of master to what it was at commit 1cbe0f3, do

1
    git reset 1cbe0f3
bash

This results in the changes that can be seen in Fig. 14:

Figure 14 - Resetting the repository to a previous commit

Thus, README.md and system_info.py are still present in the current directory but were removed from the staging area after we ran the previous command.

Summary

In this guide, we have learned how to create a Git repository, work with branches, merge changes, and resolve conflicts. With these new skills, you will be able to work with other developers more effectively from here on out.

3