Git implements a distributed version control. This means that any type of repository links that you can think of can be implemented - not just “everything connects to one central server.
Two topologies are very frequent: centralized and forking layout.
In Git, all repositories are equivalent but in the typical centralized style, we consider one repository as the main development line and this is marked as “central”. The “central” is a role, not a technical difference.
Features:
Advantages:
Disadvantages:
In the forking layout, again we call one repository the “central” repository but people push to forks (their own copies of the repository on Github).
Features:
Advantages:
Disadvantages:
origin
. The origin
is just an alias.$ git remote add upstream https://github.com/project/project.git
$ git remote rm upstream
$ git remote add group-repo https://example.com/exciting-project.git
$ git remote rm group-repo
We synchronize remotes via the local clone.
To see all remotes:
$ git remote --verbose
In this exercise, we make a fork, push to that fork, and make a pull request to the master repository. We will run this exercise in groups. Groups can choose a number or a name.
Objectives:
We will do this exercise on GitHub but also GitLab and Bitbucket allow similar workflows and basically everything that we will discuss is transferable.
For this exercise we will fork a different repository compared to earlier today. Please step out of the repository and check that you fork the forking-workflow-exercise.
First fork this repository into your namespace and then clone the fork to your computer.
Here is a pictorial representation of this part:
This is how it looks after we fork:
central:
fork:
After we clone the fork we have three in principle independent repositories:
central:
fork:
local:
Before we do any modification, we create a new branch and switch to it - this is a good reflex and a good practice.
On the new branch add a file group-X.py
where X is your group number or group name, e.g. group-17.py
.
Add only one file per group.
(Why? - if you are adventurous, add both a file with the same name to see what happens)
This file should contain a function called tweet()
which returns
a string of maximum 280 characters, for instance (don’t worry, nothing gets out to Twitter):
def tweet():
return "please replace this boring sentence with something more fun"
The file main.py
automatically calls all tweet()
functions defined in files
group*.py
. You do not need to edit main.py
.
Test it before you commit your change:
$ python main.py
group 17 says: please replace this boring sentence with something more fun
If it works, commit the change. And here is a picture of what just happened:
central:
fork:
local:
Once you see your sentence correctly printed, commit and push the branch to your fork.
Don’t worry nothing gets out to Twitter but please mind that your changes will be public on GitHub (but you can delete them later).
$ git push origin feature
central:
fork:
local:
Then file a pull request from the branch on your fork towards the master branch on the repository where you forked from.
Here is a pictorial representation for parts C and D:
A pull-request means: “please review my changes and if you agree, merge them with a mouse-click”.
Once the pull-request is accepted, the change is merged:
central:
fork:
local:
Wait here until we integrate all pull requests into the central repo together on the big screen.
We do this part after the contributions from all groups have been integrated.
Once this is done, practice to update your forked repo with the upstream changes and verify that you got the files created by other groups:
$ python main.py
Make sure that the contributions from other groups are not only on your local repository but really also end up in your fork.
Here is a pictorial representation of this part:
We will discuss two solutions:
$ git remote add upstream https://github.com/KTH-dESA/forking-workflow-exercise.git
$ git fetch upstream
central:
fork:
local:
$ git checkout master
$ git merge upstream/master
central:
fork:
local:
$ git push origin master
central:
fork:
local:
Remotes are aliases. We can use remote URLs directly.
Here we pull from the central repo and push to our fork:
$ git checkout master
$ git pull https://github.com/KTH-dESA/forking-workflow-exercise.git master
$ git push https://github.com/user/forking-workflow-exercise.git master
Use Different URLs for fetch and push. Makes sense if you are the only person pushing to the fork:
$ git remote add origin https://github.com/project/project.git
$ git remote set-url --push origin https://github.com/user/project.git
Now we always fetch from the central repo and push to forked repo.
$ git remote -v
origin https://github.com/project/project.git (fetch)
origin https://github.com/user/project.git (push)
(from Star Wars Episode IV - A New Hope)
In GitHub or BitBucket asking someone to bring code from a forked repo or branch to the main repo is called a pull request. In GitLab it is called a merge request. Which one do you feel is more appropriate and in which context?
Motivation:
Working with multiple remotes is not as scary as it looks.
origin
is just an alias.
We can add and remove remotes.
We can call these aliases as we like.
We synchronize remotes via the local clone.
To see all remotes use git remote -v
.
If you are more than one person contributing to a project, implement code review.