---
title: "Introduction to git"
draft: false
date: 2019-10-22T19:00:00+02:00
image: "uploads/Git-Logo-2Color.png"
tags: [GIT, training, tutorial]
categories: [Projects, English]
---

As you man now I work in a research lab. Nearly everyone in our lab needs to do at least some programming. There are trained software engineers next to people how write their first line of code here. 
As we produce a lot of code that is only scripts not many people used git or any other version control system. 
For all the good reasons (some are mentioned in the guide) we everybody to learn git in a way that is tradeoff between good version control and fast development. 
As most of us work on separate projects there is not so much need to collaborate which is reflected ind this guide as I completely excluded branching and merge conflicts.
Yet I hope this will maybe help some learners of git or some people that need to introduce git to others.

I will not be updating this guide, for the newest version please visit https://github.com/GerJuli/introduction-to-git


Now enjoy the guide!

# Installation

* On Windows: Download git here: https://git-scm.com/download/win and install it
* On Linux: execute 'sudo apt install git' in the terminal

# Configuration

## Basics

```bash
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
```

Run these commands without --global to apply changes only for local repository.

## Advanced

* Change from default editor by executing  `$ git config --global core.editor vim`
* Create aliases by: 
    - `git config --global alias.unstage 'reset HEAD --'`:
    Introduces new command unstage

    - `git config --global alias.hist 'log --pretty=format:"%h - %an, %ar : %s" --graph'`:
    Is an pretty alternative to git log.

* Check the configuration by `$ git config --list`

# Getting started

## Create an directory
Select an directory of your choice e.g. ~/Desktop/git-training/, 
open the terminal there and type 

```bash
$ git init
```
Congratulations you have your first git repository!

## Committing files
Create some text files e.g. `hallo.txt` or  `hello_world.py`.
To start version-controlling them add the file to git by using the command 
```bash
$ git add filename
```
You can also add multiple files. E.g. you want to add all text files the do 
```bash
$ git add *.txt
```
Now we can commit these changes by typing 
```bash
$ git commit
```
This will open your preferred text editor
where you can type in a commit message.

### Commit messages

*Commit messages are important*

Why are the so important? Because it is much easier to track bugs with it,
they describe the process of development, make it easier for others to work
with your code (e.g. code review) and will help you in two years to understand what you did.
They extend your labbook in its function.

#### How to write commit messages
* Use present tense and use imperative
* Tell why you did changes.
* Limit yourself to 50 characters in the first line.
* Wrap the body at 72 characters

#### Good commit messages

For short commits that need only few explanation it is convenient to use 
```bash
$ git commit -m "Fix typo in introduction to user guide"
```

For long commit message you use 
```bash
$ git commit 
```
which opens a text editor and lets you describe your changes in detail. Do not forget the line
between header and body of the commit message.

```
Summarize changes in around 50 characters or less

More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of the commit and the rest of the text as the body. The
blank line separating the summary from the body is critical (unless
you omit the body entirely); various tools like `log`, `shortlog`
and `rebase` can get confused if you run the two together.

Explain the problem that this commit is solving. Focus on why you
are making this change as opposed to how (the code explains that).
Are there side effects or other unintuitive consequences of this
change? Here's the place to explain them.

Further paragraphs come after blank lines.

 - Bullet points are okay, too

 - Typically a hyphen or asterisk is used for the bullet, preceded
   by a single space, with blank lines in between, but conventions
   vary here

```

#### Hall of shame
Here you see some examples of bad commit messages.

* “bug fix”, "more work”, “minor changes”:
Bad because it contains no useful information

* “Change X constant to be 10”:
Bad as it does not tell why. What was changed is easy to find out by
  git diff.

* “super long commit message goes here, something like 100 words and lots of characters woohoo!”:
Bad because it is unreadable.

## Storing changes on remote server
To store changes on a remote server e.g. Github you need to push your repository there.
If you are doing this for the first time you first need to define where to push your repository to.
Use 

```bash
$ git remote add origin https://github.com/GerJuli/introduction-to-git.git
```

The URL can be
replaced with any URL that points to an existing repository. This can even be a USB drive!
Now push by using `git push -u origin master`. With this command you created an upstream to your
remote 'origin' where you branch 'master' will be pushed.
As this is set up you can use `git push` from now on.

# Cloning existing repositories
Downloading existing repositories is called 'cloning'. You can do this by using
```bash
$ git clone https://github.com/GerJuli/introduction-to-git.git
```
That is it. Now you can start working on it.

# Workflow

## Check status
With 
```bash
$ git status
``` 
you can check the status of your current directory.
This will look like this:

```bash
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
```

## Add file
If you now add a file to the repository e.g. README then the status changes.

``` bash
$ echo 'My Project' > README
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
  (use "git add <file>..." to include in what will be committed)

      README

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

You can also run

```bash
$ git diff
``` 

which will show you the changes that where made.

Now track the file by adding it to the staging area via 

``` bash
$ git add README
```

If you want to commit only a part of the changes you made use 
```bash
git add -p
```
git will ask you for every "hunk"(part of the file) if you want to add it to the staging area.
The main options are:

* y stage this hunk for the next commit
* n do not stage this hunk for the next commit
* q quit; do not stage this hunk or any of the remaining hunks

## Committing
The changes are now ready to be committed

``` bash
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

      new file:   README
```

Now commit this change with a suitable commit message.
You forgot what you changed and `git diff` does not work?
If you already added the file to the staging area you can run 
```bash
$ git diff --staged
```

## Push to remote
Push this now to your repository with

```bash
$ git push
```

## Show last changes

```bash
$ git log
``` 
shows you a log of recent commit messages.

If you want to have a look at the changes source use
```bash
$ git log -p
```
A much prettier version is 
```bash
$ git log --pretty=format:"%h - %an, %ar : %s" --graph
```

# Get latest changes
An amazing thing of git is to work together with others. This guide will not go into the details
of this, yet you will often have to get the latest changes of a project.

You can do this easily by using
```bash
$ git pull
```
which is a short version of two different commands. It first executes `git fetch` that downloads
the latest changes. Then it runs `git merge FETCH_HEAD` which tries to apply the newest changes
to your local repository. This is also the difficulty of this as any file that was changed locally
and in the remote repository will cause a *merge conflict* as git does not know which file/parts
of the file to keep. The resolution of such a conflict can be complicated and goes beyond the
intentions of this guide.

A brief overview can be found
[here](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/resolving-a-merge-conflict-using-the-command-line).

## Gitignore
Sometimes you do not want git to track every file in your repository.
Typically this applies for log files, configuration files (where maybe passwords are stored)
and compiled sources. For this purpose you can create the file  `.gitignore` in your repository.
This file will be read by git. An example `.gitignore` looks like this:

```gitignore
# ignore all .log files
*.log

# ignore all files in any directory named config
build/

# but do track sample.log, even though you're ignoring .log files above
!sample.log

# only ignore the TODO file in the current directory, not subdir/TODO
/TODO

# ignore all files in any directory named build
build/
```
You can generate gitignore files [here](https://www.gitignore.io/).

# Undoing things

## Make changes to the last commit
You forgot to add one file to your commit?
You are unhappy with your commit message?
Use `git --amend`!
```bash
$ git commit -m 'Pretty commit message'
$ git add forgotten_file
$ git commit --amend
```
Do not do this if you already pushed to remote.

## Unmodifying a Modified File
You made changes to a file but the changes messed everything up?
You can always go back to the version of the last commit by 
```bash
git checkout -- filename

```
*Warning*: This is dangerous as you delete all changes that you made locally.
Do NOT use this command unless you are absolutely sure what you are doing.

## Time machine
Something went terribly wrong. When using git this is no problem.
Just use `reflog` and select the commit where still everything was alright.

```bash
$ git reflog
9bff138 HEAD@{0}: commit: Document limitations of this guide
8d9dac8 HEAD@{1}: commit (amend): Adjust script to nice print
[...]
2b66f53 HEAD@{7}: commit: Introduce git log
8835c33 HEAD@{8}: commit: Fix of formating of headings
2f0f500 HEAD@{9}: commit: Improve order of comments on workflow
249dc14 HEAD@{10}: commit (amend): Explain git diff
f5ba1d3 HEAD@{11}: commit: Explain git diff
0a2ce1c HEAD@{12}: commit: Remove trailing whitspaces
735511f HEAD@{13}: commit (initial): Initial commit

$ git reset HEAD@{index_where_everything_was_fine}
$ git reset --hard origin/master
```

*Warning*: This is dangerous as you delete all changes that you made locally.
Do NOT use this command unless you are absolutely sure what you are doing.

# USB sticks as remote
Sometimes (e.g. you are working on a machine that is not connected to the internet) it can be
helpful to use an USB drive as remote.

## How to prepare the drive

Go to the USB drive
```bash
$ cd /media/username/git-stick/
```
Create a directory for your repository
```bash
$ mkdir my-repo
```
Initialize the repo
```bash
$ cd my-repo
$ git init --bare
```

## How to push to a USB drive

To push to a USB drive you need to add a remote. Go to your local repository and use
```bash
$ git remote add usb /media/username/git-stick/my-repo/
```
Be aware that your stick will have a different name and will be at a different location, depending
on your operating system. You named the remote "usb" here, of course you can change that name.

Now push your repo
```bash
$ git push usb
```

To list all repositories just type
```bash
$ git remote
origin
usb
```

If you want to push to the USB drive by default you can use
```bash
$ git push -u usb master
Branch 'master' set up to track remote branch 'master' from 'usb'
```

# What this guide does not cover

* Branching
    - Creating branches
    - Merging branches (and merge conflicts)
    - Remote branches
    - Tagging
    - Forks
* Usage of Github
* Hooks

# Further reading

* Official git website [Git SCM](https://git-scm.com/): Extensiv documentation
* [Oh shit Git](https://ohshitgit.com/): Help when you messed up.




# Logo
Git Logo by Jason Long

{{< chat git  >}}
