+ - 0:00:00
Notes for current slide
Notes for next slide

Introduction to git, Part I

Dr. Uwe Schmitt

Scientific IT Services ETH

Contact: uwe.schmitt@id.ethz.ch


Script at https://siscourses.ethz.ch/git

1 / 72

Please try to login at

https://sis-jupyterhub.ethz.ch

2 / 72

Structure of the course:

  1. General introduction and basic concepts of git.

  2. Hands-on exercises for basic git commands.

  3. Introduction to "branching" with exercises.

  4. Basic introduction to gitlab/ github.

3 / 72

About git

5 / 72

Effects

  • no version tags in file names any more

  • never loose old files

  • undo changes efficiently

  • distribute code in a controlled way

  • analyse history / changes which introduced a bug

6 / 72

What git can manage

  • program code

  • text files used for documentation (latex files, markdown, html, ..)

  • textual data files (like .csv, .txt, ..)

Notebooks?

  • git to manage jupyter notebooks is inconvenient
7 / 72

Caution!

  • git is not suited to track huge data files

    • ... you need a special solution as git lsf or git annex instead.
  • git is not suited to track binary files (.xlsx, .zip, .gz, .doc, ...)

  • git has many features

  • You have to exercise to learn it!

8 / 72

git does not forget

In case you accidentelly added private data such as passwords, or large files to your repository, commands such as git rm or rewriting history with git rebase is not enough.

See these docs on how to fix such situations

9 / 72

About git repositories

  • git can be used on a single computer (without github et al)

  • A local git repository is a folder including sub folders, holding a hidden .git subfolder.

  • git manages local git repositories

  • git allows synchronization of git repositories (eg with github)

About gitlab / github / ...

  • In a team developers have their local git repositories

  • github / gitlab offer just another local git repository on a remote computer.

  • git assists in synchronizing repositories with such a remote.

10 / 72

Distributed software development without a version control system

Setting:

  • one person is main maintainer of a code base

Workflow:

  1. contributer ask for a up to date version
  2. work on the copy
  3. submit the changes as a "patch" to the maintainer
  4. maintainer checks changes and applies them to the code base
  5. goto 1.
11 / 72

Example patch

print_squares.py:

for i in range(10):
# display i and its square
print("i is", i)
print("i^2 is", i ** 2)

print_squares.py after modification:

for i in range(10):
# this is the magic computation
print("i^2 is", i ** 2)
print("i is", i)

and this is the according patch:

--- a/git/sandbox/print_squares.py
+++ b/git/sandbox/print_squares.py
@@ -1,4 +1,4 @@
for i in range(10):
- # display i and its square
- print("i is", i)
+ # this is the magic computation
print("i^2 is", i ** 2)
+ print("i is", i)
12 / 72

gits most important internals

  • git allows management, contribution and manipulation of patches.

  • git chains patches over time

  • if you know the initial state of an folder and this chain you can reconstruct the state of the file for any time.

  • that's it

13 / 72

Example list of commits

  • A commit consists of a single or multiple related patches.

  • The git history is a list of commits:

$ git log
commit 8ab13c9a930d4b0fd1bc1937f382196bc3a1bbdc (HEAD -> main)
Author: Uwe <uwe.schmitt@id.ethz.ch>
Date: Fri Feb 9 12:50:00 2018 +0100
changed order of output in print_squares.py
commit 0daab54f48ac33b5cfa71f90634ad82dd655e33c
Author: Uwe <uwe.schmitt@id.ethz.ch>
Date: Fri Feb 9 12:49:16 2018 +0100
initial version of print_squares.py
  • starts with the most recent commit on top
  • commits are identified using ids like 8ab13c9a930d4b0fd1bc1937f382196bc3a1bbdc
  • Usually the first eight characters are enough to identify the id.
14 / 72

Example list of commits including patches

$ git log -p

(Inverted order, older commit first)

This patch adds four new lines to an empty file (marked as /dev/null):

commit 90b3a581cae221342ca82fe2862fd5daa219a4be
Author: Uwe <uwe.schmitt@id.ethz.ch>
Date: Fri Feb 9 16:47:49 2018 +0100
initial version of print_squared.py
diff --git a/print_squares.py b/print_squares.py
new file mode 100644
index 0000000..d45e7ab
--- /dev/null
+++ b/print_squares.py
@@ -0,0 +1,4 @@
+for i in range(10):
+ # print i and i squared
+ print("i is", i)
+ print("i^2 is", i ** 2)
15 / 72

... log with patches continued

commit b3ed251fa0701ee5f986adc7a63eafd87d7d0bd2 (HEAD -> main)
Author: Uwe <uwe.schmitt@id.ethz.ch>
Date: Fri Feb 9 16:48:20 2018 +0100
changed order of output in print_squares.py
diff --git a/print_squares.py b/print_squares.py
index d45e7ab..893f18d 100644
--- a/print_squares.py
+++ b/print_squares.py
@@ -1,4 +1,4 @@
for i in range(10):
- # print i and i squared
- print("i is", i)
+ # print i squared an i
print("i^2 is", i ** 2)
+ print("i is", i)
16 / 72

The staging area (also named "index")

Related patches (maybe over multiple files) are grouped as commits

  1. First use git add to group changes in staging area

  2. git commit adds this group of patches as a single entry (commit) to the history chain

17 / 72

Important git commands

git command line interface uses your current working directory to detect the repository you want to work with. Even if you are in a subfolder.

  • git init initializes given folder and its subfolders as a local git repository

  • git status shows state of current git repository

  • git diff shows state of current git repository

  • git add creates patches to create current versions of file(s) and places them into the staging area

  • git commit creates a commit from the current staging area

  • git log shows the history of commits

  • git show shows details single commits

18 / 72

Hands on

Be exact when you type the examples!

19 / 72

Check git version

$ git --version
git version 2.32.0

Should be at least 2.32 to follow the tutorial.

In case you use an older version of git you will have to replace commands

  • git switch -c ... by git checkout -b ...
  • git checkout ... by git switch ...

later.

20 / 72

Configuring git

Before you use git the first time we configure some settings:

$ git config --global user.name "Uwe Schmitt"
$ git config --global user.email "uwe.schmitt@id.ethz.ch"
21 / 72

Configuring git

Note: Not needed in Online Course on jupyterhub

Then we set your default text editor.

  • On Mac / Linux: (replace nano by vim if you like):

    $ git config --global core.editor /usr/bin/nano
    $ git config --global core.autocrlf input
  • On Windows:

    $ git config --global core.editor "'C:/Program Files/Notepad++/notepad++.exe' \
    -multiInst -notabbar -nosession -noPlugin"
    $ git config --global core.autocrlf true

Now check if the configured editor works, but don't modify the shown file!

$ git config --global -e
22 / 72

Creating a local Repository

Every folder on your file system can be turned into a local git repository:

$ cd
$ mkdir git_demo
$ cd git_demo
$ git init .
hint: Using 'main' as the name for the initial branch. This default branch name
..
Initialized empty Git repository in ~/git_demo/.git/
$ ls -a
. .. .git
  • This means: the folder and all subfolders are under control now!

  • The folder is not necessarily empty, you can put existing folders under version control.

  • Use seperate repositories for seperate software projects.

23 / 72

First steps with git

Now create a new file greet.py in the folder git_demo:

def greet(name):
return "hi %s" % name

If we ask git about the status of the repository, we see that have one file which is not under controly yet:

$ git status
On branch main
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
greet.py
nothing added to commit but untracked files present (use "git add" to track)
24 / 72

Your first commit

git add creates a patch to build the current version of greet.py and places this patch into the index:

$ git add greet.py
$ git status
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: greet.py
  • git add also works with multiple files and / or folders
  • git add is required to put files under version control.
25 / 72

Your first commit (continued)

  • Now commit the patch in the index with a comment describing the commit:
$ git commit -m "first version of greet.py"
[main (root-commit) 8175092] first version of greet.py
1 file changed, 2 insertions(+)
create mode 100644 greet.py
  • 8175092 are the first characters of the commit id.

  • If you ommit the "-m ...." git will open the configured text editor where you can enter the message.

  • Think about your commit messages. You might want to understand them in one year or later.

26 / 72

Inspecting changes

Show the history:

$ git log
commit 8175092830d7722c30d339106f3738a7ff5f53fc (HEAD -> main)
Author: Uwe Schmitt <uwe.schmitt@id.ethz.ch>
Date: Wed Sep 30 21:58:30 2015 +0200
first version of greet.py
27 / 72

Inspecting changes continued

Show which change was introduced by the latest commit:

$ git show
commit 8175092830d7722c30d339106f3738a7ff5f53fc (HEAD -> main)
Author: Uwe Schmitt <uwe.schmitt@id.ethz.ch>
Date: Thu Oct 1 15:47:11 2015 +0200
first version of greet.py
diff --git a/greet.py b/greet.py
new file mode 100644
index 0000000..7a875b9
--- /dev/null
+++ b/greet.py
@@ -0,0 +1,2 @@
+def greet(name):
+ return "hi %s" % name
28 / 72

More code changes for the next commit

First we add a new feature to greet.py:

def greet(name):
return "hi %s" % name
def say_hello(name):
print(greet(name))

And we create a new file run.py:

import greet
greet.say_hello("monty")
29 / 72

Which changes did we introduce in already committed files?

$ git diff
diff --git a/greet.py b/greet.py
index 7a875b9..53bb92b 100644
--- a/greet.py
+++ b/greet.py
@@ -1,2 +1,5 @@
def greet(name):
return "hi %s" % name
+
+def say_hello(name):
+ print(greet(name))
30 / 72

What is the current status or your repository?

$ 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: greet.py
Untracked files:
(use "git add <file>..." to include in what will be committed)
run.py
no changes added to commit (use "git add" and/or "git commit -a")
31 / 72

git add to setup stagin area

We place now multiple patches to the staging area:

$ git add run.py
$ git add greet.py

Now we have two changes in our staging area:

$ git status
$ git status
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: greet.py
new file: run.py
32 / 72

Check staging area

We use git diff --cached to see the patches in the staging area:

$ git diff --cached
diff --git a/greet.py b/greet.py
index 7a875b9..53bb92b 100644
--- a/greet.py
+++ b/greet.py
@@ -1,2 +1,5 @@
def greet(name):
return "hi %s" % name
+
+def say_hello(name):
+ print(greet(name))
diff --git a/run.py b/run.py
new file mode 100644
index 0000000..1b804f3
--- /dev/null
+++ b/run.py
@@ -0,0 +1,3 @@
+import greet
+
+greet.say_helo("monty")
33 / 72

Our next commit

We create a commit now:

$ git commit -m "improved greet.py and added test script"
[main c3cdcfa] improved greet.py and added test script
2 files changed, 6 insertions(+)
create mode 100644 run.py

And inspect the history:

$ git log
commit c3cdcfa04b7de45403a8291c567fba6ff4ae0b25 (HEAD -> main)
Author: Uwe Schmitt <uwe.schmitt@id.ethz.ch>
Date: Wed Sep 30 22:14:10 2015 +0200
improved greet.py and added test script
commit 8175092830d7722c30d339106f3738a7ff5f53fc
Author: Uwe Schmitt <uwe.schmitt@id.ethz.ch>
Date: Wed Sep 30 21:58:30 2015 +0200
first version of greet.py
34 / 72

Inspect the last commit

$ git show
commit c3cdcfa04b7de45403a8291c567fba6ff4ae0b25 (HEAD -> main)
Author: Uwe Schmitt <uwe.schmitt@id.ethz.ch>
Date: Thu Oct 1 16:03:30 2015 +0200
improved greet.py and added test script
diff --git a/greet.py b/greet.py
index 7a875b9..2cd4ad9 100644
--- a/greet.py
+++ b/greet.py
@@ -1,2 +1,5 @@
def greet(name):
return "hi %s" % name
+
+def say_hello(name):
+ print(greet(name))
diff --git a/run.py b/run.py
new file mode 100644
index 0000000..3fb5e9b
--- /dev/null
+++ b/run.py
@@ -0,0 +1,5 @@
+import greet
+
+greet.say_hello("monty")
35 / 72

... and we add another new feature to cour code

Edit greet.py:

def greet(name):
return "hi %s" % name
def go_to_hell():
print("to hell with python")
def say_hello(name):
print(greet(name))

We check the changes again:

$ git diff
diff --git a/greet.py b/greet.py
index 2cd4ad9..e6b949a 100644
--- a/greet.py
+++ b/greet.py
@@ -1,5 +1,8 @@
def greet(name):
return "hi %s" % name
+def go_to_hell():
+ print("to hell with python")
+
def say_hello(name):
print(greet(name))
36 / 72

... and another commit

$ git add greet.py
$ git commit -m "added go_to_hell"

Here we use git log --oneline to reduce output:

$ git log --oneline
523eb90 (HEAD -> main) added go_to_hell
c3cdcfa improved greet.py and added test script
8175092 first version of greet.py
37 / 72

Typical pattern:

  • you worked on a new feature

  • git diff and git status to inspect changes

  • git add to add files to index (staging area)

  • git diff --cached to check stating area

  • git commit to add index to history

38 / 72

But one of the commits was crap!

First lookup the commit id of your last commit. Replace the COMMIT_ID_HERE fields by this id.

$ git revert COMMIT_ID_HERE --no-edit

git created an "inverse" patch of commit COMMIT_ID_HERE and committed it:

$ git log --oneline
d3cf980 (HEAD -> main) Revert "added go_to_hell"
523eb90 added go_to_hell
c3cdcfa improved greet.py and added test script
8175092 first version of greet.py

And we see that the feature is removed again:

$ cat greet.py
def greet(name):
return "hi %s" % name
def say_hello(name):
print(greet(name))
39 / 72

Inspect what git revert did

The last commit holds the mentioned "inverse patch":

$ git show
commit f4ba88676875a087ac7fac3bee2b0dbb676202d2 (HEAD -> main)
Author: Uwe Schmitt <uwe.schmitt@id.ethz.ch>
Date: Thu Oct 1 16:20:40 2015 +0200
Revert "added go_to_hell"
This reverts commit COMMIT_ID_HERE
diff --git a/greet.py b/greet.py
index e6b949a..2cd4ad9 100644
--- a/greet.py
+++ b/greet.py
@@ -1,8 +1,5 @@
def greet(name):
return "hi %s" % name
-def go_to_hell():
- print("to hell with python")
-
def say_hello(name):
print(greet(name))
40 / 72

More about git revert

  • git revert may be used not only to revert the most recent commit.

  • even reverted commits can be reverted again!

  • if the "inverse" patch can not be applied, git indicates a so called "merge conflict"

41 / 72

Recap

  • git status shows current status of repository

  • git add PATH, PATH, ... adds files to staging area

  • git diff shows current changes for files already tracked by git

  • git commit -m "...." commits changes with given commit message

  • git log shows history

  • git log --oneline shows only commit uniqued ids plus messages from history

  • git show shows changes introduced in most recent commit

  • git show COMMIT_ID shows changes introduced in given commit

  • git revert COMMIT_ID reverts changes introduced in given commit.

42 / 72

Not handled yet

  • git rm to remove a file under version control.

  • git mv to move / rename a file under version control.

  • git commit -a .... adds all changes of tracked files + creates commit.

  • git reset clears staging area in case of unintended added files.

  • git log -N only shows the last N patches in the history

  • git restore FILE_NAME overwrites the current changes in the given file by its last recoreded contents. (undo current edits)

  • git restore . resets the current folder and its subfolder to the state of the last commit.

  • .gitignore is a file where you can specify file names, folders and patterns ignored by git (e.g. binary files or backup files from your editor)

43 / 72

Working with branches

44 / 72

In future slides you see the branch named main which is the default branch we were already working on. Depending on the version of git or the git repositories you are working on this name might be master.

45 / 72

Branching

Up to now the evolution of our repository was linear, our repository has only one branch, the main branch:

A --> B --> C --> D main (*)

(the * marks the active branch)

To create a new branch ans work with it we enter:

$ git switch -c new_feature
Switched to a new branch 'new_feature'

And if we check the status we get:

$ git status
On branch new_feature
...
46 / 72

The history is still the same

Our last commit C now is the last commit for both branches, new_feature is active.

A --> B --> C --> D main, new_feature(*)
$ git log --oneline
af68936 (HEAD -> new_feature, main) Revert "added go_to_hell"
389d0ea added go_to_hell
a8ba071 improved greet.py and added test script
2c9fcec first version of greet.py

To list the existing branches:

$ git branch
main
* new_feature
47 / 72

Branching continued

Now we add a new function

def greet(name):
return "hi %s" % name
def say_hello(name):
print(greet(name))
def greet_two(name_1, name_2):
return "hi %s and %s" % (name_1, name_2)

and commit it to our new branch

$ git add greet.py
$ git commit -m "added function greet_two"
48 / 72

Branching continued

This is now the history of the active branch new_feature:

$ git log --oneline
3732022 (HEAD -> new_feature) added function new_feature
af68936 (main) Revert "added go_to_hell"
389d0ea added go_to_hell
a8ba071 improved greet.py and added test script
2c9fcec first version of greet.py
A --> B --> C --> D main
\
E new_feature (*)
49 / 72

Branching continued

We switch to the main branch we use git switch BRANCH_NAME:

$ git switch main
Switched to branch 'main'

this diagram shows the current state of our repository:

A --> B --> C --> D main (*)
\
E new_feature
$ git log --oneline
af68936 (HEAD -> main) Revert "added go_to_hell"
389d0ea added go_to_hell
a8ba071 improved greet.py and added test script
2c9fcec first version of greet.py

and the files in our repository reflect the main branch:

$ cat greet.py
def greet(name):
return "hi %s" % name
def say_hello(name):
print(greet(name))
50 / 72

Branching continued

And back ...

$ git switch new_feature
$ cat greet.py
def greet(name):
return "hi %s" % name
def say_hello(name):
print(greet(name))
def greet_two(name_1, name_2):
return "hi %s and %s" % (name_1, name_2)
51 / 72

Branching continued

We implement a "bug fix" in our main branch:

$ git switch main

And change "hi %s" to "hello %s":

def greet(name):
return "hello %s" % name
def say_hello(name):
print(greet(name))
$ git add greet.py
$ git commit -m "fixed spelling"
52 / 72

Branching continued

We decide that the new feature is ready and want to introduce it to the main branch. This is the current state of the commits and branches:

A --> B --> C --> D --> F main (*)
\
E new_feature

To merge our commit(s) from the new_feature branch to the current active branch (here main) we enter

$ git merge new_feature
53 / 72

Branching continued

This created a "merge commit" G:

A --> B --> C --> D --> F --> G main (*)
\ /
E ------- new_feature
$ git log --oneline --graph
* 9abfcea (HEAD -> main) Merge branch 'new_feature'
|\
| * 32c3d76 (new_feature) added function greet_two
* | 27e558a fixed spelling
|/
* 03f9fbb Revert "added go_to_hell"
* bbf296e added go_to_hell
* 4b79572 improved greet.py and added test script
* 8c637a8 fist version of greet.py
54 / 72

Branching continued: use case "freeze publication"

Lets assume this is the state of your repository at the time of publicaton:

A --> B --> C --> D main (*)
$ git switch -c publication
$ git switch main

publication and main point at the same HEAD:

A --> B --> C --> D main (*)
^
publication
55 / 72

Branching continued: use case "freeze publication"

Now you continue to work on main, and commit more changes:

A --> B --> C --> D --> E --> F main(*)
^
new_feature

To reset your project into the state of publication:

$ git switch publication

Which results in:

A --> B --> C --> D --> E --> F main
^
new_feature (*)

Note: git also supports so called "tags".

56 / 72

Branching: merge conflicts

If a patch can not be applied we get a "merge conflict".

Let us try to trigger this by committing conflicting changes in main and new_feature.

First in main:

$ git switch main
$ echo name > name.txt
$ echo uwe >> name.txt
$ git add name.txt
$ git commit -m "added name.txt"

Then in new_feature:

$ git switch new_feature
$ echo name > name.txt
$ echo schmitt >> name.txt
$ git add name.txt
$ git commit -m "added name.txt"
57 / 72

Branching: merge conflicts 2

Let's try to merge:

$ git switch main
$ git merge new_feature
CONFLICT (add/add): Merge conflict in name.txt
Auto-merging name.txt
Automatic merge failed; fix conflicts and then commit the result.

git status also indicates this:

$ git status
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both added: name.txt
no changes added to commit (use "git add" and/or "git commit -a")
58 / 72

Branching: merge conflicts 3

YOU MUST RESOLVE MERGE CONFLICTS OR ABORT THE MERGE

YOU MUST RESOLVE MERGE CONFLICTS OR ABORT THE MERGE

YOU MUST RESOLVE MERGE CONFLICTS OR ABORT THE MERGE

YOU MUST RESOLVE MERGE CONFLICTS OR ABORT THE MERGE

To abort the merge use

$ git merge --abort

Continue working with an unresolved merge conflict will mess up your repository!

59 / 72

Branching: merge conflicts 4

The computer was not able to merge conflicting patches and we have to decide how the final result in name.txt should look like after the merge.

git left markers in the conflicing files which we have to fix, there can be multiple markers in a file:

$ cat name.txt
name
<<<<<<< HEAD
uwe
=======
schmitt
>>>>>>> new_feature

We must edit the file to remove the markers and bring the file to the intended state. Open a text editor and modify the file to

name
uwe schmitt

The last step to finish the merge is

$ git add name.txt
$ git commit
60 / 72

Good practices

  • commits should be small

  • commit messages should be understandable and descriptive

  • use git status, git diff --cached before you commit.

  • only track plain source and text files (e.g. put *.pyc into .gitignore)

61 / 72

Introduction to github / gitlab / ...

62 / 72

About remote repositories

  • Working with remote repositories is about synchronization of repositories:

    1. push commits and branches to another repository

    2. fetch commits and branches from another repository and merge them

Why a remote repository?

  • You can share your code

  • You can use it as a backup

  • You can use it as an "staging area" if you work on different computers

63 / 72

Typical workflow for one or a few developers:

  1. I updated my local repository by fetching and merging all new commits from a remote repository with git pull

  2. I work on a new feature / fix a bug / ... (git add, git commit, ...)

  3. I push the new commits and branches to the remote repository with git push

  4. Continue with 1.

64 / 72

1. Please create a user account on https://gitlab.com if you don't have one yet.

2. Please open https://gitlab.com/uweschmitt/git-handson.git in your browser.

65 / 72

Fetch (clone) a remote repository

Before you want to work with a remote reposiory, we first have to clone it. First look at https://gitlab.com/uweschmitt/git-handson.git before you continue with the examples below.

$ cd
$ mkdir gitlab_demo
$ cd gitlab_demo
$ git clone https://gitlab.com/uweschmitt/git-handson.git
Cloning into 'git-handson'...
....
Unpacking objects: 100% (20/20), done.
$ cd git-handson
$ ls -al
total 16
drwxr-xr-x 5 uweschmitt staff 160 Feb 12 17:32 .
drwxr-xr-x 47 uweschmitt staff 1504 Feb 12 17:32 ..
drwxr-xr-x 13 uweschmitt staff 416 Feb 12 17:33 .git
-rw-r--r-- 1 uweschmitt staff 252 Feb 12 17:32 greet.py
-rw-r--r-- 1 uweschmitt staff 123 Feb 12 17:32 run.py
66 / 72

Fetch (clone) a remote repository continued

When we ran git clone we automatically registered the remote repository as origin:

$ git remote -v
origin https://gitlab.com/uweschmitt/git-handson.git (fetch)
origin https://gitlab.com/uweschmitt/git-handson.git (push)

Our default branch is main:

$ git log --oneline --graph
* 2f16683 (HEAD -> main, origin/main, origin/HEAD) Merge branch 'new_feature'
|\
| * 2ab650b (origin/new_feature, new_feature) added function greet_two
* | 381ebd0 fixed spelling
|/
* ba63be2 Revert "added go_to_hell"
* c1f84d2 added go_to_hell
* 69e5167 improved greet.py and added test script
* 16cf3f2 first version of greet.py
67 / 72

Fetch (clone) a remote repository continued

We can now switch to an existing branch:

$ git switch new_feature
$ git log --oneline --graph
* 2ab650b (HEAD -> new_feature, origin/new_feature) added function greet_two
* ba63be2 Revert "added go_to_hell"
* c1f84d2 added go_to_hell
* 69e5167 improved greet.py and added test script
* 16cf3f2 first version of greet.py

And also list existing branches:

$ git branch
main
* new_feature
$ git switch main
68 / 72

A new commit

  1. Make sure that your active branch is main.

  2. Please create a text file with a unique name (eg choose your name) and some random content.

  3. Commit this file.

  4. Now push these changes using arguments REMOTE_NAME and BRANCH_NAME

    $ git push
  5. When all your colleagues are done or the push fails, because the remote repository changed, you have to update your local repository:

    $ git pull
  6. Now check what happened:
    $ ls -al
    .....
69 / 72

Exercise!

71 / 72

This slide show was created with http://remarkjs.com/

72 / 72

Please try to login at

https://sis-jupyterhub.ethz.ch

2 / 72
Paused

Help

Keyboard shortcuts

, , Pg Up, k Go to previous slide
, , Pg Dn, Space, j Go to next slide
Home Go to first slide
End Go to last slide
b / m / f Toggle blackout / mirrored / fullscreen mode
c Clone slideshow
p Toggle presenter mode
t Restart the presentation timer
?, h Toggle this help
Esc Back to slideshow