GitHub Workflow

We've used GitHub so far as a tool to backup and restore our work across different machines but always as a single user.

git clone

git init creates a new repository. But often you don't want to create a new repository, but to copy an existing repository. Maybe you want to work on a project at work and or possibly after hours at home(?)

When you want to create a copy of an existing repository, you use the git clone command.

Clone an existing repository

First, visit the Barba-group copy of the "wordcount" repository on GitHub located at https://github.com/barbagroup/wordcount

On the right-hand-side, click the "Clone or Download" button:

clonebutton

Then copy the clone URL (make sure to use HTTPS!):

cloneurl

Now let's clone the repo. In a terminal, do git clone <URL>:

$ git clone https://github.com/barbagroup/wordcount.git
fatal: destination path 'wordcount' already exists and is not an empty directory

ACK. "fatal" is usually a bad sign. What happened? clone, by default, creates a folder with the same name as the repository, so wordcount. But you already have a folder called wordcount (right?), so git won't overwrite that copy (and that's good).

In this case, we can specify a folder name for git to create that doesn't conflict with the existing folder:

$ git clone https://github.com/barbagroup/wordcount.git gil_wordcount
Cloning into 'gil_wordcount'...
remote: Counting objects: 15, done.
remote: Total 15 (delta 0), reused 0 (delta 0), pack-reused 15
Unpacking objects: 100% (15/15), done.

You cloned your first repository! Now cd in and look at the repo history.

$ cd gil_wordcount
$ git log
commit 3f62d8fe59fc6cbded99485a3bebec95e8703a7d
Author: Gil Forsyth <gforsyth@users.noreply.github.com>
Date:   Thu Dec 15 12:06:58 2016 -0500

    Create README.md

commit de8fbc35961f0b7412a8e862e212a50ea0dff7cc
Author: Gil Forsyth <gforsyth@users.noreply.github.com>
Date:   Wed Dec 14 18:02:38 2016 -0500

    Add user-friendly print statement

commit 09633c88bb3f8b40d1c988b1df9004245320462a
Author: Gil Forsyth <gilforsyth@gmail.com>
Date:   Tue Dec 13 11:01:11 2016 -0500

    add helper text to input function

commit 97fba8ddd7685e650813675f5b024267af0b94e7
Author: Gil Forsyth <gilforsyth@gmail.com>
Date:   Tue Dec 13 10:58:59 2016 -0500

    allow user input of statement to word count

commit 47f748fea14e14ed84452a802dc14a5ea0829949
Author: Gil Forsyth <gilforsyth@gmail.com>
Date:   Tue Dec 13 10:53:23 2016 -0500

    Add initial version of word count script

Those are the commits made in the instructor's repository. We have copied the entire history of that repo to our own machine.

Edit the cloned repo

That README.md file is pretty sparse so let's add something to it.

Open README.md in nano and add a greeting, something like "Welcome to the wordcount repo!"

Now save the file, stage it and commit it! (Need a refresher?)

Now push those changes up!

$ git push
Permission denied.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

What happened? We don't have write access to that repository because it doesn't belong to us. It would be a problem if anyone could overwrite a file on GitHub whenever they felt like it.

But how do we propose a change to a repository if we don't have write access?

We fork it!

forks

A fork is a complete copy of an existing git repository under your account. Since it's yours, you now have the ability to make changes to it. Even cooler is that once you've made those changes, you can then propose that they be added back in to the original repository that you forked! This is the main mechanism by which people contribute to other projects on GitHub.

To create a fork, first go to the GitHub page of the repository that you want to fork. If you are in a guided workshop right now, please partner up with someone near you and fork each other's repository. If you are following along on your own, you can use a repository that GitHub has created specifically for this purpose:

Spoon-Knife Repo

To create a fork, click the "Fork" button in the top right of the repo:

fork_button

When you click "Fork", GitHub will take a few moments to create a complete copy of the repository under your control, then it will forward you to that page.

Notice that the username on the new page is your username, but the repo name is the same. Additionally, there will be a link under the repo name indicating that it is a fork of an existing repository.

fork_title

Also note that there is a little info bar right above the file listing:

fork_even

The fork is even with the upstream (original) repo. That means the history is identical. Now let's make a change!

clone your fork

Now that you have created a copy of the repo that you control, go ahead and clone it to your local machine.

As we did earlier, make a small change to the README.md file in nano, then save, stage and commit. Then try again to push your changes back to GitHub.

$ git push
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 349 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local objects.
To github.com:gforsyth/wordcount-1.git
   d0dd1f6..31da785  master -> master

It worked!

Now that we pushed a change to our fork, the fork itself is one commit ahead of the upstream (or original) repository. The history of the two repositories is identical except for the commit that we just created.

Notice that the infobar above the file listing informs us that we are now one commit ahead of the upstream:

fork_one_ahead

Pull Requests

In order to add this commit to the original, we open a pull request to propose adding our change to the original repository.

Note: git is a version control system. GitHub is an online service that provides hosting for git repositories. GitHub also has additional features to help with software collaboration, the most prominent of which is the "Pull Request".

"Pull Requests" are not a feature of git, but of GitHub.

To create a Pull Request, click the link indicated in the figure below.

open_pr

This will open up the following screen:

create_pr

The "base fork" is the upstream location of the repository. It is the original version of the repository that we forked. The "head fork" is our version of the repo, that contains the changes we are proposing to add to the original.

Click "Create Pull Request".

On the following page, write a description of what you are proposing to add to the original project with the changes you have made. In this case, we have made a small, somewhat trivial change. In general, though, it is a good idea to write a detailed description when you open a PR.

You should include a description of the pull request's contents. Are you fixing a bug that you found? Which bug? Are you adding a new feature to an existing project? The more descriptive you are, the easier it is for the maintainers of the original project to determine if they want to accept your contribution.

For the small README change, write a message something like:

"I added a greeting to the README to try to make it a little bit friendlier."

Then click "Create Pull Request" once more to finish.

I opened a pull request, now what?

Once you open a pull request, hopefully a member of the upstream repo will review your proposed changes. Then, they can either accept them, reject them, or request some changes be made before they accept.

This is an example of what a review might look like. There's a specific request to add a newline to the README in between the heading and the greeting.

pr_review

Also note at the bottom that we can add more commits to this PR by pushing them to our fork. If we make the requested change and then push it, this update is immediately reflected on the PR page.

updated_pr

You can see that the new commit and the commit message appear below the comments left by @ncclementi. The chronology of comments, requests and additional commits is preserved in the PR. You can also see that the original comment requesting an extra blank line is now hidden by default, since the file it refers to has been updated since the comment was left.