XClose

COMP0233: Research Software Engineering With Python

Home
Menu

Publishing

We're still in our working directory:

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(working_dir)
working_dir
Out[1]:
'/home/runner/work/rsd-engineeringcourse/rsd-engineeringcourse/ch00git/learning_git/git_example'

Sharing your work

So far, all our work has been on our own computer. But a big part of the point of version control is keeping your work safe, on remote servers. Another part is making it easy to share your work with the world In this example, we'll be using the "GitHub" cloud repository to store and publish our work.

If you have not done so already, you should create an account on GitHub: go to GitHub's website, fill in a username and password, and click on "sign up for GitHub".

Creating a repository

Ok, let's create a repository to store our work. Hit "new repository" on the right of the github home screen.

Fill in a short name, and a description. Choose a "public" repository. Don't choose to initialize the repository with a README. That will create a repository with content and we only want a placeholder where to upload what we've created locally.

Paying for GitHub

For this course, you should use public repositories in your personal account for your example work: it's good to share! GitHub is free for open source, but in general, charges a fee if you want to keep your work private.

In the future, you might want to keep your work on GitHub private.

Students can get free private repositories on GitHub, by going to GitHub Education and filling in a form (look for the Student Developer Pack).

UCL pays for private GitHub repositories for UCL research groups: you can find the service details on the Advanced Research Computing Centre's website.

Adding a new remote to your repository

Instructions will appear, once you've created the repository, as to how to add this new "remote" server to your repository, in the lower box on the screen. Mine say:

In [2]:
%%bash
git remote add origin git@github.com:UCL/github-example.git
In [3]:
%%bash
git push -uf origin main # You shouldn't need the extra `f` switch. We use it here to force the push and rewrite that repository.
      #You should copy the instructions from YOUR repository.
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)
Cell In[3], line 1
----> 1 get_ipython().run_cell_magic('bash', '', "git push -uf origin main # You shouldn't need the extra `f` switch. We use it here to force the push and rewrite that repository.\n      #You should copy the instructions from YOUR repository.\n")

File /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/IPython/core/interactiveshell.py:2541, in InteractiveShell.run_cell_magic(self, magic_name, line, cell)
   2539 with self.builtin_trap:
   2540     args = (magic_arg_s, cell)
-> 2541     result = fn(*args, **kwargs)
   2543 # The code below prevents the output from being displayed
   2544 # when using magics with decorator @output_can_be_silenced
   2545 # when the last Python token in the expression is a ';'.
   2546 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):

File /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/IPython/core/magics/script.py:155, in ScriptMagics._make_script_magic.<locals>.named_script_magic(line, cell)
    153 else:
    154     line = script
--> 155 return self.shebang(line, cell)

File /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/IPython/core/magics/script.py:315, in ScriptMagics.shebang(self, line, cell)
    310 if args.raise_error and p.returncode != 0:
    311     # If we get here and p.returncode is still None, we must have
    312     # killed it but not yet seen its return code. We don't wait for it,
    313     # in case it's stuck in uninterruptible sleep. -9 = SIGKILL
    314     rc = p.returncode or -9
--> 315     raise CalledProcessError(rc, cell)

CalledProcessError: Command 'b"git push -uf origin main # You shouldn't need the extra `f` switch. We use it here to force the push and rewrite that repository.\n      #You should copy the instructions from YOUR repository.\n"' returned non-zero exit status 128.

Remotes

The first command sets up the server as a new remote, called origin.

Git, unlike some earlier version control systems is a "distributed" version control system, which means you can work with multiple remote servers.

Usually, commands that work with remotes allow you to specify the remote to use, but assume the origin remote if you don't.

Here, git push will push your whole history onto the server, and now you'll be able to see it on the internet! Refresh your web browser where the instructions were, and you'll see your repository!

Let's add these commands to our diagram:

In [4]:
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
"""
from wsd import wsd
%matplotlib inline
wsd(message)
Out[4]:
No description has been provided for this image

Playing with GitHub

Take a few moments to click around and work your way through the GitHub interface. Try clicking on 'index.md' to see the content of the file: notice how the markdown renders prettily.

Click on "commits" near the top of the screen, to see all the changes you've made. Click on the commit number next to the right of a change, to see what changes it includes: removals are shown in red, and additions in green.

Working with multiple files

Some new content

So far, we've only worked with one file. Let's add another:

nano lakeland.md
In [5]:
%%writefile lakeland.md
Lakeland  
========   
  
Cumbria has some pretty hills, and lakes too.  
Writing lakeland.md
In [6]:
cat lakeland.md
Lakeland  
========   
  
Cumbria has some pretty hills, and lakes too.  

Git will not by default commit your new file

In [7]:
%%bash --no-raise-error
git commit -m "Try to add Lakeland"
On branch main
Untracked files:
  (use "git add <file>..." to include in what will be committed)
	__pycache__/
	lakeland.md
	wsd.py

nothing added to commit but untracked files present (use "git add" to track)

This didn't do anything, because we've not told git to track the new file yet.

Tell git about the new file

In [8]:
%%bash
git add lakeland.md
git commit -m "Add lakeland"
[main 32a2306] Add lakeland
 1 file changed, 4 insertions(+)
 create mode 100644 lakeland.md

Ok, now we have added the change about Cumbria to the file. Let's publish it to the origin repository.

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

    git push --set-upstream origin main

To have this happen automatically for branches without a tracking
upstream, see 'push.autoSetupRemote' in 'git help config'.

---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
Cell In[9], line 1
----> 1 get_ipython().run_cell_magic('bash', '', 'git push\n')

File /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/IPython/core/interactiveshell.py:2541, in InteractiveShell.run_cell_magic(self, magic_name, line, cell)
   2539 with self.builtin_trap:
   2540     args = (magic_arg_s, cell)
-> 2541     result = fn(*args, **kwargs)
   2543 # The code below prevents the output from being displayed
   2544 # when using magics with decorator @output_can_be_silenced
   2545 # when the last Python token in the expression is a ';'.
   2546 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):

File /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/IPython/core/magics/script.py:155, in ScriptMagics._make_script_magic.<locals>.named_script_magic(line, cell)
    153 else:
    154     line = script
--> 155 return self.shebang(line, cell)

File /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/IPython/core/magics/script.py:315, in ScriptMagics.shebang(self, line, cell)
    310 if args.raise_error and p.returncode != 0:
    311     # If we get here and p.returncode is still None, we must have
    312     # killed it but not yet seen its return code. We don't wait for it,
    313     # in case it's stuck in uninterruptible sleep. -9 = SIGKILL
    314     rc = p.returncode or -9
--> 315     raise CalledProcessError(rc, cell)

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

Visit GitHub, and notice this change is on your repository on the server. We could have said git push origin to specify the remote to use, but origin is the default.

Changing two files at once

What if we change both files?

In [10]:
%%writefile lakeland.md
Lakeland  
========   
  
Cumbria has some pretty hills, and lakes too

Mountains:
* Helvellyn
Overwriting lakeland.md
In [11]:
%%writefile index.md
Mountains and Lakes in the UK   
===================   
Engerland is not very mountainous.
But has some tall hills, and maybe a
mountain or two depending on your definition.
Overwriting index.md
In [12]:
%%bash
git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   index.md
	modified:   lakeland.md

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	__pycache__/
	wsd.py

no changes added to commit (use "git add" and/or "git commit -a")

These changes should really be separate commits. We can do this with careful use of git add, to stage first one commit, then the other.

In [13]:
%%bash
git add index.md
git commit -m "Include lakes in the scope"
[main 14b8b39] Include lakes in the scope
 1 file changed, 4 insertions(+), 5 deletions(-)

Because we "staged" only index.md, the changes to lakeland.md were not included in that commit.

In [14]:
%%bash
git add lakeland.md
git commit -m "Add Helvellyn"
[main 7d735f6] Add Helvellyn
 1 file changed, 4 insertions(+), 1 deletion(-)
In [15]:
%%bash
git log --oneline
7d735f6 Add Helvellyn
14b8b39 Include lakes in the scope
32a2306 Add lakeland
30b25c7 Add a lie about a mountain
fe0ceeb First commit of discourse on UK topography
In [16]:
%%bash
git push
fatal: The current branch main has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin main

To have this happen automatically for branches without a tracking
upstream, see 'push.autoSetupRemote' in 'git help config'.

---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
Cell In[16], line 1
----> 1 get_ipython().run_cell_magic('bash', '', 'git push\n')

File /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/IPython/core/interactiveshell.py:2541, in InteractiveShell.run_cell_magic(self, magic_name, line, cell)
   2539 with self.builtin_trap:
   2540     args = (magic_arg_s, cell)
-> 2541     result = fn(*args, **kwargs)
   2543 # The code below prevents the output from being displayed
   2544 # when using magics with decorator @output_can_be_silenced
   2545 # when the last Python token in the expression is a ';'.
   2546 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):

File /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/IPython/core/magics/script.py:155, in ScriptMagics._make_script_magic.<locals>.named_script_magic(line, cell)
    153 else:
    154     line = script
--> 155 return self.shebang(line, cell)

File /opt/hostedtoolcache/Python/3.12.5/x64/lib/python3.12/site-packages/IPython/core/magics/script.py:315, in ScriptMagics.shebang(self, line, cell)
    310 if args.raise_error and p.returncode != 0:
    311     # If we get here and p.returncode is still None, we must have
    312     # killed it but not yet seen its return code. We don't wait for it,
    313     # in case it's stuck in uninterruptible sleep. -9 = SIGKILL
    314     rc = p.returncode or -9
--> 315     raise CalledProcessError(rc, cell)

CalledProcessError: Command 'b'git push\n'' returned non-zero exit status 128.
In [17]:
message="""
participant "Cleese's remote" as M
participant "Cleese's repo" as R
participant "Cleese's index" as I
participant Cleese as C

note right of C: nano index.md
note right of C: nano lakeland.md

note right of C: git add index.md
C->I: Add *only* the changes to index.md to the staging area

note right of C: git commit -m "Include lakes"
I->R: Make a commit from currently staged changes: index.md only

note right of C: git add lakeland.md
note right of C: git commit -m "Add Helvellyn"
C->I: Stage *all remaining* changes, (lakeland.md)
I->R: Make a commit from currently staged changes

note right of C: git push
R->M: Transfer commits to Github
"""
wsd(message)
Out[17]:
No description has been provided for this image