Average rainfall 2001-2016, global tropics

Map: Average rainfall 2001-2016, global tropics

Forking repositories

Thomas Gumbricht bio photo By Thomas Gumbricht

NOTE, 1 October 2020 the label ‘master’ was replaced by ‘main’ for the default repo branch.

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 then 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 (usually aliased as upstream). 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, upstream repo. The post is inspired by the Youtube Introduction to Git - Remotes by David Mahler. GitHub has 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 SSH, as outlined in the 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. That is not covered in this post.

GitHub fork

You can not push any local changes back to a GitHub repository that you have no 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 to his or hers copy at GitHub.com. The forking as such is done from the source repo and 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 (shown below).

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 (as well as 3 commits). 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-clone-button-4-submodule

In your browser, viewing the Spoon-Knife repo, click on the Code button (previously Clone or Download/span> as in the figure) 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 a 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 remote the command for that is git remote remove [alias].

Sync with upstream

As shown in the post on Remote repositories with 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

The previous posts also introduced the git log with blings attached for displaying a graphical representation of the branches and commits.

$ 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

The 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 command:

$ 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 from upstream are 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/

Either of the branches off master can be used for an initial fast-forward merge, but to merge the second branch to master will require a 3-way merge. 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(-)

The merge was easily accomplished with Fast-forward, even if the branch was from the remote (origin) repository.

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 git push 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 (only master was copied). You have to “clone” these separately. The standard command checkout (see post on Local git control) can be used with the parameter -b to create a local clone 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, it is also 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

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 suggestions for change against the current “downstream” suggestions that reaches upstream. 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 (not git) 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 original repo (to whom you sent the pull request) will be notified and can decide what to do with your request (accept, reject, review or edit etc). 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.

Resources

Youtube tutorial Introduction to Git - Remotes by David Mahler (20180327).

Pro Git - Everything you need to know about git by Scott Chacon and Ben Straub (20200219).