Verified Commit fc299498 authored by Laurent Modolo's avatar Laurent Modolo
Browse files

tp.md: split tp into 4 files

parent b85ce21e
......@@ -11,9 +11,9 @@ make
The practical guide is decomposed in three sections.
- In the first part [ **Git Alone** ](./tp.md#part-1-git-alone), you will learn to use the basic Git command.
- In the second part [ **Git remote** ](./tp.md#part-2-git-remote), you will learn to interact with a Git remote repository
- In the last part [ **Git together** ](./tp.md#part-3-git-together), you will learn to work in collaboration with another person using Git.
- In the first part [ **Git Alone** ](./tp_1.md#part-1-git-alone), you will learn to use the basic Git command.
- In the second part [ **Git remote** ](./tp_2.md#part-2-git-remote), you will learn to interact with a Git remote repository
- In the last part [ **Git together** ](./tp_3.md#part-3-git-together), you will learn to work in collaboration with another person using Git.
## [Presentation support](./presentation.md)
......
This diff is collapsed.
# Part 1: Git alone
Git is a powerful tool to keep track of changes in your project and to manage your modifications history.
In this first part of the TP you will practice different git commands to keep track of your work and modifications with Git.
> A Git repository is an informatic project (folder) where changes are recorded using Git.
## Creation of a git repository
Start by creating a folder `alpha` in which you are going to write your project:
```sh
mkdir alpha
cd alpha
```
Once in the alpha folder, you can initialize a Git repository.
A Git repository is a project tracked and indexed by git.
```sh
git init
ls -la
```
> The `git init` command create a hidden `.git` folder at the root of your project.
**You should not temper with the content of the `.git` folder.**
Everything in the `.git` folder belongs to Git the rest of the `alpha` folder belongs to you.
When you issue `git` command the content of the `.git` folder is accessed or modified by git.
## Using git to track changes
There is nothing in our repository:
```sh
git status
git st
```
We defined `st` as an alias of `status` in the `~/.gitconfig` file, so the two commands are equivalent.
Our first code:
```sh
mkdir data
git st
echo 'a' > data/letter.txt
git st
```
**Git doesn’t track folders, only files**. For git folders are just structures to organise files.
With the creation of `letter.txt` git is aware of a change in the repository.
There are **untracked files**.
To start tracking files we use the command `git add` :
```sh
git add data/letter.txt
ls -R .git/objects/
git st
```
> `git add` greate **git blob**:
>
> - contains the compressed content of a file
> - The name of the blob is the [SHA1](https://en.wikipedia.org/wiki/SHA-1) of the file.
> - The first two characters of the [SHA1](https://en.wikipedia.org/wiki/SHA-1) are used as the name of a directory inside the objects folder
> - The rest of the hash is used as the name of the blob file
There are now changes to be committed, this means that git is now following the state of the `data/letter.txt` file.
The current state of `data/letter.txt` is recorded.
![git add made a copy of the file creating the corresponding blob](img/staging_1.png)
```sh
git ls-files --stage
echo "1234" > data/number.txt
git add data/number.txt
git ls-files --stage
printf "1" > data/number.txt
```
We changed the state of `data/number.txt`, but those changes are not staged to be committed.
The previous states of `data/number.txt` is still recorded *somewhere* even if it differs from its current state.
> This *somewhere* is called the **staging area** (where you stage changes).
```sh
git add data/number.txt
git ls-files --stage
```
![modifications in the working area don’t affect what’s stored in Git](img/staging_2.png)
![The staging area is different from the working directory](img/staging_3.png)
You can save the state of the staging area **definitively** with the command `git commit`
```sh
git commit -m "a1"
git st
```
Here "a1" is the message associated with the commit.
![Write clear and informative commit messages ([xkcd](https://xkcd.com/))](img/git_commit_xkcd.png)
> There are two rules for committing:
>
> - Commit often
> - Write clear and informative logs
> [http://git-scm.com/book/ch5-2.html](http://git-scm.com/book/ch5-2.html)
You cleared the changes to be committed and wrote them in a commit.
```sh
git log
git lo
```
You wrote your first commit with a unique identifier:
`531019e7119268c4dae5ac44ef5929165794f4b0`
> `git commit`:
> - creates a tree graph to represent the content of the version of the project being committed
> - creates a commit object
> - points the current branch to the new commit object
```sh
git ls-tree -r 531019e7119268c4dae5ac44ef5929165794f4b0
git ls-tree -d 531019e7119268c4dae5ac44ef5929165794f4b0
```
The `531019e7119268c4dae5ac44ef5929165794f4b0` points to the tree object which points to the two committed files.
![The commit a1 record the tree structure and the files corresponding to the staging area](img/commit_a1.png)
In git, there are 3 areas:
- The **working area** (everything in `alpha/` except the folder `.git`)
- The **staging area** (in the `.git` folder)
- The **repository** (also in the `.git` folder)
![git areas](img/three_git_areas.png)
The repository is a chain of commit, beginning with your first commit.
### Navigating a git repository
Let’s create a new commit with the changes made to `data/number.txt`:
```sh
echo "2" > data/number.txt
git add data/number.txt
git commit -m "a2"
git st
git lo
```
You have a second point in your commit history.
You can navigate to a given point of the repository with the command `git checkout`:
```sh
git log
cat data/number.txt
git checkout 531019e
cat data/number.txt
```
> You don't have to give the complete commit identifier for the command `git checkout`, only an unique subset of it.
The state, of the file `data/number.txt` is back to the one at the time of the first commit.
The `git checkout` or `git co` command rewrite your whole working area to match the state of the targeted commit.
```sh
git log
```
The `git log` command doesn’t display your second commit anymore.
Git commits only know of their direct ancestor(s).
The other change is in the first line of the `git log` command:
`(HEAD -> master)` became (HEAD).
This change means that you are in a **detached HEAD** state , the command `git st` also gives you this information.
```sh
git st
```
In git commit are chained one after another starting with the first commit.
Therefore, you can always go back to the commit history.
The repository is not only made of commits, but also of labels.
Labels point to a commit and can be the target of the `git co` command.
They are two types of labels:
- branches
- tags
If the first commit is the root of a growing tree of commits, branches are labels pointing to the leaves of the tree.
They change after each commit from pointing to the ancestor of the new commit, to pointing to the new commit.
The default branch in git is called `master`
Contrary to branches tags are anchored to a fixed commit.
**HEAD** is a special label that indicates your position in the tree of commits.
You can add a tag to your first commit with the command `git tag`
```sh
git tag -a v0.1 -m "my version 0.1"
git tag
git lo
```
You now have one tag in your repository.
The commit `c7a4cb9` is pointed by the tag `v0.1`.
```sh
git co master
git st
git lo
```
We are back at the leaf of the git repository.
## Growing the repository tree
We only have one branch, the `master` branch in our repository.
This means that we only have one timeline in our history.
In git, you can have as many branches as you want, to test out things, for example.
The following command creates the branch `dev` and move us (**HEAD**) to it.
```sh
git co -b dev
git st
git lo
```
```sh
echo ’3’ > data/number.txt
git add data/number.txt
git commit -m "a3"
git lo
```
If we have two branches `dev` and `master`, it’s hard to tell them apart (`master` is shorter).
```sh
git co master
echo 'b' > data/letter.txt
git add data/letter.txt
git commit -m "b2"
git lo
```
Congratulations, you have a fork in your git repository !
Let’s make another one called `dev2` from the branch `master` where `data/letter.txt` contain the letter `c`.
Then create the corresponding commit `c2`
## Merging branches
When you are ready to incorporate your new code in your main branch you need to merge the branch containing the new code into your main branch.
You can merge branches with the command `git merge`.
This command is going to try to merge the targeted branch into the branch you are on (**HEAD**).
The command `git branch` shows you the available branches and the one you are on.
```sh
git branch
git merge master
```
Can we merge `master` into `dev2` ?
```sh
git co master
git branch
git merge dev2
```
There are three types of merge :
- Fast-forward
- Merge of two different lineages
- Merge of two different lineages with conflict
Here the branch `dev2` is a direct descendant of `master`.
`dev2` contain all the information contained in `master`.
For `master` to gain all the information contained in `dev2`, we just have to move the label `master` to the commit pointed by `dev2`
```sh
git lo
```
There is a fork between the branch `master` and `dev`, we have to merge two different lineages.
```sh
git branch
git merge dev
```
Here the command create a **merge commit**, a merge commit is a commit that has two direct ancestors.
A new commit means a new commit message to write.
```sh
git lo
```
The new commit is a `Merge` commit with the identifiers of its two ancestors.
Here, we didn't have any conflict: in the `dev` branch, we worked on the `data/number.txt` file while in the `master` branch, we worked on the `data/letter.txt` file.
Let’s complicate things !
Create a new commit `e3` in the `master` branch where the content of `data/letter.txt` is set to `e`.
Then create a new commit in the `dev` branch where the content of `data/letter.txt` is set to `f` and go back the branch `master`.
```sh
git lt
git branch
git merge dev
git st
```
The automatic merge failed due to a conflict in `data/letter.txt`.
You are now in a merging state.
You must solve the conflict by editing `data/letter.txt`.
You can see three things in the `data/letter.txt`:
- The state of the file in your current branch (**HEAD**)
- The state of the file in the last common ancestor of the two branches
- The state of the file in the merged branch (*dev*)
Edit `data/letter.txt`, to set its content to `f`.
Then complete the merge:
```sh
git add data/letter.txt
git st
git commit
git st
git lt
```
You, now, know how to deal with the different kind of merge
[ ****Next: Git remote**** ](./tp_2.md#part-2-git-remote)
# Part 2: Git remote
We start by cloning an existing repository.
`file_handle.py` is a small python script to handle the dating and the access to dated files in a format compatible with the [guide of good practices at the LBMC](http://www.ens-lyon.fr/LBMC/intranet/fichiers/bioinfo/good-practices.pdf).
The `git clone <url>` command retrieves the whole history of a project and setup a working area based on the last point in this history.
```sh
cd ~/
git clone https://gitlab.biologie.ens-lyon.fr/LBMC/file_handle.git git_basis_tp1
cd git_basis_tp1
ls -l
```
We can check the log (history) of this repository with the command `git log`
this command has a huge number of formatting options.
```sh
git log --graph --all
git lt
```
Git history is not necessarily linear. The bifurcations or branches are a useful
tool to try and implement new things without tempering with the main (`master`)
branch of a project.
To check the different branches of this project:
```sh
git branch
```
By default the main branch and the first branch of a git repository is called `master`.
In the framework of this TP we want to start working from a specific point of the
`file_handle` project history. The sha1 of this commit is `727b007b`.
```sh
git checkout 727b007b
```
We are now in a `detached HEAD state`. This means that the working area was set
to match the commit `727b007b` which is not pointed by any references.
We are in part 1 or this TP so we want to setup a new branch to work on.
The command `git checkout -b <branch>` creates the branch `<branch>` and update
the working directory to match it.
```sh
git checkout -b tp1
ls -l
```
The content of the branch `tp1` is the same as the one of the commit `727b007b`.
## Modification to Git history
Gitlab is able to render the [markdown format](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) of files with the `.md` extension.
To enable this rendering for the `README` file, we need to rename it. To do this we have
two options:
- Deleting the file and creating a new one with the commands `git rm README` and `git add README.md`.
- Directly renaming the file with the command `git mv README README.md`.
```sh
git mv README README.md
```
Why did we choose `git mv` instead of the other option (besides entering less git commands)?
The commands like `git mv` and `git rm` add the modification directly to the staging
area.
```sh
git status # README.md is in the staging area
git commit -m "README: rename to README.md for md rendering"
git status # README.md is in the git repository
```
The first thing is to add a title to this `README.md` file.
```sh
echo "# file_handle" > README.md # we add the name of the project in the README
git status # README.md is in the working area
git add README.md
git status # README.md is in the staging area
git commit -m "README.md: add title"
git status # README.md is in the git repository
```
![git lifecycle](img/git_lifecycle.png)
We then add a small description.
```sh
echo "smalll python software to handle dated file names" >> README.md
git status
git diff README.md
git add README.md
git commit -m "README: smalll description of the software"
```
We made a mistake in the last commit: there is a typo in the commit message and
we also wanted to delete the file `todo.txt`. The command `git commit --amend`
allows us to edit the last commit.
```sh
git rm todo.txt
git status
git commit --amend
```
## Setting up your git repository
We made some changes to the local git repository. We want to make them available
on the gitlab server. The command `git push <repos>` send your latest
modifications to the remote repository defined as `<repos>`. The default remote
repository is called `origin`
```sh
git push
```
You don’t have permission to write to this repository (if you want to contribute to the file_handle project you can ask me later).
To cope with this problem you are going to create your own remote repository for this project on the gitlab server.
To do so, go to [http://gitlab.biologie.ens-lyon.fr/](http://gitlab.biologie.ens-lyon.fr/) and click on **new project**.
You can give a name to your project (we are going to use `git_basis` in the following commands). Click on **Create project**.
You end up on your project home page.
The main information is in the **ssh** box containing a link to your
repository :
`git@gitlab.biologie.ens-lyon.fr:<user_name>/git_basis.git`.
with the https protocol we have:
`https://lmodolo@gitlab.biologie.ens-lyon.fr/<user_name>/git_basis.git`
> Note: repositories created on gitlab are _bare_ repository. There is no working
> or stash area on gitlab because nobody works on it.
At the end of the page [http://gitlab.biologie.ens-lyon.fr/<user_name>/git_basis](http://gitlab.biologie.ens-lyon.fr/<user_name>/git_basis) you have the following instruction to populate your remote repository
from an existing repository.
We can check the current remote addresses of our local git repository:
```sh
git remote -v
```
**origin** is set to `https://gitlab.biologie.ens-lyon.fr/LBMC/file_handle.git` for `fetch` and `push`
operation.
We want to add our repository to the remote addresses of our local git repository.
We are going to use `gitlab_lbmc` instead of `git@gitlab.biologie.ens-lyon.fr`
to match the ssh configuration file and use our ssh key in the connections to
this server.
```sh
git remote add perso https://gitlab.biologie.ens-lyon.fr/<user_name>/git_basis.git
git remote -v
```
Then we use the following commands to push our local copy to our remote repository:
```sh
git push -u perso --all
git push -u perso --tags # tags need to be pushed separatly
```
## merging branches
We want to merge our work with the **master** branch. What will the following
command do?
```sh
git merge master
```
Nothing. **master** points to an ancestor commit of the **tp1** branch.
However, the reverse operation is possible:
```sh
git checkout master
git branch -v
git merge tp1
git push perso
```
You can see the graph of our modifications at the following address [http://gitlab.biologie.ens-lyon.fr/<user_name>/git_basis/network/master](http://gitlab.biologie.ens-lyon.fr/<user_name>/git_basis/network/master)
[ ****Next: Git together**** ](./tp_3.md#part-3-git-together)
# Part 3: Git together
Branch management is at the heart of Git.
These powerful mechanisms will help you to work in collaboration with others.
For the last part of the TP you need to pair with someone else. We will refer to you as developer **W** and the other person as developer **C**.
## Developer **W**:
For **C** to be able to push to you repository, you need to grant him access.
The gitlab access control is repository or branch-based.
Go to the project **Settings**, tab and then to **Member**.
You can search **C** and give him a role. Here we will use the role **Master** so **C** has as many rights as **W**.
Click on **Add to project** to validate the changes.
The idea behind a branch-based permission is to allow developers to work on a given branch of your repository while keeping others under your control.
## Developer **C**:
Clone **W**’s repository:
```sh
git clone https://gitlab.biologie.ens-lyon.fr/<W_name>/git_basis.git git_basis_tp2
git clone https://gitlab.biologie.ens-lyon.fr/<W_name>/git_basis.git git_basis_tp2
cd git_basis_tp2
git remote -v
git checkout -b tp2
```
The only remote that **C**’s local repository knows is **W**’s remote.
**C** adds a dependency section to `README.md`
````md
## Dependencies
The only dependencies for file_handle.py are `python3` and the `argspaste`
```sh
sudo install python3 pip3
pip3 install argparse
```
````
```sh
git add README.md
git commit -m "README.md: add dependencies description"
git status
```
Developer **C** is now ahead of `remote/master` by one commit.
```sh
git push
```
The command is not working.
Git writes a useful message giving you the right command for this first push.
## Developer **W**:
Before starting to work on the `file_handle`, developer **W** want to get the last version of the project.
```sh
git branch
git fetch perso
git status
git branch
```
**W** sees that a new `tp2` branch was created.
```sh
git checkout tp2
git branch
```
**W** wants to add a small help section to the `README.md`.
````md
## Usage
To know how to use the `file_handle.py` script, enter the following command:
```sh
file_handle.py --help
```
````
```sh
git add README.md
git commit -m "README.md: add Usage section"
git status
```
## Developer **C**:
While **W** is contributing to the redaction of the documentation, developer **C** continue to work on it:
```sh
git fetch
git status
```
````sh
## Usage