Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.

Channels ▼


Git Tutorial: Branches and Workflow

This article is the second in a two-part tutorial on using Git. If you've never used Git, you should read the first installment Getting Started with Git: The Fundamentals before starting on this one. In the previous article, I showed how to set up a Git project on GitHub, copy the project's files to a local repository, make changes locally, stage them, and finally push them to the remote repository.

Moving Forward

While we're browsing the Github interface, let's use it to create a change that you can fetch (or pull) to your local Git repository. This will emulate someone else accessing the remote repository and making a change. If you want your local copy of the repository to reflect what's stored in the remote repository, you need to keep yours up-to-date by intermittently fetching new changes. First, let's create a README.md file that Github will automatically use to describe your project. Github provides a button labeled "Add a README" for this, but let's do it the more generic way. Click the "Add a file" button on the GitHub repository

Git Tutorial
Figure 1: Adding a file to the remoted GitHub repository.

Type README.md for the name and a description that makes sense to you. (The "md" in the filename stands for "Markdown," which is a markup language that lets you augment your text with simple formatting. If you want details on how pretty you can make your README file, learn more about Github's version of Markdown. After adding some text, click the "Commit new file" button. You've committed the file to the remote GitHub repository.Go back to your terminal window and type git status.

Git Tutorial
Figure 2: Status after a change to the remote directory.

Git tells you that there's nothing to commit. This is because the Git status command does not do any network communication. Even typing "git log origin/master" won't show the change. Only Git's push, pull, and fetch do anything over the network. Let's talk about fetch, since pull is just a shortcut to some of the functionality that fetch offers.

When you track a remote branch, you do get a copy of that remote branch in your local repository. However, aside from those three aforementioned commands that talk over the network, Git treats these remote branches just like any other branches. (You can even have one local branch track another local branch.)

So, how do we update our local copies of the remote branches? git fetch will update all the local copies of the remote branches listed in your .git/config file. Here is what I get when I type git fetch

Git Tutorial
Figure 3: Output from git fetch.

Now, you'll notice there's still no difference if you type git log, but let's type git log origin/master.

Git Tutorial
Figure 4: How changes appear in the master.

Now you see the remote change.

Let's now merge the change we made on the remote repository with our local repository. In Git, a clean merge like that is called "fast-forwarding." It means there's no potential conflict. Specifically, it means that no changes were made to the branch you're going to merge the changes into. I'll explain more later in the section on rebasing, but for now, we're going to pull these changes in to our local repository. Type: git merge origin/master.

Git Tutorial
Figure 5: Pulling the remote changes from the master to our local branch.

Figure 5 shows there was one file inserted. Now if you typed git log, you'd see that you brought the change first from the master branch on your GitHub repository to your origin/master branch, and then from there to your local master branch. You could even have absolute proof of the change by looking in your current directory, where you'll see the README.md file.

There is a short cut. It's too late now that we've done the merge, but you could have done everything in one fell swoop by typing: git pull origin master.

That would have fetched the commits from the remote repository and done the merge. And if you want to pull all of the branches from all the remote repositories that your .git/config file lists, you can just type: git pull. You can be as trigger happy as you want.

Merges and Conflicts

For the purpose of learning about merges, we're going to undo that last merge. Very carefully, type git reset HEAD~1 --hard.

Git Tutorial
Figure 6: Undoing a merge.

In Figure 6, "HEAD~1" refers to the first commit before the latest commit. The latest commit is referred to as the "HEAD" of the branch (currently master). By doing this hard reset, you're actually permanently erasing the last commit from your local master branch. As far as Git's concerned, the last link in the master branch's "chain" now is the commit that was previously second to last. Don't get in the habit of doing this. It's just for the purpose of this tutorial.

Your new README.md file is also safely committed to your local repository's cached version of the remote master branch, "origin/master." You could type git merge origin/master to remerge your changes, but don't do that right now.

Let's say someone else added that README.md, and you were unaware. You start to create a README.md in your local repository, with the intention of pushing it to the remote repository later. Because we undid our change, there is no longer a README.md file in your current directory. 

Let's quickly create a new README.md file: echo A test repository for learning git > README.md.

I used the cat command (For Windows, it'd be type) to display the contents of the simple file we created to make sure it's right. Now, let's stage and commit it. Type:

git add README.md
git commit -m "Created a simple readme file"
git status

Git Tutorial
Figure 7: Stage and commit.

Note the file was created and that the divergence between repositories has been identified. At present, two versions of a README.md file committed. You can see that your origin/master branch is one commit in one direction, and your master branch is one commit in the other direction. What will happen when I try to update master from origin/master? Type git merge origin/master.

Git Tutorial
Figure 8: Error from a merge.

Just as you might think, Git is flummoxed. This is essentially Git saying "You fix it." Let's see what state we're in. Type git status.

Git Tutorial
Figure 9: Status after a failed merge.

This message can't be any clearer, except for one detail. You have two options at this point. You can either edit the local file to match the original, or you can have Git help you. Let's choose the latter path, which is what you'd always choose with complex conflicts. While still in your project directory, having just experienced a failed merge command, type git mergetool.

Git Tutorial
Figure 10: Output from running git mergetool.

Mergetool will guide you through each conflicted file, letting you choose which version of each conflicted line you'd like to use for the committed file. You can see, by default, it uses opendiff. Press enter to see what opendiff looks like:

Git Tutorial
Figure 11: Opendiff.

If this were a conflict of more than one line, you'd be able to say "use the left (or right) version for this conflict line," or even "I don't want to use either line." In this case, we only have one conflicted line to choose from,. Click on the "Actions" pull down menu and choose "Choose right." You'll see nothing has changed. That's because that arrow in the middle was already pointing to the right. Try selecting "Choose left," then "Choose right" again. You'll see what I mean. Opendiff doesn't give you the opportunity to put in your own custom line. You can do that later if you wish. At the pull down menu at the top of the screen, select "File" then "Save Merge,” go back to the menu and select "Quit FileMerge." Now, to stage the new version of the README file. Type git add README.md.

Related Reading

More Insights

Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.