XClose

MPHY0021: Research Software Engineering With Python

Home
Menu

Collaboration

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)

In [1]:
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)
In [2]:
%%bash
pwd
rm -rf github-example # cleanup after previous example
rm -rf partner_repo # cleanup after previous example
/home/runner/work/rsd-engineeringcourse/rsd-engineeringcourse/ch02git/learning_git

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:

In [3]:
%%bash
pwd
git clone git@github.com:UCL/github-example.git partner_repo
/home/runner/work/rsd-engineeringcourse/rsd-engineeringcourse/ch02git/learning_git
Cloning into 'partner_repo'...
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
/tmp/ipykernel_9923/213080341.py in <module>
----> 1 get_ipython().run_cell_magic('bash', '', 'pwd\ngit clone git@github.com:UCL/github-example.git partner_repo\n')

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/interactiveshell.py in run_cell_magic(self, magic_name, line, cell)
   2417             with self.builtin_trap:
   2418                 args = (magic_arg_s, cell)
-> 2419                 result = fn(*args, **kwargs)
   2420             return result
   2421 

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in named_script_magic(line, cell)
    140             else:
    141                 line = script
--> 142             return self.shebang(line, cell)
    143 
    144         # write a basic docstring:

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/decorator.py in fun(*args, **kw)
    230             if not kwsyntax:
    231                 args, kw = fix(args, kw, sig)
--> 232             return caller(func, *(extras + args), **kw)
    233     fun.__name__ = func.__name__
    234     fun.__doc__ = func.__doc__

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magic.py in <lambda>(f, *a, **k)
    185     # but it's overkill for just that one bit of state.
    186     def magic_deco(arg):
--> 187         call = lambda f, *a, **k: f(*a, **k)
    188 
    189         if callable(arg):

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in shebang(self, line, cell)
    243             sys.stderr.flush()
    244         if args.raise_error and p.returncode!=0:
--> 245             raise CalledProcessError(p.returncode, cell, output=out, stderr=err)
    246 
    247     def _run_script(self, p, cell, to_close):

CalledProcessError: Command 'b'pwd\ngit clone git@github.com:UCL/github-example.git partner_repo\n'' returned non-zero exit status 128.
In [4]:
partner_dir = os.path.join(git_dir, 'partner_repo')
os.chdir(partner_dir)
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
/tmp/ipykernel_9923/2040552695.py in <module>
      1 partner_dir = os.path.join(git_dir, 'partner_repo')
----> 2 os.chdir(partner_dir)

FileNotFoundError: [Errno 2] No such file or directory: '/home/runner/work/rsd-engineeringcourse/rsd-engineeringcourse/ch02git/learning_git/partner_repo'
In [5]:
%%bash
pwd
ls
/home/runner/work/rsd-engineeringcourse/rsd-engineeringcourse/ch02git/learning_git
git_example

Note that your partner's files are now present on your disk:

In [6]:
%%bash
cat lakeland.md
cat: lakeland.md: No such file or directory
---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
/tmp/ipykernel_9923/560186327.py in <module>
----> 1 get_ipython().run_cell_magic('bash', '', 'cat lakeland.md\n')

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/interactiveshell.py in run_cell_magic(self, magic_name, line, cell)
   2417             with self.builtin_trap:
   2418                 args = (magic_arg_s, cell)
-> 2419                 result = fn(*args, **kwargs)
   2420             return result
   2421 

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in named_script_magic(line, cell)
    140             else:
    141                 line = script
--> 142             return self.shebang(line, cell)
    143 
    144         # write a basic docstring:

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/decorator.py in fun(*args, **kw)
    230             if not kwsyntax:
    231                 args, kw = fix(args, kw, sig)
--> 232             return caller(func, *(extras + args), **kw)
    233     fun.__name__ = func.__name__
    234     fun.__doc__ = func.__doc__

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magic.py in <lambda>(f, *a, **k)
    185     # but it's overkill for just that one bit of state.
    186     def magic_deco(arg):
--> 187         call = lambda f, *a, **k: f(*a, **k)
    188 
    189         if callable(arg):

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in shebang(self, line, cell)
    243             sys.stderr.flush()
    244         if args.raise_error and p.returncode!=0:
--> 245             raise CalledProcessError(p.returncode, cell, output=out, stderr=err)
    246 
    247     def _run_script(self, p, cell, to_close):

CalledProcessError: Command 'b'cat lakeland.md\n'' returned non-zero exit status 1.

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:

In [7]:
os.chdir(working_dir)
In [8]:
%%writefile Wales.md
Mountains In Wales
==================

* Tryfan
* Yr Wyddfa
Writing Wales.md
In [9]:
%%bash
ls
Wales.md
__pycache__
index.md
lakeland.md
wsd.py
In [10]:
%%bash
git add Wales.md
git commit -m "Add wales"
[master 480039f] Add wales
 1 file changed, 5 insertions(+)
 create mode 100644 Wales.md

And the partner:

In [11]:
os.chdir(partner_dir)
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
/tmp/ipykernel_9923/3492456231.py in <module>
----> 1 os.chdir(partner_dir)

FileNotFoundError: [Errno 2] No such file or directory: '/home/runner/work/rsd-engineeringcourse/rsd-engineeringcourse/ch02git/learning_git/partner_repo'
In [12]:
%%writefile Scotland.md
Mountains In Scotland
==================

* Ben Eighe
* Cairngorm
Writing Scotland.md
In [13]:
%%bash
ls
Scotland.md
Wales.md
__pycache__
index.md
lakeland.md
wsd.py
In [14]:
%%bash
git add Scotland.md
git commit -m "Add Scotland"
[master 976f55c] Add Scotland
 1 file changed, 5 insertions(+)
 create mode 100644 Scotland.md

One of you should now push with git push:

In [15]:
%%bash
git push
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin master

---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
/tmp/ipykernel_9923/3471985758.py in <module>
----> 1 get_ipython().run_cell_magic('bash', '', 'git push\n')

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/interactiveshell.py in run_cell_magic(self, magic_name, line, cell)
   2417             with self.builtin_trap:
   2418                 args = (magic_arg_s, cell)
-> 2419                 result = fn(*args, **kwargs)
   2420             return result
   2421 

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in named_script_magic(line, cell)
    140             else:
    141                 line = script
--> 142             return self.shebang(line, cell)
    143 
    144         # write a basic docstring:

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/decorator.py in fun(*args, **kw)
    230             if not kwsyntax:
    231                 args, kw = fix(args, kw, sig)
--> 232             return caller(func, *(extras + args), **kw)
    233     fun.__name__ = func.__name__
    234     fun.__doc__ = func.__doc__

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magic.py in <lambda>(f, *a, **k)
    185     # but it's overkill for just that one bit of state.
    186     def magic_deco(arg):
--> 187         call = lambda f, *a, **k: f(*a, **k)
    188 
    189         if callable(arg):

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in shebang(self, line, cell)
    243             sys.stderr.flush()
    244         if args.raise_error and p.returncode!=0:
--> 245             raise CalledProcessError(p.returncode, cell, output=out, stderr=err)
    246 
    247     def _run_script(self, p, cell, to_close):

CalledProcessError: Command 'b'git push\n'' returned non-zero exit status 128.

Rejected push

The other should then push, but should receive an error message:

In [16]:
os.chdir(working_dir)
In [17]:
%%bash --no-raise-error
git push
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin master

Do as it suggests:

In [18]:
%%bash
git pull
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
/tmp/ipykernel_9923/3022008257.py in <module>
----> 1 get_ipython().run_cell_magic('bash', '', 'git pull\n')

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/interactiveshell.py in run_cell_magic(self, magic_name, line, cell)
   2417             with self.builtin_trap:
   2418                 args = (magic_arg_s, cell)
-> 2419                 result = fn(*args, **kwargs)
   2420             return result
   2421 

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in named_script_magic(line, cell)
    140             else:
    141                 line = script
--> 142             return self.shebang(line, cell)
    143 
    144         # write a basic docstring:

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/decorator.py in fun(*args, **kw)
    230             if not kwsyntax:
    231                 args, kw = fix(args, kw, sig)
--> 232             return caller(func, *(extras + args), **kw)
    233     fun.__name__ = func.__name__
    234     fun.__doc__ = func.__doc__

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magic.py in <lambda>(f, *a, **k)
    185     # but it's overkill for just that one bit of state.
    186     def magic_deco(arg):
--> 187         call = lambda f, *a, **k: f(*a, **k)
    188 
    189         if callable(arg):

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in shebang(self, line, cell)
    243             sys.stderr.flush()
    244         if args.raise_error and p.returncode!=0:
--> 245             raise CalledProcessError(p.returncode, cell, output=out, stderr=err)
    246 
    247     def _run_script(self, p, cell, to_close):

CalledProcessError: Command 'b'git pull\n'' returned non-zero exit status 1.

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.

In [19]:
%%bash
git push
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin master

---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
/tmp/ipykernel_9923/3471985758.py in <module>
----> 1 get_ipython().run_cell_magic('bash', '', 'git push\n')

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/interactiveshell.py in run_cell_magic(self, magic_name, line, cell)
   2417             with self.builtin_trap:
   2418                 args = (magic_arg_s, cell)
-> 2419                 result = fn(*args, **kwargs)
   2420             return result
   2421 

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in named_script_magic(line, cell)
    140             else:
    141                 line = script
--> 142             return self.shebang(line, cell)
    143 
    144         # write a basic docstring:

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/decorator.py in fun(*args, **kw)
    230             if not kwsyntax:
    231                 args, kw = fix(args, kw, sig)
--> 232             return caller(func, *(extras + args), **kw)
    233     fun.__name__ = func.__name__
    234     fun.__doc__ = func.__doc__

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magic.py in <lambda>(f, *a, **k)
    185     # but it's overkill for just that one bit of state.
    186     def magic_deco(arg):
--> 187         call = lambda f, *a, **k: f(*a, **k)
    188 
    189         if callable(arg):

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in shebang(self, line, cell)
    243             sys.stderr.flush()
    244         if args.raise_error and p.returncode!=0:
--> 245             raise CalledProcessError(p.returncode, cell, output=out, stderr=err)
    246 
    247     def _run_script(self, p, cell, to_close):

CalledProcessError: Command 'b'git push\n'' returned non-zero exit status 128.

The partner now needs to pull down that commit:

In [20]:
os.chdir(partner_dir)
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
/tmp/ipykernel_9923/3492456231.py in <module>
----> 1 os.chdir(partner_dir)

FileNotFoundError: [Errno 2] No such file or directory: '/home/runner/work/rsd-engineeringcourse/rsd-engineeringcourse/ch02git/learning_git/partner_repo'
In [21]:
%%bash
git pull
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
/tmp/ipykernel_9923/3022008257.py in <module>
----> 1 get_ipython().run_cell_magic('bash', '', 'git pull\n')

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/interactiveshell.py in run_cell_magic(self, magic_name, line, cell)
   2417             with self.builtin_trap:
   2418                 args = (magic_arg_s, cell)
-> 2419                 result = fn(*args, **kwargs)
   2420             return result
   2421 

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in named_script_magic(line, cell)
    140             else:
    141                 line = script
--> 142             return self.shebang(line, cell)
    143 
    144         # write a basic docstring:

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/decorator.py in fun(*args, **kw)
    230             if not kwsyntax:
    231                 args, kw = fix(args, kw, sig)
--> 232             return caller(func, *(extras + args), **kw)
    233     fun.__name__ = func.__name__
    234     fun.__doc__ = func.__doc__

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magic.py in <lambda>(f, *a, **k)
    185     # but it's overkill for just that one bit of state.
    186     def magic_deco(arg):
--> 187         call = lambda f, *a, **k: f(*a, **k)
    188 
    189         if callable(arg):

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in shebang(self, line, cell)
    243             sys.stderr.flush()
    244         if args.raise_error and p.returncode!=0:
--> 245             raise CalledProcessError(p.returncode, cell, output=out, stderr=err)
    246 
    247     def _run_script(self, p, cell, to_close):

CalledProcessError: Command 'b'git pull\n'' returned non-zero exit status 1.
In [22]:
%%bash
ls
Scotland.md
Wales.md
__pycache__
index.md
lakeland.md
wsd.py

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:

In [23]:
%%writefile Wales.md
Mountains In Wales
==================

* Tryfan
* Snowdon
Overwriting Wales.md
In [24]:
%%bash
git diff
diff --git a/Wales.md b/Wales.md
index f3e88b4..90f23ec 100644
--- a/Wales.md
+++ b/Wales.md
@@ -2,4 +2,4 @@ Mountains In Wales
 ==================
 
 * Tryfan
-* Yr Wyddfa
+* Snowdon
In [25]:
%%bash
git commit -am "Translating from the Welsh"
[master 380d1f1] Translating from the Welsh
 1 file changed, 1 insertion(+), 1 deletion(-)
In [26]:
%%bash
git log --oneline
380d1f1 Translating from the Welsh
976f55c Add Scotland
480039f Add wales
a77a766 Add Helvellyn
e95fb6e Include lakes in the scope
e87cd77 Add lakeland
74a8ea7 Revert "Add a lie about a mountain"
c730d31 Change title
d94bbd3 Add a lie about a mountain
c26b924 First commit of discourse on UK topography
In [27]:
os.chdir(working_dir)
In [28]:
%%writefile Wales.md
Mountains In Wales
==================

* Pen y Fan
* Tryfan
* Snowdon
Overwriting Wales.md
In [29]:
%%bash
git commit -am "Add a beacon"
[master 94628af] Add a beacon
 1 file changed, 1 insertion(+)
In [30]:
%%bash
git log --oneline
94628af Add a beacon
380d1f1 Translating from the Welsh
976f55c Add Scotland
480039f Add wales
a77a766 Add Helvellyn
e95fb6e Include lakes in the scope
e87cd77 Add lakeland
74a8ea7 Revert "Add a lie about a mountain"
c730d31 Change title
d94bbd3 Add a lie about a mountain
c26b924 First commit of discourse on UK topography
In [31]:
%%bash
git push
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin master

---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
/tmp/ipykernel_9923/3471985758.py in <module>
----> 1 get_ipython().run_cell_magic('bash', '', 'git push\n')

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/interactiveshell.py in run_cell_magic(self, magic_name, line, cell)
   2417             with self.builtin_trap:
   2418                 args = (magic_arg_s, cell)
-> 2419                 result = fn(*args, **kwargs)
   2420             return result
   2421 

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in named_script_magic(line, cell)
    140             else:
    141                 line = script
--> 142             return self.shebang(line, cell)
    143 
    144         # write a basic docstring:

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/decorator.py in fun(*args, **kw)
    230             if not kwsyntax:
    231                 args, kw = fix(args, kw, sig)
--> 232             return caller(func, *(extras + args), **kw)
    233     fun.__name__ = func.__name__
    234     fun.__doc__ = func.__doc__

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magic.py in <lambda>(f, *a, **k)
    185     # but it's overkill for just that one bit of state.
    186     def magic_deco(arg):
--> 187         call = lambda f, *a, **k: f(*a, **k)
    188 
    189         if callable(arg):

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in shebang(self, line, cell)
    243             sys.stderr.flush()
    244         if args.raise_error and p.returncode!=0:
--> 245             raise CalledProcessError(p.returncode, cell, output=out, stderr=err)
    246 
    247     def _run_script(self, p, cell, to_close):

CalledProcessError: Command 'b'git push\n'' returned non-zero exit status 128.

Switching back to the other partner...

In [32]:
os.chdir(partner_dir)
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
/tmp/ipykernel_9923/3492456231.py in <module>
----> 1 os.chdir(partner_dir)

FileNotFoundError: [Errno 2] No such file or directory: '/home/runner/work/rsd-engineeringcourse/rsd-engineeringcourse/ch02git/learning_git/partner_repo'
In [33]:
%%bash --no-raise-error
git push
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin master

In [34]:
%%bash
git pull
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
/tmp/ipykernel_9923/3022008257.py in <module>
----> 1 get_ipython().run_cell_magic('bash', '', 'git pull\n')

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/interactiveshell.py in run_cell_magic(self, magic_name, line, cell)
   2417             with self.builtin_trap:
   2418                 args = (magic_arg_s, cell)
-> 2419                 result = fn(*args, **kwargs)
   2420             return result
   2421 

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in named_script_magic(line, cell)
    140             else:
    141                 line = script
--> 142             return self.shebang(line, cell)
    143 
    144         # write a basic docstring:

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/decorator.py in fun(*args, **kw)
    230             if not kwsyntax:
    231                 args, kw = fix(args, kw, sig)
--> 232             return caller(func, *(extras + args), **kw)
    233     fun.__name__ = func.__name__
    234     fun.__doc__ = func.__doc__

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magic.py in <lambda>(f, *a, **k)
    185     # but it's overkill for just that one bit of state.
    186     def magic_deco(arg):
--> 187         call = lambda f, *a, **k: f(*a, **k)
    188 
    189         if callable(arg):

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in shebang(self, line, cell)
    243             sys.stderr.flush()
    244         if args.raise_error and p.returncode!=0:
--> 245             raise CalledProcessError(p.returncode, cell, output=out, stderr=err)
    246 
    247     def _run_script(self, p, cell, to_close):

CalledProcessError: Command 'b'git pull\n'' returned non-zero exit status 1.
In [35]:
%%bash
git push
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin master

---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
/tmp/ipykernel_9923/3471985758.py in <module>
----> 1 get_ipython().run_cell_magic('bash', '', 'git push\n')

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/interactiveshell.py in run_cell_magic(self, magic_name, line, cell)
   2417             with self.builtin_trap:
   2418                 args = (magic_arg_s, cell)
-> 2419                 result = fn(*args, **kwargs)
   2420             return result
   2421 

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in named_script_magic(line, cell)
    140             else:
    141                 line = script
--> 142             return self.shebang(line, cell)
    143 
    144         # write a basic docstring:

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/decorator.py in fun(*args, **kw)
    230             if not kwsyntax:
    231                 args, kw = fix(args, kw, sig)
--> 232             return caller(func, *(extras + args), **kw)
    233     fun.__name__ = func.__name__
    234     fun.__doc__ = func.__doc__

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magic.py in <lambda>(f, *a, **k)
    185     # but it's overkill for just that one bit of state.
    186     def magic_deco(arg):
--> 187         call = lambda f, *a, **k: f(*a, **k)
    188 
    189         if callable(arg):

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in shebang(self, line, cell)
    243             sys.stderr.flush()
    244         if args.raise_error and p.returncode!=0:
--> 245             raise CalledProcessError(p.returncode, cell, output=out, stderr=err)
    246 
    247     def _run_script(self, p, cell, to_close):

CalledProcessError: Command 'b'git push\n'' returned non-zero exit status 128.
In [36]:
%%bash
git log --oneline --graph
* 94628af Add a beacon
* 380d1f1 Translating from the Welsh
* 976f55c Add Scotland
* 480039f Add wales
* a77a766 Add Helvellyn
* e95fb6e Include lakes in the scope
* e87cd77 Add lakeland
* 74a8ea7 Revert "Add a lie about a mountain"
* c730d31 Change title
* d94bbd3 Add a lie about a mountain
* c26b924 First commit of discourse on UK topography
In [37]:
os.chdir(working_dir)
In [38]:
%%bash
git pull
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
/tmp/ipykernel_9923/3022008257.py in <module>
----> 1 get_ipython().run_cell_magic('bash', '', 'git pull\n')

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/interactiveshell.py in run_cell_magic(self, magic_name, line, cell)
   2417             with self.builtin_trap:
   2418                 args = (magic_arg_s, cell)
-> 2419                 result = fn(*args, **kwargs)
   2420             return result
   2421 

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in named_script_magic(line, cell)
    140             else:
    141                 line = script
--> 142             return self.shebang(line, cell)
    143 
    144         # write a basic docstring:

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/decorator.py in fun(*args, **kw)
    230             if not kwsyntax:
    231                 args, kw = fix(args, kw, sig)
--> 232             return caller(func, *(extras + args), **kw)
    233     fun.__name__ = func.__name__
    234     fun.__doc__ = func.__doc__

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magic.py in <lambda>(f, *a, **k)
    185     # but it's overkill for just that one bit of state.
    186     def magic_deco(arg):
--> 187         call = lambda f, *a, **k: f(*a, **k)
    188 
    189         if callable(arg):

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in shebang(self, line, cell)
    243             sys.stderr.flush()
    244         if args.raise_error and p.returncode!=0:
--> 245             raise CalledProcessError(p.returncode, cell, output=out, stderr=err)
    246 
    247     def _run_script(self, p, cell, to_close):

CalledProcessError: Command 'b'git pull\n'' returned non-zero exit status 1.
In [39]:
%%bash
git log --graph --oneline
* 94628af Add a beacon
* 380d1f1 Translating from the Welsh
* 976f55c Add Scotland
* 480039f Add wales
* a77a766 Add Helvellyn
* e95fb6e Include lakes in the scope
* e87cd77 Add lakeland
* 74a8ea7 Revert "Add a lie about a mountain"
* c730d31 Change title
* d94bbd3 Add a lie about a mountain
* c26b924 First commit of discourse on UK topography
In [40]:
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

note left of P: git commit -am "Add scotland"
P->PR: create commit with Scotland file

note right of C: git commit -am "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)
Out[40]:

Conflicting commits

Finally, go through the process again, but this time, make changes which touch the same line.

In [41]:
%%writefile Wales.md
Mountains In Wales
==================

* Pen y Fan
* Tryfan
* Snowdon
* Fan y Big
Overwriting Wales.md
In [42]:
%%bash
git commit -am "Add another Beacon"
git push
[master a496f22] Add another Beacon
 1 file changed, 1 insertion(+)
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin master

---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
/tmp/ipykernel_9923/1666590468.py in <module>
----> 1 get_ipython().run_cell_magic('bash', '', 'git commit -am "Add another Beacon"\ngit push\n')

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/interactiveshell.py in run_cell_magic(self, magic_name, line, cell)
   2417             with self.builtin_trap:
   2418                 args = (magic_arg_s, cell)
-> 2419                 result = fn(*args, **kwargs)
   2420             return result
   2421 

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in named_script_magic(line, cell)
    140             else:
    141                 line = script
--> 142             return self.shebang(line, cell)
    143 
    144         # write a basic docstring:

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/decorator.py in fun(*args, **kw)
    230             if not kwsyntax:
    231                 args, kw = fix(args, kw, sig)
--> 232             return caller(func, *(extras + args), **kw)
    233     fun.__name__ = func.__name__
    234     fun.__doc__ = func.__doc__

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magic.py in <lambda>(f, *a, **k)
    185     # but it's overkill for just that one bit of state.
    186     def magic_deco(arg):
--> 187         call = lambda f, *a, **k: f(*a, **k)
    188 
    189         if callable(arg):

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in shebang(self, line, cell)
    243             sys.stderr.flush()
    244         if args.raise_error and p.returncode!=0:
--> 245             raise CalledProcessError(p.returncode, cell, output=out, stderr=err)
    246 
    247     def _run_script(self, p, cell, to_close):

CalledProcessError: Command 'b'git commit -am "Add another Beacon"\ngit push\n'' returned non-zero exit status 128.
In [43]:
os.chdir(partner_dir)
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
/tmp/ipykernel_9923/3492456231.py in <module>
----> 1 os.chdir(partner_dir)

FileNotFoundError: [Errno 2] No such file or directory: '/home/runner/work/rsd-engineeringcourse/rsd-engineeringcourse/ch02git/learning_git/partner_repo'
In [44]:
%%writefile Wales.md
Mountains In Wales
==================

* Pen y Fan
* Tryfan
* Snowdon
* Glyder Fawr
Overwriting Wales.md
In [45]:
%%bash --no-raise-error
git commit -am "Add Glyder"
git push
[master 44e89d1] Add Glyder
 1 file changed, 1 insertion(+), 1 deletion(-)
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin master

When you pull, instead of offering an automatic merge commit message, it says:

In [46]:
%%bash --no-raise-error
git pull
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

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

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:

In [47]:
%%bash
cat Wales.md
Mountains In Wales
==================

* Pen y Fan
* Tryfan
* Snowdon
* Glyder Fawr

Manually edit the file, to combine the changes as seems sensible and get rid of the symbols:

In [48]:
%%writefile Wales.md
Mountains In Wales
==================

* Pen y Fan
* Tryfan
* Snowdon
* Glyder Fawr
* Fan y Big
Overwriting Wales.md

Commit the resolved file

Now commit the merged result:

In [49]:
%%bash
git commit -a --no-edit # I added a No-edit for this non-interactive session. You can edit the commit if you like.
Aborting commit due to empty commit message.
---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
/tmp/ipykernel_9923/252762378.py in <module>
----> 1 get_ipython().run_cell_magic('bash', '', 'git commit -a --no-edit # I added a No-edit for this non-interactive session. You can edit the commit if you like.\n')

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/interactiveshell.py in run_cell_magic(self, magic_name, line, cell)
   2417             with self.builtin_trap:
   2418                 args = (magic_arg_s, cell)
-> 2419                 result = fn(*args, **kwargs)
   2420             return result
   2421 

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in named_script_magic(line, cell)
    140             else:
    141                 line = script
--> 142             return self.shebang(line, cell)
    143 
    144         # write a basic docstring:

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/decorator.py in fun(*args, **kw)
    230             if not kwsyntax:
    231                 args, kw = fix(args, kw, sig)
--> 232             return caller(func, *(extras + args), **kw)
    233     fun.__name__ = func.__name__
    234     fun.__doc__ = func.__doc__

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magic.py in <lambda>(f, *a, **k)
    185     # but it's overkill for just that one bit of state.
    186     def magic_deco(arg):
--> 187         call = lambda f, *a, **k: f(*a, **k)
    188 
    189         if callable(arg):

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in shebang(self, line, cell)
    243             sys.stderr.flush()
    244         if args.raise_error and p.returncode!=0:
--> 245             raise CalledProcessError(p.returncode, cell, output=out, stderr=err)
    246 
    247     def _run_script(self, p, cell, to_close):

CalledProcessError: Command 'b'git commit -a --no-edit # I added a No-edit for this non-interactive session. You can edit the commit if you like.\n'' returned non-zero exit status 1.
In [50]:
%%bash
git push
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin master

---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
/tmp/ipykernel_9923/3471985758.py in <module>
----> 1 get_ipython().run_cell_magic('bash', '', 'git push\n')

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/interactiveshell.py in run_cell_magic(self, magic_name, line, cell)
   2417             with self.builtin_trap:
   2418                 args = (magic_arg_s, cell)
-> 2419                 result = fn(*args, **kwargs)
   2420             return result
   2421 

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in named_script_magic(line, cell)
    140             else:
    141                 line = script
--> 142             return self.shebang(line, cell)
    143 
    144         # write a basic docstring:

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/decorator.py in fun(*args, **kw)
    230             if not kwsyntax:
    231                 args, kw = fix(args, kw, sig)
--> 232             return caller(func, *(extras + args), **kw)
    233     fun.__name__ = func.__name__
    234     fun.__doc__ = func.__doc__

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magic.py in <lambda>(f, *a, **k)
    185     # but it's overkill for just that one bit of state.
    186     def magic_deco(arg):
--> 187         call = lambda f, *a, **k: f(*a, **k)
    188 
    189         if callable(arg):

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in shebang(self, line, cell)
    243             sys.stderr.flush()
    244         if args.raise_error and p.returncode!=0:
--> 245             raise CalledProcessError(p.returncode, cell, output=out, stderr=err)
    246 
    247     def _run_script(self, p, cell, to_close):

CalledProcessError: Command 'b'git push\n'' returned non-zero exit status 128.
In [51]:
os.chdir(working_dir)
In [52]:
%%bash
git pull
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
/tmp/ipykernel_9923/3022008257.py in <module>
----> 1 get_ipython().run_cell_magic('bash', '', 'git pull\n')

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/interactiveshell.py in run_cell_magic(self, magic_name, line, cell)
   2417             with self.builtin_trap:
   2418                 args = (magic_arg_s, cell)
-> 2419                 result = fn(*args, **kwargs)
   2420             return result
   2421 

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in named_script_magic(line, cell)
    140             else:
    141                 line = script
--> 142             return self.shebang(line, cell)
    143 
    144         # write a basic docstring:

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/decorator.py in fun(*args, **kw)
    230             if not kwsyntax:
    231                 args, kw = fix(args, kw, sig)
--> 232             return caller(func, *(extras + args), **kw)
    233     fun.__name__ = func.__name__
    234     fun.__doc__ = func.__doc__

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magic.py in <lambda>(f, *a, **k)
    185     # but it's overkill for just that one bit of state.
    186     def magic_deco(arg):
--> 187         call = lambda f, *a, **k: f(*a, **k)
    188 
    189         if callable(arg):

/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/IPython/core/magics/script.py in shebang(self, line, cell)
    243             sys.stderr.flush()
    244         if args.raise_error and p.returncode!=0:
--> 245             raise CalledProcessError(p.returncode, cell, output=out, stderr=err)
    246 
    247     def _run_script(self, p, cell, to_close):

CalledProcessError: Command 'b'git pull\n'' returned non-zero exit status 1.
In [53]:
%%bash
cat Wales.md
Mountains In Wales
==================

* Pen y Fan
* Tryfan
* Snowdon
* Glyder Fawr
* Fan y Big
In [54]:
%%bash
git log --oneline --graph
* 44e89d1 Add Glyder
* a496f22 Add another Beacon
* 94628af Add a beacon
* 380d1f1 Translating from the Welsh
* 976f55c Add Scotland
* 480039f Add wales
* a77a766 Add Helvellyn
* e95fb6e Include lakes in the scope
* e87cd77 Add lakeland
* 74a8ea7 Revert "Add a lie about a mountain"
* c730d31 Change title
* d94bbd3 Add a lie about a mountain
* c26b924 First commit of discourse on UK topography

Distributed VCS in teams with conflicts

In [55]:
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 commit -am "update wales.md"
P->PR: add commit to local repo
    
note right of C: git commit -am "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)
Out[55]:

The Levels of Git

In [56]:
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)
Out[56]:

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!