Introduction

A collection of exercises for the OESA Git Workshop.

The workshop is intended to enable participants to work collaboratively using Git and GitLab on software and other projects.

No prior knowledge of Git is required. However, there are some prerequisites on software that needs to be installed to complete the exercises (see section Requirements).

We will use the Git command line interface (CLI) because it exposes the terms and concepts directly. We know this may seem inconvenient, and a number of GUI frontends and IDE integrations exist. However, if you know how to use the CLI, you should be able to understand and use any GUI.

How to use this book

In its current state, this book is not intended for self-study, as the context necessary to understand everything is provided in the workshop and is not laid out here. This may, however, change in a future version to make this book a stand-alone learning resource.

Each exercise proceeds on the state generated in the previous exercises. Thus, the intended way to use them is to work through them one by one. However, mind the limitations stated above.

The slides for the theory parts of the workshop are available as PDF here.

Requirements

UFZ GitLab account

To work with UFZ GitLab, an account is required there. On the UFZ GitLab login page (https://git.ufz.de/), use the Contact us link and write a short email to the WKDV. You should get an account quickly, usually at the same day.

Alternatively, a free GitLab account at https://gitlab.com/ can be used.

Software

Essential software required to complete the exercises, and to work with Git in general, are:

  • Git. Download the "official" Git client from Git - Downloads. Install with all settings as suggested by the installer!
  • A text editor. Notepad (the Windows default) will do, but Notepad++ might be more comfortable to use

Further, we will use Pandoc in the exercises to convert Markdown files to HTML. It is not strictly required, but you may find it useful for your work also on other occasions.

On Windows, install Pandoc using the package installer available at https://pandoc.org/installing.html. For other platforms, see the instructions there.

Book sources

This book is generated from Markdown. Sources are available at UFZ GitLab:

https://git.ufz.de/oesa/git-exercises

Cloning

To view the sources locally, clone them:

git clone https://git.ufz.de/oesa/git-exercises.git

Contributing

If you have any suggestions how to improve this book, please create an issue or make a merge request with your suggested changes.


Start with Exercise 1

Exercise 1 - Linear workflow

In this exercise, you will learn the most basic Git commands for a simple linear workflow. You will make commits and inspect the project's history.

Test the Git installation

Open the console ("Eingabeaufforderung").

To test your git installation, run the following, which should print the installed Git version

git --version
Output
git version 2.30.0.windows.2

Git help

Help overview

git --help

Help on a specific command

git <command> -h
git <command> --help

Git settings

User name and email

Git needs a user name and email address to attribute your changes. We set them with

git config --global user.name "<Your Yame>"
git config --global user.email "<your.name>@ufz.de"

Line endings

Line endings are differnt in Unix compared to Windows. therefore, we need to set how they are handled

git config --global core.autocrlf true

Default text editor

Further, we set the default text editor to notepad, the Windows default editor

git config --global core.editor notepad

Default branch

To avoid the outdated, oppressive default branch name master, which is perceived as being related to slavery, we change it to main

git config --global init.defaultBranch main

All these setting are now global, you don't need to repeat them for every new project.

Project setup

Create a directory for your project (C:\Projects\git-workshop)

C:\Users\username>cd C:\
C:\>mkdir Projects
C:\>cd Projects
C:\Projects>mkdir git-workshop
C:\Projects>cd git-workshop
C:\Projects\git-workshop>

From here on, we assume C:\Projects\git-workshop as the working directory of the prompt.

Initialize a Git repository

Initialization of a repository is done with a single, simple command

git init
Output
Initialized empty Git repository in C:/Projects/git-workshop/.git/

We can inspect our project's directory content (with the option to show hidden files)

dir /A:H
Output
...
27/01/2021  13:17    <DIR>          .git
               0 File(s)              0 bytes
               1 Dir(s)  517,128,151,040 bytes free

Git created a directory .git, which is where the repository history is stored. You don't need to do anything with this directory, just for your information...

Make a first commit

Create a file README.md1

echo.> README.md

You can also create the file using the Explorer, but depending on your settings you may end up with README.md.txt, which may be complicated to change.

Open the file with your text editor and fill it with

# Git Workshop

Content

* ...
* ...
* ...

Save your changes.

View the status of your project

git status
Output
On branch main

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        README.md

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

We need to "stage" our changes to be able to commit

git add README.md

View the status again to see what happened

git status
Output
On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   README.md

And finally, commit (with a message)

git commit -m "initial commit"
Output
[main (root-commit) d8d9072] initial commit
 1 file changed, 7 insertions(+)
 create mode 100644 README.md

Please note that hashes (the 7-digits hex code in the first line) will be different in your output.

Check the status again to see that there is "nothing to commit, working tree clean".

git status
Output
On branch main
nothing to commit, working tree clean

Make changes

Let's take some notes of what we did. Create a file linear-workflow.md

echo.> linear-workflow.md

Fill it with some content, e.g.

# Linear workflow

```
git init
```

* Create file README.md

```
git status
git add README.md
git status
git commit -m "initial commit"
git status
```

Save your changes.

Inspect what changed (you should always do that before staging and committing!)

git status
Output
On branch main
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        linear-workflow.md

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

Stage the new file

git add linear-workflow.md
git status
Output
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   linear-workflow.md

To "un-stage" files use reset

git reset linear-workflow.md
git status
Output
On branch main
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        linear-workflow.md

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

Stage the file again

git add linear-workflow.md
git status
Output
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   linear-workflow.md

Commit

git commit -m "added linear workflow"
Output
[main 43bc0a8] added linear workflow
 1 file changed, 15 insertions(+)
 create mode 100644 linear-workflow.md

Inspect the history

To view the history of your project, use

git log
Output
commit 43bc0a86a7d49ad269f798360dfcea944713ef90 (HEAD -> main)
Author: ... <...@ufz.de>
Date:   Wed Jan 27 20:27:02 2021 +0100

    added linear workflow

commit d8d9072990da891df3624358b7a8fc473afb57f8
Author: ... <...@ufz.de>
Date:   Wed Jan 27 20:25:35 2021 +0100

    initial commit

We can also inspect the last commit with its message and diffs

git show
Output
commit 43bc0a86a7d49ad269f798360dfcea944713ef90 (HEAD -> main)
Author: ... <...@ufz.de>
Date:   Wed Jan 27 20:27:02 2021 +0100

    added linear workflow

diff --git a/linear-workflow.md b/linear-workflow.md
new file mode 100644
index 0000000..d039c21
--- /dev/null
+++ b/linear-workflow.md
@@ -0,0 +1,15 @@
+# Linear workflow
+
+```
+> git init
+```
+
+* Create file README.md
+
+```
+> git status
+> git add README.md
+> git status
+> git commit -m "initial commit"
+> git status
+```
\ No newline at end of file

Depending on the size of your console window, the last line displayed may be .... In this case, scroll down with the arrow keys until the last line shows (END). Then, press Q to finish.

Please not the last line, \ No newline at end of file. It is a Unix convention that any text file should end with a newline character (\n), and as a programmer you should also follow this convention on other systems.
If you use the small Copy to clipboard icon in the top right corner of each code block instead of marking the text, it will automatically be copied with an extra newline at the end.

We can inspect an arbitraty commit by using its hash (at least the first 4 characters, typically 7). We view the first commit. Get the hash from the previous log output

git show d8d9072

We can also compare arbitrary commits

git diff <old-hash> <new-hash>
git diff d8d9072 43bc0a8

The output should look similar to that of the two calls above, just showing other diffs.

Amend a commit

Oops, we forgot to link the file in README.md. This is only a small change that belongs to our last commit. We don't want to make a new commit, but we can amend the previous one.

Add the link to README.md and add an empty line at its end.

# Git Workshop

Content

* [Linear workflow](linear-workflow.md)
* ...
* ...

Also, fix the newline at the end of file linear-workflow.md

New file content
# Linear workflow

```
git init
```

* Create file README.md

```
git status
git add README.md
git status
git commit -m "initial commit"
git status
```

Check the status.

git status
Output
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:   README.md
        modified:   linear-workflow.md

With git diff, we can also view changes in files compared to what is committed (actually, committed + staged).

git diff
Output
diff --git a/README.md b/README.md
index e266d1c..6ecdc70 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,6 @@

 Content

+* [Linear workflow](linear-workflow.md)
 * ...
 * ...
-* ...
\ No newline at end of file
diff --git a/linear-workflow.md b/linear-workflow.md
index d039c21..fda7fd8 100644
--- a/linear-workflow.md
+++ b/linear-workflow.md
@@ -12,4 +12,4 @@
 > git status
 > git commit -m "initial commit"
 > git status
-```
\ No newline at end of file
+```
git add README.md linear-workflow.md
git status
Output
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   README.md
        modified:   linear-workflow.md

To amend the last commit rather than create a new one, commit with option --amend

git commit --amend

As we did not enter a message this time, the text editor will pop up. Change the message if you want, save and close the editor.

Output
...
[main 1860049] added linear workflow
 Date: Wed Jan 27 20:27:02 2021 +0100
 2 files changed, 16 insertions(+), 1 deletion(-)
 create mode 100644 linear-workflow.md

Inspect the history again to see that there is no new commit

git log
Output
commit 1860049c5afd2ffed4661e8e36745aec3da57183 (HEAD -> main)
Author: ... <...@ufz.de>
Date:   Wed Jan 27 20:27:02 2021 +0100

    added linear workflow

commit d8d9072990da891df3624358b7a8fc473afb57f8
Author: ... <...@ufz.de>
Date:   Wed Jan 27 20:25:35 2021 +0100

    initial commit

However, the hash of the top-most commit changed. Further, the diff of the last commit now contains our change

git show

We can also show the diff for a single file

git show README.md

Check out older states

Sometimes it may be necessary to revert a file to a state from the history, or just to view its old content.

git checkout 3cda487 -- README.md

(Use the hash of your first commit, it will be different!)

View the status to see what happened

git status
Output
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   README.md

We have staged changes in file README.md. It is a bit of a quirk that the file is staged, but that's how it is. View the file in the text editor to note that is now looks like after your first commit.

To return to the latest version, check out the file for HEAD

git checkout HEAD -- README.md
git status
Output
On branch main
nothing to commit, working tree clean
1

echo. writes text to the console. Using >, we redirect this (empty) text to the file and thereby create it. The dot . is required because without an argument (i.e. without text to write), echo switches the echo mode on or off, instead of writing text.


Continue with Exercise 2

Exercise 2 - Non-linear workflow with branches

In this exercise, you will learn how to work with branches. You will create branches, merge them and resolve a conflict.

Create a branch

We want to take some further notes from the workshop. However, we will now work on different branches and start with the chapter on how to inspect the history. First, create a new branch inspect-history

git branch inspect-history

Let's list the branches we have now

git branch
Output
  inspect-history
* main

Fine, but we are still on main. Switch to inspect-history and list branches again

git switch inspect-history
git branch
Output
* inspect-history
  main

The switch command is relatively new in Git. On older versions, you have to use checkout instead. The command checkout can do different things, depending on the context and the arguments. To reduce ambiguities, in newer versions of Git switch can be used instead of checkout to switch between branches, and restore --staged to un-stage changes.

We now have two branches and are currently on inspect-history. When using git log, you will see that both branches point to the same commit.

git log
Output
commit 1860049c5afd2ffed4661e8e36745aec3da57183 (HEAD -> inspect-history, main)
Author: ... <...@ufz.de>
Date:   Wed Jan 27 20:27:02 2021 +0100

    added linear workflow

commit d8d9072990da891df3624358b7a8fc473afb57f8
Author: ... <...@ufz.de>
Date:   Wed Jan 27 20:25:35 2021 +0100

    initial commit

BTW, HEAD shows where you currently are.

There is also a shortcut that creates a branch and switches to it immediately

git switch -c inspect-history

Make changes on a branch

Create a new file inspecting.md

echo.> inspecting.md

Fill it with some content, e.g.

# Inspecting

## Inspect the history

```
git log
```

## Inspecting commits

```
git show
git show 3cda487
git show README.md
```

Save your changes.

Link it in README.md and save again.

# Git Workshop

Content

* [Linear workflow](linear-workflow.md)
* [Inspecting](inspecting.md)
* ...

Now, commit as usual

git status
git diff
git add README.md inspecting.md
git status
git commit -m "added page on inspecting the history"

Let's view the history again

git log

For a more compact view, use

git log --oneline
Output
eba0f8f (HEAD -> inspect-history) added page on inspecting the history
1860049 (main) added linear workflow
d8d9072 initial commit

You will see that branch inspect-history is now one commit ahead of main. I.e. it moved along with our changes, while main did not.

Switching between branches

With Git, it is possible to work on multiple branches in parallel. Using switch, we can simply switch between branches. Observe the content of your project folder. There are now three Markdown files.

Switch to main and see the folder content again

git switch main

Now, the file inspecting.md isn't there anymore. When we switched to main, Git replaced the files in our working copy with the version referenced by main. Switch to branch inspect-history again to see that the working copy changes again and inspecting.md is back again.

git switch inspect-history

Another branch

We now make some parallel edits on an additional branch. First, switch to main again, as we want to start from there rather than from inspect-history

git switch main

Create another branch amending-commits where we will take notes on that aspect

git switch -c amending-commits

Create a new file amending.md

echo.> amending.md

Fill it the following content (and save...)

# Amending commits

```
git status
git diff
git add README.md
git commit --amend
```

Link the file in README.md

# Git Workshop

Content

* [Linear workflow](linear-workflow.md)
* [Amending commits](amending.md)
* ...

You may notice that the link to inspecting.md has gone. This is because we went back to branch main, which does not contain that change.

Commit as usual

git status
git diff
git add README.md amending.md
git status
git commit -m "added page on amending commits"

Let's inspect again what we have, with option --oneline for a more compact view

git log --oneline
Output
0639ed4 (HEAD -> amending-commits) added page on amending commits
1860049 (main) added linear workflow
d8d9072 initial commit

You may be surprised where branch inspect-history has gone. This is because by default, Git only shows what is part of the history of the current state, which inspect-history is not. To see the entire history as a (directed acyclic) graph, add options --all and --graph

git log --graph --oneline --all
Output
* 0639ed4 (HEAD -> amending-commits) added page on amending commits
| * eba0f8f (inspect-history) added page on inspecting the history
|/
* 1860049 (main) added linear workflow
* d8d9072 initial commit

You should see the entire graph now, and that we have diverged from main in two different directions.

Merge

When the work on a branch is completed, it can be merged back into main. To merge, you need to be on the branch you want to merge the other branch into. So we switch to main

git switch main

Now, merge amending-commits into the current branch main

git merge amending-commits
Output
Updating 1860049..0639ed4
Fast-forward
 README.md   | 2 +-
 amending.md | 8 ++++++++
 2 files changed, 9 insertions(+), 1 deletion(-)
 create mode 100644 amending.md

Inspect the graph again

git log --graph --oneline --all
Output
* 0639ed4 (HEAD -> main, amending-commits) added page on amending commits
| * eba0f8f (inspect-history) added page on inspecting the history
|/
* 1860049 added linear workflow
* d8d9072 initial commit

Now, main and amending-commits point to the same commit, but somehow our branching topology has gone. This is because Git makes a so-called "fast-forward" merge in case there are no conflicts. We can prevent that with the option --no-ff. But first, we have to undo the merge.

Reset a branch

To bring main back to the state before the merge, we make a hard reset to the previous commit (use the correct hash, the 3rd counted from the top!)

git reset --hard 1860049
Output
HEAD is now at 1860049 added linear workflow

Inspect again to see that we have what we had before the merge

git log --graph --oneline --all
Output
* 0639ed4 (HEAD -> amending-commits) added page on amending commits
| * eba0f8f (inspect-history) added page on inspecting the history
|/
* 1860049 (main) added linear workflow
* d8d9072 initial commit

Merge with an extra commit

Now, we can merge without "fast-forward"

git merge amending-commits --no-ff
Output
Merge made by the 'recursive' strategy.
 README.md   | 2 +-
 amending.md | 8 ++++++++
 2 files changed, 9 insertions(+), 1 deletion(-)
 create mode 100644 amending.md

Inspect again to see that the branching topology is preserved now

git log --graph --oneline --all
Output
*   e25d3cc (HEAD -> main) Merge branch 'amending-commits'
|\
| * 0639ed4 (amending-commits) added page on amending commits
|/
| * eba0f8f (inspect-history) added page on inspecting the history
|/
* 1860049 added linear workflow
* d8d9072 initial commit

Further, a new commit was created, with an automatic message (Merge branch 'amending-commits')

Merge with conflict

We can now try to also merge branch inspect-history

git merge inspect-history --no-ff
Output
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.

Git says that automatic merging failed due to a conflict in README.md, and that we should resolve the conflict and then commit. This is also a reminder to always read Git's output carefully.

To get some more insights, check the status

git status
Output
On branch main
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Changes to be committed:
        new file:   inspecting.md

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   README.md

Again, read carefully! We have unmerged paths. Further, is says we can resolve the conflicts and commit, or abort. merge is an example of a modal command, i.e. we have to commit or abort the merge before we can continue to use Git normally. For practice, we abort the merge and view the status:

git merge --abort
git status
Output
On branch main
nothing to commit, working tree clean

That was for practice. Now let's merge again and resolve the conflict.

git merge inspect-history --no-ff
Output
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.

We get the same message as before: that automatic merging failed due to a conflict in README.md.

Resolve conflicts

Open file README.md. It has the following content

# Git Workshop

Content

* [Linear workflow](linear-workflow.md)
<<<<<<< HEAD
* [Amending commits](amending.md)
=======
* [Inspecting](inspecting.md)
>>>>>>> inspect-history
* ...

The content between <<<<<<< HEAD and >>>>>>> inspect-history is where the conflict is, with the first part on main (our current HEAD), and the second part on inspect-history. Resolve the conflict and make the file look like this

# Git Workshop

Content

* [Linear workflow](linear-workflow.md)
* [Inspecting](inspecting.md)
* [Amending commits](amending.md)

Now that the conflict is resolved we can stage as usual

git status
git diff
git add README.md
git status
Output
On branch main
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:
        modified:   README.md
        new file:   inspecting.md

Git tells us that all conflicts are fixed, but we are still merging. We do what it suggests and commit

git commit

Leave the message in the popup as is and close it.

Through the commit, we finished the merge and are now no longer in "merge mode". Confirm through checking the status

git status
Output
On branch main
nothing to commit, working tree clean

Inspect the graph again

git log --graph --oneline --all
Output
*   fc527c5 (HEAD -> main) Merge branch 'inspect-history'
|\
| * eba0f8f (inspect-history) added page on inspecting the history
* |   e25d3cc Merge branch 'amending-commits'
|\ \
| |/
|/|
| * 0639ed4 (amending-commits) added page on amending commits
|/
* 1860049 added linear workflow
* d8d9072 initial commit

We see two nicely merged branches.

To finish our work, we should delete the merged branches. They are only pointers and not needed anymore. The topology will remain untouched by deleting them

git branch --delete amending-commits
git branch --delete inspect-history

And, a final check that everything worked as expected

git log --graph --oneline --all
*   fc527c5 (HEAD -> main) Merge branch 'inspect-history'
|\
| * eba0f8f added page on inspecting the history
* |   e25d3cc Merge branch 'amending-commits'
|\ \
| |/
|/|
| * 0639ed4 added page on amending commits
|/
* 1860049 added linear workflow
* d8d9072 initial commit

Continue with Exercise 3

Exercise 3 - Sharing changes

In this exercise, you will learn how to work with a remote repository. You will create a GitLab project, push your project to it and pull changes from the remote to your local project.

Create a GitLab project

  1. Log into your GitLab account
  2. Click the + button in the middle of the top bar and select New project
  3. Select Create blank project
  4. Fill the text field Project name with git-workshop
  5. Leave everything else as is and click Create project at the bottom of the page

You now have an empty private project. However, there are some useful instructions how to proceed. Only the last section is relevant for us (Push an existing Git repository, partially). Settings of the first sections were made in the first exercise (Git global setup).

Push your repository

From the last section (Push an existing Git repository), we ignore the first two lines. We set the remote for our repository

git remote add origin https://git.ufz.de/<you>/git-workshop.git

Finally, we push our branch main to the remote repository

git push --set-upstream origin main
Output
Enumerating objects: 19, done.
Counting objects: 100% (19/19), done.
Delta compression using up to 8 threads
Compressing objects: 100% (17/17), done.
Writing objects: 100% (19/19), 2.68 KiB | 915.00 KiB/s, done.
Total 19 (delta 4), reused 0 (delta 0), pack-reused 0
To https://git.ufz.de/mlange/git-workshop.git
 * [new branch]      main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.

At this point, Git will ask for your login and password. Use your normal UFZ login here.

When completed, refresh your project's page. You will see some statistics, a list of your project files, and a nicely rendered version of README.md.

Finally, we check the graph

git log --graph --oneline --all
Output
*   fc527c5 (HEAD -> main, origin/main) Merge branch 'inspect-history'
|\
| * eba0f8f added page on inspecting the history
* |   e25d3cc Merge branch 'amending-commits'
|\ \
| |/
|/|
| * 0639ed4 added page on amending commits
|/
* 1860049 added linear workflow
* d8d9072 initial commit

Notice that there is now a branch origin/main, in addition to main. Both point to the same commit.

Pull changes

We will simulate changes made by others by editing file README.md online.

In the file list, click README.md. Click the blue edit button above the text. Make a change to the file, e.g. by adding a brief description

# Git Workshop

Notes taken in the OESA Git workshop.

Content

* [Linear workflow](linear-workflow.md)
* [Inspecting](inspecting.md)
* [Amending commits](amending.md)

At the top of the page, there is a Preview tab where you can check that your changes render as expected.

Scroll to the bottom of the page and click Commit changes (you may want to change the commit message, too).

To make Git notice remote changes, we need to "fetch"

git fetch
Output
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 457 bytes | 57.00 KiB/s, done.
From https://git.ufz.de/.../git-workshop
   fc527c5..f39b285  main       -> origin/main

Check the graph again to see what happened

git log --graph --oneline --all
Output
* f39b285 (origin/main) Update README.md
*   fc527c5 (HEAD -> main) Merge branch 'inspect-history'
|\
| * eba0f8f added page on inspecting the history
* |   e25d3cc Merge branch 'amending-commits'
|\ \
| |/
|/|
| * 0639ed4 added page on amending commits
|/
* 1860049 added linear workflow
* d8d9072 initial commit

Branch origin/main is now one commit ahead of our local main. To update the local branch, we need to pull

git pull
Output
Updating fc527c5..f39b285
Fast-forward
 README.md | 2 ++
 1 file changed, 2 insertions(+)

Check the graph again

git log --graph --oneline --all
Output
* f39b285 (HEAD -> main, origin/main) Update README.md
*   fc527c5 Merge branch 'inspect-history'
|\
| * eba0f8f added page on inspecting the history
* |   e25d3cc Merge branch 'amending-commits'
|\ \
| |/
|/|
| * 0639ed4 added page on amending commits
|/
* 1860049 added linear workflow
* d8d9072 initial commit

Now, origin/main and main point to the same commit again.


Continue with Exercise 4

Exercise 4 - Collaborate using GitLab

In this exercise, you will learn how to use the most essential collaboration features of GitLab. You will create and manage issues and create, discuss and finalize a Merge Request.

Create an issue

  1. On your project's GitLab page, click Issues in the navigation at the left
  2. Click New issue at the bottom of the page
  3. Fill fields Title and Description with some content

Title

Better description in README.md

Description

Add a more informative description in file `README.md`

* [ ] What is the project about
* [ ] How to use the project

Check the Preview tab of the description field. Click Submit issue when you are fine with the content of the preview.

You should now see the page of the issue. There are several actions available at the right, and there is a text field at the bottom to start a discussion about the issue.

Manage issues with boards

In the left navigation, under Issues, click Boards. A Kanban board with your issue in column Open will appear.

To create more lists, in addition to Open and Closed, click Add list (top right), and select Create project label. Enter In Progress as name, select a color and scroll down to click Create.

Drag the issue to column In Progress. This wil automatically label the issue with In Progress. In the left navigation, under Issues, click List to see that the issue is labelled now.

Create a merge request

We will now fix the issue on a new branch and create a merge request for the fix.

Create and switch to a new branch better-description

git switch -c better-description

Edit file README.md by replacing its content with

# Git Workshop

Notes taken in the OESA Git workshop in early 2021.

Use the project by browsing the files linked below, and by trying the commands listed there.

Content

* [Linear workflow](linear-workflow.md)
* [Inspecting](inspecting.md)
* [Amending commits](amending.md)

Commit as usual

git status
git diff
git add README.md
git commit -m "enhanced description in README.md"

Push the branch to the GitLab project

git push --set-upstream origin better-description
Output
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 760 bytes | 760.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: To create a merge request for better-description, visit:
remote:   https://git.ufz.de/mlange/git-workshop/-/merge_requests/new?merge_request%5Bsource_branch%5D=better-description
remote:
To https://git.ufz.de/mlange/git-workshop.git
 * [new branch]      better-description -> better-description
Branch 'better-description' set up to track remote branch 'better-description' from 'origin'.

Go back to your project's GitLab page and refresh it. At the very top, there is a notification that you just pushed branch better-description, with a button Create merge request. Click that button.

You will see a form that looks very similar to the issue form. Fill the description with some informative content.

Enhanced description according issue #1.

Fixes #1.

Check the Preview, and click Submit merge request.

Scan through the merge request's page. Also check the tabs Commits and Changes, right below the heading.

Discuss changes

In tab Changes you can comment on individual lines. In the right half (the new version), hover over line 5. Left of the line, a small speech bubble icon will appear. Click it!

Enter a comment in the appearing text field, e.g.

We could add that the commands are Git commands.

Press Add comment now. Go back to the Overview tab. Notice the 1 unresolved thread next to the heading. Click the speech bubble with the arrow next to it to jump to the thread. Below your comment is a text box for others to reply.

Resolve threads

We will resolve the discussion by changing file README.md again. Open it locally with a text editor and replace the content with

# Git Workshop

Notes taken in the OESA Git workshop in early 2021.

Use the project by browsing the files linked below, and by trying the git commands listed there.

Content

* [Linear workflow](linear-workflow.md)
* [Inspecting](inspecting.md)
* [Amending commits](amending.md)

Check diffs and commit as usual

git status
git diff
git add README.md
git commit -m "added note that the commands are git commands"

Push again. Now that the branch was pushed and the upstream repository was set with --set-upstream origin, we can use a shorter form

git push

Preview a branch

You can also preview the rendered version of the branch. Go to the project's main page by clicking git-workshop on the very top left.

Below ths statistics, there is a dropdown with main. Click it and select better-description. The page now shows the version on your branch.

If you scroll down and check the content, you may notice that we have a typo there. Git should be capitalized!

Amend last commit

Open file README.md locally and fix the typo.

Inspect and stage changes

git status
git diff
git add README.md
git status

As this is a tiny change belonging to the previous commit, we amend this time

git commit --amend

Close the popup message editor.

We can now push again

git push
Output
To https://git.ufz.de/mlange/git-workshop.git
 ! [rejected]        better-description -> better-description (non-fast-forward)
error: failed to push some refs to 'https://git.ufz.de/mlange/git-workshop.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Oops, red text! You should always read Git's messages carefully! It says that "Updates were rejected because the tip of your current branch is behind its remote counterpart". Let's check the status, maybe this helps us

git status
Output
On branch better-description
Your branch and 'origin/better-description' have diverged,
and have 1 and 1 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)

nothing to commit, working tree clean

It tells us that "Your branch and 'origin/better-description' have diverged, and have 1 and 1 different commits each, respectively." We can better see what is meant here by viewing the graph

git log --graph --oneline --all
Output
* 8226777 (HEAD -> better-description) added note that the commands are git commands
| * 89a8e14 (origin/better-description) added note that the commands are git commands
|/
* 39d2543 enhanced description in README.md
* f39b285 (origin/main, main) Update README.md
*   fc527c5 Merge branch 'inspect-history'
|\
| * eba0f8f added page on inspecting the history
* |   e25d3cc Merge branch 'amending-commits'
|\ \
| |/
|/|
| * 0639ed4 added page on amending commits
|/
* 1860049 added linear workflow
* d8d9072 initial commit

The error message as well as git status suggest that we should pull, but that is not what we want. Instead, we have to force-push here with option --force-with-lease

git push --force-with-lease

There is also the shorter option --force, but it is strongly discouraged to use it as it can be destructive if a collaborator (or you) already committed on top of the amended commit.

Refresh the repository's page (still on branch better-description) to see that the fix is there.

Resolve the merge request

Go back to the merge request's page and jump or scroll to the unresolved thread. Then, either

  • Press button Resolve thread, or
  • Write something into the text box directly beneath (!) your first comment, tick Resolve thread, and press Add comment now

Now, all threads are resolved. Scroll up to the green Merge button and press it to merge the branch into main.

Update local repository

Fetch the changes from the remote with option --prune to prune the merged and automatically deleted remote branch

git fetch --prune

Switch to branch main and pull it

git switch main
git pull

Check the graph

git log --graph --oneline --all
Output
*   a3d243a (HEAD -> main, origin/main) Merge branch 'better-description' into 'main'
|\
| * 8226777 (better-description) added note that the commands are git commands
| * 39d2543 enhanced description in README.md
|/
* f39b285 Update README.md
*   fc527c5 Merge branch 'inspect-history'
|\
| * eba0f8f added page on inspecting the history
* |   e25d3cc Merge branch 'amending-commits'
|\ \
| |/
|/|
| * 0639ed4 added page on amending commits
|/
* 1860049 added linear workflow
* d8d9072 initial commit

Delete the local branch better-description, which is not required anymore

git branch --delete better-description

Check the graph again

git log --graph --oneline --all

Continue with Exercise 5

Exercise 5 - Ignoring files

In this exercise, you will learn how to make Git ignore certain files. You will convert your Markdown files into a HTML file and write a .gitignore file to ignore it.

Generate a HTML page

You may want to generate an all-in-one document of your notes to send it to a friend, or simply to see how it looks like in its rendered form. We will do that using Pandoc.

First, create a sub-folder documents

mkdir documents

Next, we convert all Markdown files into a single HTML file

pandoc README.md linear-workflow.md inspecting.md amending.md -o documents/README.html

Navigate into folder documents using the explorer and view the output.

We could now commit the document. However, it is good practice to not commit anything that can be generated from the project's sources. This applies also to compiled binaries, like your model's .exe file.

But let's check the status first

git status
Output
On branch main
Your branch is up to date with 'origin/main'.

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

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

which should show documents/ as unstaged.

Ignore files

One way to not commit a file it not to stage it. But there is a better way provided by Git: .gitignore files.

At the top level of your project (i.e. in git-workshop), create a file .gitignore (notice the dot! 1).

echo.> .gitignore

Open the file in your text editor. Here, we can list files, directories or file name patterns to be ignored, one entry per line. We will ignore the entire documents folder. Fill the file with the following content

/documents/

For details on how to ignore directories, files, patterns etc. see the gitignore documentation.

Check the status again

git status
Output
On branch main
Your branch is up to date with 'origin/main'.

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

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

The file .gitignore is listed as unstaged, but documents/ disappeared, which is exactly what was our aim.

We can now commit as usual, and also push

git add .gitignore
git status
git commit -m "added gitignore file to ignore documents"
git push

and view the graph again

git log --graph --oneline
Output
* 2b94010 (HEAD -> main, origin/main) added gitignore file to ignore documents
*   a3d243a Merge branch 'better-description' into 'main'
|\
| * 8226777 added note that the commands are git commands
| * 39d2543 enhanced description in README.md
|/
* f39b285 Update README.md
*   fc527c5 Merge branch 'inspect-history'
|\
| * eba0f8f added page on inspecting the history
* |   e25d3cc Merge branch 'amending-commits'
|\ \
| |/
|/|
| * 0639ed4 added page on amending commits
|/
* 1860049 added linear workflow
* d8d9072 initial commit

Continue with Exercise 6

1

The leading dot is a naming convention for hidden files.

Exercise 6 - Tags for reproducibility

In this exercise, you will learn how use tags. You will create tags, push them to the remote repository and inspect them.

Create tags

We want to add two tags, one to the commit before our merge request, and one to the current state.

View the graph to get the hash of the commit we want to tag first

git log --graph --oneline --all
Output
* 2b94010 (HEAD -> main, origin/main) added gitignore file to ignore documents
*   a3d243a Merge branch 'better-description' into 'main'
|\
| * 8226777 added note that the commands are git commands
| * 39d2543 enhanced description in README.md
|/
* f39b285 Update README.md
*   fc527c5 Merge branch 'inspect-history'
|\
| * eba0f8f added page on inspecting the history
* |   e25d3cc Merge branch 'amending-commits'
|\ \
| |/
|/|
| * 0639ed4 added page on amending commits
|/
* 1860049 added linear workflow
* d8d9072 initial commit

Then, we add a tag v0.1.0 to that commit

git tag v0.1.0 f39b285

Tagging the current commit is even simpler

git tag v0.1.1

View the graph again

git log --graph --oneline --all
Output
* 2b94010 (HEAD -> main, tag: v0.1.1, origin/main) added gitignore file to ignore documents
*   a3d243a Merge branch 'better-description' into 'main'
|\
| * 8226777 added note that the commands are git commands
| * 39d2543 enhanced description in README.md
|/
* f39b285 (tag: v0.1.0) Update README.md
*   fc527c5 Merge branch 'inspect-history'
|\
| * eba0f8f added page on inspecting the history
* |   e25d3cc Merge branch 'amending-commits'
|\ \
| |/
|/|
| * 0639ed4 added page on amending commits
|/
* 1860049 added linear workflow
* d8d9072 initial commit

Push tags

We now have two tags, but they are only local. Push all tags to the remote

git push --tags
Output
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
To https://git.ufz.de/mlange/git-workshop.git
 * [new tag]         v0.1.0 -> v0.1.0
 * [new tag]         v0.1.1 -> v0.1.1

Inspect tags

To view a list of all tags, use

git tag
Output
v0.1.0
v0.1.1

Individual tags can be inspected with git show, just like commits

git show v0.1.0
git show v0.1.1

The output should look like when showing a commit.


Continue with Exercise 7

Exercise 7 - Keep branches up-to-date

In this exercise, you will learn how to keep branches up-to-date with changes made by collaborators (or yourself). You will back-merge branch main into a topic branch.

Make changes on a branch

We continue our work on taking notes, again on a separate branch. Create and switch to a new branch branching and check the result

git switch -c branching
git branch

Create a new file branching.md

echo.> branching.md

Fill it with

# Branching

## Create a new branch

```
git branch inspect-history
git switch inspect-history
git branch
```

Link the file in README.md

# Git Workshop

Notes taken in the OESA Git workshop in early 2021.

Use the project by browsing the files linked below, and by trying the Git commands listed there.

Content

* [Linear workflow](linear-workflow.md)
* [Inspecting](inspecting.md)
* [Amending commits](amending.md)
* [Branching](branching.md)

Then, commit as usual

git status
git diff
git add README.md branching.md
git status
git commit -m "added page on branching"

Simulate changes by a collaborator

Meanwhile, a collaborator (or you) may have made changes to branch main, e.g. by merging a Merge Request. We simulate that by making an online edit.

Go to your project's page and edit REAMDE.md. Add a final note

# Git Workshop

Notes taken in the OESA Git workshop in early 2021.

Use the project by browsing the files linked below, and by trying the Git commands listed there.

Content

* [Linear workflow](linear-workflow.md)
* [Inspecting](inspecting.md)
* [Amending commits](amending.md)

For further information, see the [OESA Git Workshop book](https://oesa.pages.ufz.de/git-exercises).

Preview and commit your changes on target branch main (should be already set).

Pull the changes

Pull the changes into your local repository

git switch main
git pull

Then, check the graph

git log --graph --oneline --all
Output
* 653207e (HEAD -> main, origin/main) Update README.md
| * 3e445bb (branching) added page on branching
|/
* 2b94010 (tag: v0.1.1) added gitignore file to ignore documents
*   a3d243a Merge branch 'better-description' into 'main'
|\
| * 8226777 added note that the commands are git commands
| * 39d2543 enhanced description in README.md
|/
* f39b285 (tag: v0.1.0) Update README.md
*   fc527c5 Merge branch 'inspect-history'
|\
| * eba0f8f added page on inspecting the history
* |   e25d3cc Merge branch 'amending-commits'
|\ \
| |/
|/|
| * 0639ed4 added page on amending commits
|/
* 1860049 added linear workflow
* d8d9072 initial commit

As expected, main has diverged.

Back-merge into your branch

Before you continue your work on branch branching, you may want to update it to the latest state of main. Do that by merging main into branching

git switch branching
git merge main

There is a conflict in README.md again, but you already know how to resolve it. Open the file locally and recolve the conflict. The result should look like this

# Git Workshop

Notes taken in the OESA Git workshop in early 2021.

Use the project by browsing the files linked below, and by trying the Git commands listed there.

Content

* [Linear workflow](linear-workflow.md)
* [Inspecting](inspecting.md)
* [Amending commits](amending.md)
* [Branching](branching.md)

For further information, see the [OESA Git Workshop book](https://oesa.pages.ufz.de/git-exercises).

Then, commit as usual

git status
git diff
git add README.md
git status
git commit

As before, close the editor popup to complete the commit.

Finally, inspect the graph again

git log --graph --oneline --all
*   e8ed3fd (HEAD -> branching) Merge branch 'main' into branching
|\
| * 653207e (origin/main, main) Update README.md
* | 3e445bb added page on branching
|/
* 2b94010 (tag: v0.1.1) added gitignore file to ignore documents
*   a3d243a Merge branch 'better-description' into 'main'
|\
| * 8226777 added note that the commands are git commands
| * 39d2543 enhanced description in README.md
|/
* f39b285 (tag: v0.1.0) Update README.md
*   fc527c5 Merge branch 'inspect-history'
|\
| * eba0f8f added page on inspecting the history
* |   e25d3cc Merge branch 'amending-commits'
|\ \
| |/
|/|
| * 0639ed4 added page on amending commits
|/
* 1860049 added linear workflow
* d8d9072 initial commit

This starts to look a bit confusing. Here is an alternative visualization that better conveys what really happened

 ╭>○    e8ed3fd (HEAD -> branching) Merge branch 'main' into branching
 ● │    653207e (main, origin/main) Update README.md
 │ ●    3e445bb added page on branching
 ├─╯
 ●      2b94010 [v0.1.1] added gitignore file to ignore documents
 ○<╮    a3d243a Merge branch 'better-description' into 'main'
 │ ●    8226777 added note that the commands are git commands
 │ ●    39d2543 enhanced description in README.md
 ├─╯
 ●      f39b285 [v0.1.0] Update README.md
 ○<──╮  fc527c5 Merge branch 'inspect-history'
 ○<╮ │  e25d3cc Merge branch 'amending-commits'
 │ ● │  0639ed4 added page on amending commits
 ├─╯ ●  eba0f8f added page on inspecting the history
 ├───╯
 ●      1860049 added linear workflow
 ●      d8d9072 initial commit

This visualization was created with git-graph. For an interactive version that also allows you to view commits, diffs, etc. see git-igitt.

How to continue

This chapter provides some links and recommendations on how to continue using and learning Git.

Further reading

Some reading suggestions to continue with:

Recommended GUI clients

For those who prefer to work with a GUI client rather than the command line:

  • Sourcetree is a freeware GUI client for Windows & MacOS.
  • Some text editors like Atom and many IDEs like IntelliJ and Eclipse have a Git integration or plugin.
  • git-igitt is a TUI client for browsing the history in the console.

The Git documentation provides an extensive list of GUI clients.

Git forges

Git forges are online platforms where you can host repositories, and get a lot of other features for project management and collaboration.

UFZ

Use the UFZ GitLab for your work-related projects. Non-UFZ collaborators can get an account there, just contact the WKDV.

Don't put your personal/hobby projects there, as they will then be owned by the UFZ.

Other

The most famous platforms to use for online repositories:

  • On GitLab.com, you get the same features as with the UFZ GitLab instance. They offer a free plan with unlimited public and private repositories.
  • GitHub is the most famous Git forge out there. If you want to find contributors to your projects, you probably have the best chance there. It has similar features like GitLab, and also offers a free plan.

Both GitHub and GitLab offer all features you need for your projects, from merge requests over issue trackers and wikis to Continuous Integration. For a comparison between GitHub and GitLab, see e.g. this blog post.

CheatSheet Command Line

Command Effect Examples
dir List directory content dir
dir *.md
cd <dir> Navigate into directory cd Projects
cd .. Navigate to parent directory
mkdir <dir>
md <dir>
Create a directory mkdir git-workshop
help
help <cmd>
Get help (for a command) help mkdir
<cmd> > <file> Redirect output to file dir > out.txt
echo Hello World > out.txt
<cmd> >> <file> Redirect (append) output to file dir >> out.txt
type <file> Display the content of a file type README.md
start <file> Start a program or open a file start notepad
start README.md
Ctrl+C Exit/abort the current program
Up/Down Arrows Scroll through previous command

CheatSheet Git Commands

Command Effect Examples
init Initialize a local repo git init
clone Clone a remote repo git clone https://git.ufz.de/oesa/git-exercises.git
status View the repo status git status
show Show different things git show
git show v0.1.0
git show 3cda487
diff View diffs git diff
git diff README.md
git diff 3cda487 c8b0455
log Show the repo's history git log
git log --all
git log --graph --oneline --all
add Stage files git add README.md
git add *.md
git add --all
reset Un-stage files git reset README.md
git reset --all
commit Commit staged changes git commit
git commit -m "A commit message"
git commit --amend
checkout Checkout, e.g. branch git checkout main
branch List, create, delete branches git branch
git branch my-feature
git branch --delete my-feature
merge merge branch into current branch git merge my-feature
git merge my-feature --no-ff
fetch Get remote changes git fetch
pull Pull changes from remote git pull origin main
git pull --all
push Push something to remote git push -u origin main
git push --tags
tag List and create tags git tag
git tag v0.1.0
git tag v0.1.0 f3c5a77