Chapter 3. Git Fundamentals – Working Remotely

In this chapter, we will finally start to work in a distributed manner, using remote servers as a contact point for different developers. As we said earlier, Git is a distributed version-control system. This chapter is for the distributed part.

Working with remotes

You know that Git is a tool for versioning files. However, it has been built with collaboration in mind. In 2005, Linus Torvalds had the need for a light and efficient tool to handle tons of patches proposed to the Linux kernel from a multitude of contributors. He wanted a tool that would allow him and hundreds of other people to work on it without going crazy. The pragmatism that guided its development gave us a very robust layer to share data among computers, without the need of a central server.

A Git remote is another computer that has the same repository you have on your computer. Every computer that hosts the same repository on a shared network can be the remote of other computers:

Working with remotes

So, a remote Git repository is nothing other than a remote copy of the same Git repository we created locally. If you have access to that host via common protocols such as SSH, HTTPS or the custom git:// protocol, you can keep your modification with it in sync.

The great difference between Git and other distributed version control systems (DVCS) to classical centralized versioning systems (VCS) such as Subversion is that there's no central server where you can give custody of your repository. However, you can have many remote servers. This allows you to be fault tolerant and have multiple working copies where you can get or pull modifications, giving you incredible flexibility.

To start working with a remote, we have to get one. Today, it is not difficult to get a remote. The world has plenty of free online services that offer room for Git repositories. One of the most commonly used repository is GitHub. Before starting, note that GitHub offers free space for open source repositories, so everyone in the world can access their code. Be careful, and don't store sensitive information such as passwords and so on in your repository; they will be publicly visible.

Setting up a new GitHub account

GitHub offers unlimited free public repositories, so we can make use of them without investing a penny. In GitHub, you have to pay only if you need private repositories, for example, to store the closed source code on which you base your business.

Creating a new account is simple. Just perform the following steps:

  1. Go to https://github.com.
  2. Sign up using your e-mail.
    Setting up a new GitHub account

When done, we are ready to create a brand new repository where we can push our work:

Setting up a new GitHub account

Go to the Repositories tab, click on the green New button, and choose a name for your repository:

Setting up a new GitHub account

For the purpose of learning, I will create a simple repository for my personal recipes. These recipes are written using the Markdown markup language (http://daringfireball.net/projects/markdown/).

Setting up a new GitHub account

Then, you can write a description for your repository. This is useful to allow people who come to visit your profile to better understand what your project is intended for. We create our repository as public because private repositories have a cost, as we said earlier. Then, we initialize it with a README file. Choosing this GitHub makes a first commit for us, initializing the repository that is now ready to use.

Cloning a repository

Now, we have a remote repository, so it's time to learn how to hook it locally. For this, Git provides the git clone command.

Using this command is quite simple. All we need to know is the URL of the repository to clone. The URL is provided by GitHub in the bottom-right corner of the repository home page, as shown in the following screenshot:

Cloning a repository

To copy the URL, you can simply click on the clipboard button on the right-hand side of the textbox.

So, let's try to follow these steps together:

  1. Go to the local root folder, C:Repos, for the repositories.
  2. Open a Bash shell within it.
  3. Type git clone https://github.com/fsantacroce/Cookbook.git.

Obviously, the URL of your repository will be different. As you can see in this screenshot, GitHub URLs are composed by https://github.com/<Username>/<RepositoryName>.git:

Cloning a repository

At this point, Git created a new Cookbook folder that contains the downloaded copy of our repository. Inside, we will find a README.md file, a classical one for a GitHub repository. In this file, you can describe your repository using the common Markdown markup language to users who will chance upon it.

Uploading modifications to remotes

So, let's try to edit the README.md file and upload modifications to GitHub:

  1. Edit the README.md file using your preferred editor. You can add, for example, a new sentence.
  2. Add it to the index and then commit.
  3. Put your commit on the remote repository using the git push command.
    Uploading modifications to remotes

The git push command allows you to upload local work to a configured remote location, in this case, a remote GitHub repository. There are a few things we have to know about pushing. We can begin to understand the message Git gave us just after we run the git push command.

What do I send to the remote when I push?

When you give the git push command without specifying anything else, Git sends to the remote all the new commits you did locally in your actual branch. For new commits, we will send only the local commits that have not been uploaded yet.

The messages that appeared earlier tell us that something is about to change in the default behavior of the git push command. Before the incoming Git 2.0 release, when you fire the push command without specifying anything else, the default behavior is to push all the new commits in all the corresponding local-remote branches.

In this brand new Cookbook repository, we only have the master branch. However, next, you will learn how to deal with the remote having many branches.

Pushing a new branch to the remote

Obviously, we can create and push a new branch to the remote to make our work public and visible to other collaborators. For instance, I will create a new branch for my first recipe; then, I will push this branch to the remote GitHub server. Follow these simple steps:

  1. Create a new branch, for instance, Pasta: git checkout –b Pasta.
  2. Add to it a new file, for example, Spaghetti-Carbonara.md, and commit it.
  3. Push the branch to the remote using git push -u origin Pasta.
    Pushing a new branch to the remote

Before continuing, we have to examine in depth some things that happened after we used the git push command.

The origin

With the git push –u origin Pasta command, we told Git to upload our Pasta branch (and the commits within it) to the origin. The origin is the default remote name of a repository, like master is the default branch name. When you clone a repository from a remote, that remote becomes your origin alias. When you tell Git to push or pull something, you often have to tell it about the remote you want to use. Using the origin alias, you tell Git that you want to use your default remote.

If you want to see remotes actually configured in your repository, you could type a simple git remote command, followed by -v (--verbose) to get some more details:

The origin

In the details, you will see the full URL of the remote.

You can add, update, and delete remotes using the git remote command. We will make use of it when we need to. For now, just remember that there is a command for that.

Tracking branches

Using the -u option, we told Git to track the remote branch. Tracking a remote branch is the way to tie your local branch with the remote one. Note that this behavior is not automatic; you have to set it if you want it (Git does nothing until you ask for it!). When a local branch tracks a remote branch, you actually have a local and remote branch that can be kept easily in sync. This is very useful when you have to collaborate with some remote coworkers at the same branch, allowing all of them to keep their work in sync with other people's changes.

Furthermore, consider that when you use the git fetch command, you will get changes from all tracked branches. While you use the git push command, the default behavior is to push to the corresponding remote branch only.

To better understand the way our repository is now configured, try to type git remote show origin:

Tracking branches

As you can see, both the Pasta and master branches are tracked.

You can also see that your local branches are configured to push and pull to remote branches with the same name. However, remember that it is not mandatory to have local and remote branches with the same name. The local branch foo can track the remote branch bar and vice versa; there are no restrictions.

Downloading remote changes

The first thing you have to learn when working with remote branches is to check whether there are modifications to retrieve.

Checking for modifications and downloading them

The git fetch command is very helpful. To see it at work, create a new file directly on GitHub using the following steps so that we can work with it:

  1. Go to your GitHub dashboard and choose the Pasta branch.
  2. Click the plus icon on the right-hand side of the repository name to add a new file.
    Checking for modifications and downloading them
  3. Add a new empty file, for example, Bucatini-Amatriciana.md, and commit it directly from GitHub:
    Checking for modifications and downloading them

Now, we can make use of git fetch:

Checking for modifications and downloading them

The git fetch command downloads differences from the remote, but does not apply them. With the help of git status, we will see more details:

Checking for modifications and downloading them

As you can see, Git tells us there is one downloaded commit we have to apply to keep our branch in sync with the remote counterpart.

Applying downloaded changes

If push is the verb used to define the upload part of the work, pull is the verb used to describe the action of downloading and applying remote changes. When you pull something from a remote, Git will retrieve all the remote commits made after your last pull from the branch you specify and merge them. Of course, the local destination branch is the branch you are in now (if you don't explicitly specify another one). So, finally, the pull command is the git fetch command plus the git merge command (in the future, you can skip git fetch and use only git pull to merge remote commits).

Now, use the git pull command to merge the brand new Bucatini-Amatriciana.md file committed directly from GitHub:

Applying downloaded changes

Well done! Now, our Pasta branch is in sync with the remote one. We have the Bucatini-Amatriciana.md file in our local branch, ready to be filled.

Just to end this simple example, make some modifications to the new downloaded file and push the commit to GitHub:

Applying downloaded changes

This time we have specified the branch where we want to push changes, so Git avoids reminding us the default git push behavior is going to change in the next release.

Going backward: publish a local repository to GitHub

Often, you will find yourself needing to put your local repository in a shared place where someone else can look at your work. In this section, we will learn how to achieve this.

Create a new local repository to publish by following these simple steps:

  1. Go to our C:Repos folder.
  2. Create a new HelloWorld folder.
  3. Init a new repository, as we did in Chapter 1, Getting Started with Git.
  4. Add a new README.md file and commit it.
    Going backward: publish a local repository to GitHub

Now, create the GitHub repository as we did previously. This time, leave it empty. Don't initialize it with a README.md file; we already have one in our local repository:

Going backward: publish a local repository to GitHub

At this point, we are ready to publish our local repository on GitHub or, more specifically, add a remote to it.

Adding a remote to a local repository

To publish our HelloWorld repository, we simply have to add its first remote. Adding a remote is quite simple: Use the command git remote add origin <remote-repository-url>.

So, type git remote add origin https://github.com/fsantacroce/HelloWorld.git in the Bash shell.

Adding a remote, like adding or modifying other configuration parameters, simply consists of editing some text files in the .git folder. In the next chapter, we will take a look at some of these files.

Pushing a local branch to a remote repository

After adding a remote, push your local changes to the remote using git push -u origin master:

Pushing a local branch to a remote repository

That's all!

Social coding – collaborate using GitHub

GitHub's trademark is the so-called social coding. Right from the beginning, GitHub made it easy to share code, track other people's work, and collaborate using two basic concepts: forks and pull requests. In this section, I will illustrate these concepts in brief.

Forking a repository

Forking is a common concept for a developer. If you have already used a GNU-Linux-based distribution, you would know that there are some forefathers, such as Debian, and some derived distro, such as Ubuntu. They are commonly called the forks of the original distribution.

In GitHub, things are similar. At some point, you will find an interesting open-source project that you want to modify slightly to perfectly fit your needs. At the same time, you want to benefit from bug fixes and new features from the original project, all the time keeping in touch with your work. The right thing to do in this situation is to fork the project.

However, first, remember that fork is not a Git feature, but a GitHub invention. When you fork on GitHub, you get a server-side clone of the repository on your GitHub account. If you clone your forked repository locally in the remote list, you would find the origin alias that points to your account repository. The original repository will generally assume the upstream alias (but this is not automatic, you have to add it manually):

Forking a repository

For your convenience, the right command to add the upstream remote is $ git remote add upstream https://github.com/<original-owner>/<original-repository>.git.

Now, to better understand this feature, go to your GitHub account and try to fork a common GitHub repository called Spoon-Knife, made by the octocat GitHub mascot user. Perform the following steps:

  1. Log in to your GitHub account.
  2. Look for spoon-knife using the search textbox located in the top-left corner of the page:
    Forking a repository
  3. Click on the first result, octocat/Spoon-Knife repository.
  4. Fork the repository using the Fork button at the right of the page:
    Forking a repository
  5. After a funny photocopy animation, you will get a brand new Spoon-Knife repository on your GitHub account:
    Forking a repository

Now, you can clone this repository locally, as we did earlier:

Forking a repository

As you can see, the upstream remote is not present. This is a convention, not a thing that belongs to Git itself. To add this remote, type:

git remote add upstream https://github.com/octocat/Spoon-Knife.git
Forking a repository

Now, you can keep your local repository in sync with the changes in your remote and the origin alias. You can also get changes ones coming from the upstream remote, the original repository you forked. At this point, you are probably wondering how to deal with two different remotes. Well, it is easy. Simply pull from upstream and merge those modifications in your local repository. Then, push them in your origin remote in addition to your changes. If someone else clones your repository, they would receive your work merged with the work done by someone else on the original repository.

Submitting pull requests

If you created a fork of a repository, this is because you are not a direct contributor of the original project or simply because you don't want to make a mess in other people's work before you are familiar with the code.

However, at a certain point, you realize that your work can be useful even for the original project. You realize that you can implement a previous piece of code in a better way, you can add a missing feature, and so on.

So, you find yourself needing to allow the original author to know you did something interesting, to ask them if they want to take a look and, maybe, integrate your work. This is the moment when pull requests come in handy.

A pull request is a way to tell the original author, "Hey! I did something interesting using your original code. Do you want to take a look and integrate my work, if you find it good enough?" This is not only a technical way to achieve the purpose of integrating work, but it is even a powerful practice to promote code reviews (and then the so-called social coding) as recommended by the eXtreme Programming fellows (http://en.wikipedia.org/wiki/Extreme_programming).

One other reason to use a pull request is because you cannot push directly to the upstream remote if you are not a contributor of the original project. Pull requests are the only way. In small scenarios (such as a team of two or three developers that works in the same room), probably, the fork and pull model represents an overhead. So, it is more common to directly share the original repository with all the contributors, skipping the fork and pull ceremony.

Creating a pull request

To create a pull request, you have to go to your GitHub account and make it directly from your forked account. However, first, you have to know that pull requests can be made only from separated branches. At this point of the book, you are probably used to creating a new branch for a new feature or refactor purpose. So, this is nothing new.

To try, let's create a local TeaSpoon branch in our repository, commit a new file, and push it to our GitHub account:

Creating a pull request

If you take a look at your account, you will find a surprise: in your Spoon-Knife repository, there is now a new green button made on purpose to start a pull request:

Creating a pull request

Clicking on this button makes GitHub open a new page where we can adorn our pull request to better support our work. We can let the original author know why we think our work can be useful even in the original project.

However, let me analyze this new page in brief.

In the top-left corner, you will find what branches GitHub is about to compare for you:

Creating a pull request

This means that you are about to compare your local TeaSpoon branch with the original master branch of the octocat user. At the bottom of the page, you can see all the different details (files added, removed, changed, and so on):

Creating a pull request

In the central part of the page, you can describe the work you did in your branch. After that, you have to click on the green Create pull request button to send your request to the original author, allowing him to access your work and analyze it. A green Able to merge sticker on the right-hand side informs you that these two branches can be automatically merged (there are no unresolved conflicts, which is always good to see, considering your work):

Creating a pull request

Now, the last step: click on the Create pull request button and cross your fingers.

Creating a pull request

At this point a new conversation begins. You and the project collaborators can start to discuss your work. During this period, you and other collaborators can change the code to better fit common needs, until an original repository collaborator decides to accept your request or discard it, thus closing the pull request.

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

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