Collaboration¶
NOTE: using bash/git commands is not fully supported on jupyterlite yet (due to single thread/process restriction), and the cells below might error out on the browser (jupyterlite) version of this notebook
Form a team¶
Now we're going to get to the most important question of all with Git and GitHub: working with others.
Organise into pairs. You're going to be working on the website of one of the two of you, together, so decide who is going to be the leader, and who the collaborator.
Giving permission¶
The leader needs to let the collaborator have the right to make changes to his code.
In GitHub, go to Settings
on the right, then Collaborators & teams
on the left.
Add the user name of your collaborator to the box. They now have the right to push to your repository.
Obtaining a colleague's code¶
Next, the collaborator needs to get a copy of the leader's code. For this example notebook, I'm going to be collaborating with myself, swapping between my two repositories. Make yourself a space to put it your work. (I will have two)
import os
top_dir = os.getcwd()
git_dir = os.path.join(top_dir, 'learning_git')
working_dir = os.path.join(git_dir, 'git_example')
os.chdir(git_dir)
%%bash
pwd
rm -rf partner_repo # cleanup after previous example
Next, the collaborator needs to find out the URL of the repository: they should go to the leader's repository's GitHub page, and note the URL on the top of the screen. Make sure the "ssh" button is pushed, the URL should begin with git@github.com
.
Copy the URL into your clipboard by clicking on the icon to the right of the URL, and then:
%%bash
pwd
git clone git@github.com:UCL/github-example.git partner_repo
partner_dir = os.path.join(git_dir, 'partner_repo')
os.chdir(partner_dir)
%%bash
pwd
ls
Note that your partner's files are now present on your disk:
%%bash
cat lakeland.md
Nonconflicting changes¶
Now, both of you should make some changes. To start with, make changes to different files. This will mean your work doesn't "conflict". Later, we'll see how to deal with changes to a shared file.
Both of you should commit, but not push, your changes to your respective files:
E.g., the leader:
os.chdir(working_dir)
%%writefile Wales.md
Mountains In Wales
==================
* Tryfan
* Yr Wyddfa
%%bash
ls
%%bash
git add Wales.md
git commit -m "Add wales"
And the partner:
os.chdir(partner_dir)
%%writefile Scotland.md
Mountains In Scotland
==================
* Ben Eighe
* Ben Nevis
* Cairngorm
%%bash
ls
%%bash
git add Scotland.md
git commit -m "Add Scotland"
One of you should now push with git push
:
%%bash
git push
Rejected push¶
The other should then push, but should receive an error message:
os.chdir(working_dir)
%%bash --no-raise-error
git push
Do as it suggests. However, we need first to tell git how we want it to act when there are diverging branches (as in this case). We will set the default to be to create a merge commit, then we proceed to pull
.
%%bash
git config --global pull.rebase false
git pull
Merge commits¶
A window may pop up with a suggested default commit message. This commit is special: it is a merge commit. It is a commit which combines your collaborator's work with your own.
Now, push again with git push
. This time it works. If you look on GitHub, you'll now see that it contains both sets of changes.
%%bash
git push
The partner now needs to pull down that commit:
os.chdir(partner_dir)
%%bash
git pull
%%bash
ls
Nonconflicted commits to the same file¶
Go through the whole process again, but this time, both of you should make changes to a single file, but make sure that you don't touch the same line. Again, the merge should work as before:
%%writefile Wales.md
Mountains In Wales
==================
* Tryfan
* Snowdon
%%bash
git diff
%%bash
git add Wales.md
git commit -m "Translating from the Welsh"
%%bash
git log --oneline
os.chdir(working_dir)
%%writefile Wales.md
Mountains In Wales
==================
* Pen y Fan
* Tryfan
* Snowdon
%%bash
git add Wales.md
git commit -m "Add a beacon"
%%bash
git log --oneline
%%bash
git push
Switching back to the other partner...
os.chdir(partner_dir)
%%bash --no-raise-error
git push
%%bash
git pull
%%bash
git push
%%bash
git log --oneline --graph
os.chdir(working_dir)
%%bash
git pull
%%bash
git log --graph --oneline
message="""
participant Palin as P
participant "Palin's repo" as PR
participant "Shared remote" as M
participant "Cleese's repo" as CR
participant Cleese as C
note left of P: git clone
M->PR: fetch commits
PR->P: working directory as at latest commit
note left of P: edit Scotland.md
note right of C: edit Wales.md
git add Scotland.md
note left of P: git commit -m "Add scotland"
P->PR: create commit with Scotland file
git add Wales.md
note right of C: git commit -m "Add wales"
C->CR: create commit with Wales file
note left of P: git push
PR->M: update remote with changes
note right of C: git push
CR-->M: !Rejected change
note right of C: git pull
M->CR: Pull in Palin's last commit, merge histories
CR->C: Add Scotland.md to working directory
note right of C: git push
CR->M: Transfer merged history to remote
"""
from wsd import wsd
%matplotlib inline
wsd(message)
Conflicting commits¶
Finally, go through the process again, but this time, make changes which touch the same line.
%%writefile Wales.md
Mountains In Wales
==================
* Pen y Fan
* Tryfan
* Snowdon
* Fan y Big
%%bash
git add Wales.md
git commit -m "Add another Beacon"
git push
os.chdir(partner_dir)
%%writefile Wales.md
Mountains In Wales
==================
* Pen y Fan
* Tryfan
* Snowdon
* Glyder Fawr
%%bash --no-raise-error
git add Wales.md
git commit -m "Add Glyder"
git push
When you pull, instead of offering an automatic merge commit message, it says:
%%bash --no-raise-error
git pull
Resolving conflicts¶
Git couldn't work out how to merge the two different sets of changes.
You now need to manually resolve the conflict.
It has marked the conflicted area:
%%bash
cat Wales.md
Manually edit the file, to combine the changes as seems sensible and get rid of the symbols:
%%writefile Wales.md
Mountains In Wales
==================
* Pen y Fan
* Tryfan
* Snowdon
* Glyder Fawr
* Fan y Big
Commit the resolved file¶
Now commit the merged result:
%%bash
git add Wales.md
git commit --no-edit # I added a No-edit for this non-interactive session. You can edit the commit if you like.
%%bash
git push
os.chdir(working_dir)
%%bash
git pull
%%bash
cat Wales.md
%%bash
git log --oneline --graph
Distributed VCS in teams with conflicts¶
message="""
participant Palin as P
participant "Palin's repo" as PR
participant "Shared remote" as M
participant "Cleese's repo" as CR
participant Cleese as C
note left of P: edit the same line in wales.md
note right of C: edit the same line in wales.md
note left of P: git add Wales.md
note left of P: git commit -m "update wales.md"
P->PR: add commit to local repo
note right of C: git add Wales.md
note right of C: git commit -m "update wales.md"
C->CR: add commit to local repo
note left of P: git push
PR->M: transfer commit to remote
note right of C: git push
CR->M: !Rejected
note right of C: git pull
M->C: Make conflicted file with conflict markers
note right of C: edit file to resolve conflicts
note right of C: git add wales.md
note right of C: git commit
C->CR: Mark conflict as resolved
note right of C: git push
CR->M: Transfer merged history to remote
note left of P: git pull
M->SR: Download Cleese's resolution of conflict.
"""
wsd(message)
The Levels of Git¶
message="""
Working Directory -> Staging Area : git add
Staging Area -> Local Repository : git commit
Working Directory -> Local Repository : git commit -a
Staging Area -> Working Directory : git checkout
Local Repository -> Staging Area : git reset
Local Repository -> Working Directory: git reset --hard
Local Repository -> Remote Repository : git push
Remote Repository -> Local Repository : git fetch
Local Repository -> Working Directory : git merge
Remote Repository -> Working Directory: git pull
"""
wsd(message)
Editing directly on GitHub¶
Editing directly on GitHub¶
Note that you can also make changes in the GitHub website itself. Visit one of your files, and hit "edit".
Make a change in the edit window, and add an appropriate commit message.
That change now appears on the website, but not in your local copy. (Verify this).
Now pull, and check the change is now present on your local version.
Social Coding¶
GitHub as a social network¶
In addition to being a repository for code, and a way to publish code, GitHub is a social network.
You can follow the public work of other coders: go to the profile of your collaborator in your browser, and hit the "follow" button.
Check out the profiles of Linus Torvalds - creator of git (first git commit ever) and Linux - , Guido van Rossum - creator of Python -, or James Hetherington - the creator of these course notes.
Using GitHub to build up a good public profile of software projects you've worked on is great for your CV!