Average rainfall 2001-2016, global tropics

Map: Average rainfall 2001-2016, global tropics

Forking repositories

Thomas Gumbricht bio photo By Thomas Gumbricht

Introduction

In the online GitHub version control system (VCS) you can duplicate, or fork, any existing public repository to your own user. Further, you can clone the fork that resides in your GitHub user and work with it on your local machine while also keeping in sync with changes made in the original source. These are very powerful tools for developing your own projects using parts collected from all over GitHub.

This post covers how to fork an online, public GiHub project, create a local clone and keep both the local clone and the online fork in sync with each other and in sync with the original repo. The post is inspired by the Youtube Introduction to Git - Remotes by David Mahler. GitHub also have its own introduction to Forking Projects that also offers the the Spoon-Knife project for use when learning to fork.

Prerequisits

You have to have a GitHub account, preferably set up to allow access using a SSH, as outlined in the parallel post on Remote repositories with GitHub. You must also identify an online account with a public repo that you can fork - for instance the the Spoon-Knife project setup specifically for this purpose. If you want to try to make live updates from an original repo after it has changed, you need to create two online repos at GitHub that you can control.

GitHub fork

You can not push any local changes back to a GitHub repository that you have not rights to, even if it is public. But GitHub allows you to fork any public repo which is the same thing as creating an identical copy (or clone). The user performing the fork will then become the owner of the copy, allowing the new user to push changes. The forking is done from the source repo and it is cloned into the account of the logged in user.

Open your web-browser and log in to GitHub. You must be logged in order to fork Open a new browser window and navigate to the the Spoon-Knife project. Even if you are watching the Spoon-Knife project, you are still logged in as your own user.

Github - the Spoon-Knife project.

github-dismiss-github-action-popup

To fork a project to your own account, just click the Fork button (shown to the left). The forking will take a few seconds, or more for large repos, and then your browser will show the copy of the forked repo in your own account. Note the small forked icon in front of the account name.

Github - the Spoon-Knife project forked to another account.

github-spoon-knife-project-branches

Note that the project (or repo) includes 3 branches. If you click on the button indicating the current branch Branch: master, a dropdown menu appears and tells you the other branches, as well as gives you the option of creating further branches. We are going to return to these branches later in this post.



Clone forked account

You can now clone the forked repo to your local machine much in the same way as you cloned your own original repo in the parallel post on Remote repositories with GitHub.

github-dismiss-github-action-popup

In your browser, viewing the Spoon-Knife repo, click on the Clone or Download button and copy the SSH based location string, as shown to the right.

Return to your Terminal window, cd to the parent folder where you want save the clone of the Spoon-Knife project, and git clone with the SSH link pasted:

$ git clone git@github.com:thomasgumbricht/Spoon-Knife.git

Cloning into 'Spoon-Knife'...
remote: Enumerating objects: 16, done.
remote: Total 16 (delta 0), reused 0 (delta 0), pack-reused 16
Receiving objects: 100% (16/16), done.
Resolving deltas: 100% (3/3), done.

git remote

cd into the cloned directory:

$ cd Spoon-Knife

Check out the remote connections of the repo:

$ git remote -v

origin	git@github.com:thomasgumbricht/Spoon-Knife.git (fetch)
origin	git@github.com:thomasgumbricht/Spoon-Knife.git (push)

Note that the default remote (named origin) link is with your (my) own account, not the account where the original project resided.

git remote add upstream

You now have a (static) copy of the forked project (Spoon-Knife) in your GitHub online account and clone of your own copy on your local machine. But you are detached from any updates done in the original repository (of Spoon-Knife). You can solve that, not via the online GitHub account, but using your local account. You accomplish that by adding another remote. When this remote is the parent of a fork residing as a clone in the repo itself (like in this case), the conventions is to call this remote “upstream”.

To create the required command you must first return to the parent repo of your fork, the Spoon-Knife project to grab the SSH path to call at the command line. Then execute the command:

$ git remote add upstream https://github.com/octocat/Spoon-Knife.git

To check out if this had any effect:

$ git remote -v

origin	git@github.com:thomasgumbricht/Spoon-Knife.git (fetch)
origin	git@github.com:thomasgumbricht/Spoon-Knife.git (push)
upstream	https://github.com/octocat/Spoon-Knife.git (fetch)
upstream	https://github.com/octocat/Spoon-Knife.git (push)

Aside from you primary remote repo (origin) your local repo is also linked to another repo under the alias upstream.

If you want to remove a remite the command for that is git remote remove [alias]</alias>

Sync with upstream

As shown in the parallel post on parallel post on [Remote repositories with GitHub](../blog-git-github you can check if you are in sync with a remote repo using git log or git status:

$ git status

On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

$ git log –all –decorate –oneline –graph

* f439fc5 (origin/change-the-title) Update README.md
| * 5806070 (origin/test-branch) Create test.md
|/  
* d0dd1f6 (HEAD -> master, origin/master, origin/HEAD) Pointing to the guide for forking
* bb4cc8d Create styles.css and updated README
* a30c19e Created index page for future collaborative edit

This message reveals that we have several branches in the remote (origin) repo:

  • origin/master
  • origin/test-branch
  • origin/change-the-title

That our local master is in sync with with origin/master but behind the other branches. Neither the status not the log message reveal anything about the other remote repo, upstream. To access the status of upstream you first have to run the comamnd:

$ git fetch upstream

From https://github.com/octocat/Spoon-Knife
 * [new branch]      change-the-title -> upstream/change-the-title
 * [new branch]      master           -> upstream/master
 * [new branch]      test-branch      -> upstream/test-branch

If rerun git status the message will be the same as last time, but if you rerun log:

$ git log –all –decorate –oneline –graph

* f439fc5 (upstream/change-the-title, origin/change-the-title) Update README.md
| * 5806070 (upstream/test-branch, origin/test-branch) Create test.md
|/  
* d0dd1f6 (HEAD -> master, upstream/master, origin/master, origin/HEAD) Pointing to the guide for forking
* bb4cc8d Create styles.css and updated README
* a30c19e Created index page for future collaborative edits

you see that all branches and commits form upstream and in sync with the corresponding branches/commits from origin. You have successfully connected and fetched documents from the original remote repo, that you gave the alias upstream.

git merge

Inspect the branches of your project (as for now all 3 versions are in sync upstream, origin and you local clone):

* f439fc5 (upstream/change-the-title, origin/change-the-title) Update README.md
| * 5806070 (upstream/test-branch, origin/test-branch) Create test.md
|/  
* d0dd1f6 (HEAD -> master, upstream/master, origin/

Both the branches off master can be used for a fast-forward merge, but must then be followed by a 3-way merge - if you want to assemble all edits into master. This should be done locally. Start by merging the branch change-the-title into master:

$ git merge origin/change-the-title

Updating d0dd1f6..f439fc5
Fast-forward
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

git push and git push delete

You can now delete the upstream branch change-the-title:

git push origin --delete change-the-title

To github.com:thomasgumbricht/Spoon-Knife.git
 - [deleted]         change-the-title

If you return to your browser and refresh the view over your online GitHub repo Spoon-Knife, you will see that now there are only 2 branches.

Github - the Spoon-Knife project with fewer branches.

If you check status:

$ git status

On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

git will notify you that you are one commit ahead locally compared to origin/master, and how to <span class=terminalapp>git push</span> to get in sync:

$ git push

Total 0 (delta 0), reused 0 (delta 0)
To github.com:thomasgumbricht/Spoon-Knife.git
   d0dd1f6..f439fc5  master -> master

git tracking

You might already have noted that the remote branches did not clone to your local machine. You have to “clone” these separately. The standard command checkout (see post on ) can be used with the parameter -b to create a local conte tracking a remote branch git checkout -b [branch] [remotename]/[branch]:

$ git checkout -b test-branch origin/test-branch

If your new branch shall have the same name as the remote branch, you can shorten this to:

$ git checkout –track origin/test-branch

A third alternative is to first create a local branch, and then attach it to tracking the remote branch:

$ git branch test-branch
git checkout test-branch
git branch –set-upstream-to origin/test-branch

Use one of the alternatives above to create a local branch that tracks the branch test-branch at origin, then run the extended git log command:

$ git log –all –decorate –oneline –graph

* f439fc5 (upstream/change-the-title, master) Update README.md
| * 5806070 (HEAD -> test-branch, upstream/test-branch, origin/test-branch) Create test.md
|/  
* d0dd1f6 (upstream/master, origin/master, origin/HEAD) Pointing to the guide for forking
* bb4cc8d Create styles.css and updated README
* a30c19e Created index page for future collaborative edits

You can also check you local branches with the command:

$ git branch

master
* test-branch

The local branch test-branch is now included, and the active branch. Let us try to merge it with the local master:

$ git branch checkout master
$ git merge test-branch

Merge made by the 'recursive' strategy.
 test.md | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 test.md

With another successful merge completed, you can delete the branch. But this time you have a local branch that is tracking a remote branch. To delete the tracking, use the command:

$ git branch -delete -remote origin/test-branch or $ git branch -dr origin/test-branch

Deleted remote-tracking branch origin/test-branch (was 5806070).

And then delete the local branch itself:

$ git branch -d test-branch

Deleted branch test-branch (was 5806070).

Now you can also delete the remote branch at origin:

$ git push origin –delete test-branch

To github.com:thomasgumbricht/Spoon-Knife.git
 - [deleted]         test-branch

Remember to push the changes form you local repo to the online origin:

$ git push

Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 4 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 297 bytes | 297.00 KiB/s, done.
Total 2 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To github.com:thomasgumbricht/Spoon-Knife.git
   f439fc5..6a4b7e8  master -> master

If you check

$ git status

On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

and if you check your online GitHub repo (Spoon-Knife) there should only be only one branch: master.

git branch

The standard command git branch returns a list of the local branches, with a star * indicating the active branch. To instead inspect remote branches, add the parameter -r:

$ git branch -r

and to inspect both local and remote (all, -a)

$ git branch -a

Sync with upstream

As you have no rights to edit or change the upstrem project, you can not infer any changes. Neither can you react to any “downstream” suggestions for changes. To fully test the links between GitHub and git for these kinds of version control you need to get two separate GitHub accounts that you control. I will not cover that fully in this tutorial, just outline the principle steps.

Sync from upstream

First update for any commits that have occurred in upstream, otherwise they will not be recorded in your local history tree.

$ git fetch upstream

Inspect the relation between upstream and your local clone, for example with the extended log command:

$ git log –all –decorate –oneline –graph

If the local master is behind upstream/master run a merge from your local master:

$ git branch checkout master
$ git merge upstream/master

You local repo master branch is now in sync with upstream/master, but the GitHub fork is still behind, which you an confirm with another git log command:

$ git log –all –decorate –oneline –graph

To sync the online fork, push the merged local master to origin/master

$ git push origin master

Pull requests

A pull request is a GitHub specific command that notifies the fork origin account of proposed changes. Before sending a pull request, you need to do some edits or changes (otherwise you have nothing to suggest). The best way to go about that is to create a new branch that holds the edits or changes.

Create new branch

The process of proposing changes usually starts at you local clone of the forked repo. Thus, in your Terminal window pointing towards your local clone of the the Spoon-Knife project, create a new branch:

$ git checkout -b “edit-index”

Switched to a new branch 'edit-index'

Do some edit that you also save in the file index.html

commit the changes to the branch edit-index:

$ git commit -am “update index.html”

[edit-index 8b19037] update index.html
 1 file changed, 1 insertion(+)

Your local repo will now be ahead of, and out of sync with your forked GitHub repo (with the alias origin). Push the changes to origin:

$ git push origin edit-index

Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 4 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 322 bytes | 322.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
remote:
remote: Create a pull request for 'edit-index' on GitHub by visiting:
remote:      https://github.com/thomasgumbricht/Spoon-Knife/pull/new/edit-index
remote:
To github.com:thomasgumbricht/Spoon-Knife.git
 * [new branch]      edit-index -> edit-index

Pull requests

github-branch-button-menu-edit-index

Return to your online GitHub account. it should now have 2 branches. Change to the branch edit-index via the button that says Branch: Master.

The latest registered commit is the “update index.html”. GitHub also tells you that the branch is 4 commits ahead of the source of the fork.

Github - the branch with your edits of the forked project.

guthub-button-new-pull-request

You can now create a “New pull request”, by clicking the button for that (illustrated to the right). That will take you to the GitHub repo that is the origin of the fork displaying a “Comparing pages” window. As the project you have tested out, the the Spoon-Knife project was created as a test-project it is full of older pull requests.

Github - Comparing changes in pull requests.

To actually generate a pull request for the owner of the account, click the Create pull request button. To send the request you have to fill in the textboxes for title and Comment and then click Create pull request.

Github - Open a pull request.

The maintainers of the repo can now decide what to do with your request (accept or reject). Dependent on what actions are taken you can then choose to delete the branch with your suggested edits, continue with your own development, or try to alter your edits to get them accepted (if rejected), etc.