Commit 21c50fd8 authored by Grégory Mounié's avatar Grégory Mounié
Browse files

model computer lab for git

parent 9c0824a5
\documentclass[a4paper,10pt]{article}
\usepackage[frenchb]{babel}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\DeclareUnicodeCharacter{00A0}{~}
\usepackage[left=2.5cm,right=2.5cm,top=2.5cm,bottom=2.5cm]{geometry}
\usepackage{microtype}
\usepackage{menukeys}
\usepackage{url}
\usepackage{hyperref}
\hypersetup{
colorlinks,
linkcolor={black},%{red!50!black},
citecolor={blue!50!black},
urlcolor={blue!80!black},
linktoc=all
}
\usepackage{tikz}
\usetikzlibrary{shapes}
\usetikzlibrary{calc,fadings,shapes.arrows,shadows,backgrounds, positioning}
% il exite mainteannt gitdags pour générer du tikz !
% \usepackage{gitdags}
\usepackage{fancyheadings}
\usepackage{minted}
\usepackage{todonotes}
\newcommand{\annee}{2020-2021}
\date{\annee}
\author{Sylvain Bouveret, Grégory Mounié}
\title{Git\\Fundamentals of the data model}
\sloppy
\usemintedstyle{tango}
\setminted{breaklines}
\setminted{linenos=true}
\definecolor{verylightgray}{rgb}{0.95,0.95,0.95}
\setminted{bgcolor=verylightgray}
\begin{document}
\maketitle
\thispagestyle{fancy}
\fancyhead[HL]{\includegraphics[height=2cm]{logo_UGA_couleur_cmjn.jpg}}
\fancyhead[HC]{\includegraphics[height=2cm]{ensimag.jpg}}
\fancyhead[HR]{\includegraphics[width=4.5cm]{GINP_BlocLogo.png}}
This document is available here~:\\
\begin{center}
\url{http://systemes.pages.ensimag.fr/www-git/git-model-computer-lab.pdf}
\end{center}
\section{Introduction}
\subsection{Git: plumbing}
At the first sight, Git is a complicated beast. It uses roughly 100
commands, some with tenths of options. But Git has a simple data
model. Indeed, it has a classical file hierarchy storing multiple
version of the content and the commands to manipulate these
files. Understanding the basics of the model greatly ease the
understanding of the majority of the commands and the efficient
management of the repositories.
The exercises will look at the commits, the branches, the tags and
most of the basic command effect.
\subsection{Team organization}
These exercises can be done alone. We advise to do it in team of
two. Each member of the team will do all the commands. Thus, each
member should explain to the other its understanding. Exchanging with
your teamate will force you to slow your pace and consider all the
details more carefully.
Let us look now at the content of the \texttt{.git} directory.
\section{First steps}
You will create first a small python program to uncompress ZLIB file,
then a minimalist repository.
\subsection{ZLIB cat in python}
The goal of the following program is to show you that git use plain
Zlib compression format. Thus the file contents are perfectly
readeable without git. Eg. Zlib is part of the standard library of
python or Java and an ubiquitous compression format
(cf. https://en.wikipedia.org/wiki/Zlib)
The code can be directly downlocaded from
\url{http://recherche.noiraudes.net/resources/git/TP/zlibcat.py3})
\inputminted{python}{../../FormaContinue_MeteoNov2017/TPs/zlibcat.py3}
Do not forget to set its execution right after the edition.
\begin{minted}{console}
$ emacs zlibcat.py3 # or your favorite editor
$ chmod u+x zlibcat.py3
\end{minted}
\subsection{Minimalist repository}
Create a minimalist repository \mintinline{console}{MiniRepo} with a
single file and a first commit.
\begin{minted}{console}
$ mkdir MiniRepo
$ cd MiniRepo
$ git init .
$ emacs file.txt # add few lines
$ git add file.txt
$ git commit -m "message 1"
\end{minted}
\section{Exploring the .git directory}
\label{sec=gitrepo}
Check the files into the repository:
\begin{minted}{console}
$ ls -F .git
\end{minted}
You should find a file \texttt{HEAD}. Read its content.
The current state of the working
La tête (HEAD) du dépot est indiqué dans le répertoire indiqué dans le
fichier \texttt{HEAD}. En suivant le contenu du fichier \texttt{HEAD}
dans le répertoire \texttt{refs/}, trouver le fichier contenant le
résumé SHA-1 de la tête et noter sa valeur.
Vérifier que c'est bien le même que le commit que vous venez de faire.
\begin{lstlisting}
git log
\end{lstlisting}
\section{Stockage: le répertoire objects}
\subsection{À la main}
Dans le répertoire \texttt{objects} se trouve un répertoire commençant
par les deux premières lettres du SHA-1.
Dans ce répertoire, se trouve un fichier dont le nom est la suite du SHA-1.
Afficher le contenu du fichier en utilisant \texttt{zlibcat.py3} avec
une commande du genre:
\begin{lstlisting}
./zlibcat.py3 < .git/objects/2d/447e8255ace8f0d36527aa62ab7669f121f540
\end{lstlisting}
Cela vous donnera l'identifiant SHA-1 du \texttt{tree}. Lisez son
contenu avec zlibcat.py3.
En fait, le format du \texttt{tree} est un peu plus compliqué que cela à
lire, mais il ne reste qu'un fichier dans \texttt{objects/} que vous
n'avez pas lu. Lisez son contenu et vérifier que c'est bien celui que
vous avez tapez.
\subsection{en utilisant Git}
Il est possible de faire les mêmes opérations en demandant à Git de
faire le décodage proprement:
\begin{lstlisting}
git cat-file -p LE_SHA-1_A_LIRE_DANS_OBJECTS
\end{lstlisting}
Refaites le chemin complet vers \texttt{file.txt} en partant de
HEAD mais cette fois en utilisant Git.
\subsection{Les trees}
Nous allons ajouter un fichier dans un sous-répertoire et
l'enregistrer dans un nouveau commit.
\begin{lstlisting}[language=sh]
mkdir sousRepertoire
mon_editeur_prefere sousRepertoire/file.txt # inserer quelques lignes
git add sousRepertoire/file.txt
git commit -m "message 2"
\end{lstlisting}
Utiliser \lstinline{git cat-file -p} pour lire le \texttt{tree}. Il
pointe sur un autre tree (le sous-répertoire), qui pointe sur le
nouveau fichier. Vérifier que le contenu du nouveau fichier est bien
le bon.
\subsection{Les fichiers dupliqués}
Dupliquer un fichier et l'insérer dans le dépôt.
\begin{lstlisting}[language=sh]
cp file.txt file_copy.txt
git add file_copy.txt
git commit -m "message 3"
\end{lstlisting}
Vérifier que le blob est le même pour les deux fichiers.
\section{Stockage par delta}
Modifier légèrement \texttt{file.txt} et enregister un commit.
Vérifier qu'il y a bien un nouveau blob. Il y a donc deux blobs
stockant quasiment les mêmes données.
Demander à git d'optimiser le stockage avec
\begin{lstlisting}
git gc
\end{lstlisting}
Un fichier \texttt{.pack} (et \texttt{.idx}) est apparu. Il contient
le stockage des fichiers avec des delta. La commande suivante permet d'afficher le contenu résumé du pack:
\begin{lstlisting}
git verify-pack -v .git/objects/pack/pack-0618531a948d3537443496da7765fb4d0b4fb74f
\end{lstlisting}
Ce qui est conservé dans un pack, c'est la dernière version du fichier
avec un chaine de delta qui permet de revenir en arrière dans
l'histoire du fichier.
\section{Les tags~: répertoire refs}\label{sec:tags}
Les tags servent à étiqueter des révisions afin de pouvoir y revenir
directement en toute circonstance. Ils fonctionnent de la même manière
que les branches (voir plus loin) mais ne bougent pas avec la tête.
Créez un tag sur la révision suivante~:
\begin{lstlisting}[language=sh]
git tag v0.1
\end{lstlisting}
Vérifiez que le fichier correspondant à ce tag a bien été créé dans le
dossier \texttt{.git/refs/tags} et que son contenu correspond bien au
commit sur lequel est positionnée la tête actuellement~:
\begin{lstlisting}
cat .git/refs/tags/v0.1
\end{lstlisting}
Nous allons avancer la branche \texttt{master}~:
\begin{lstlisting}[language=sh]
mon_editeur_prefere file2.txt # inserer quelques lignes
git add file2.txt
git commit -m "message 4"
\end{lstlisting}
Vérifiez dans le journal que la branche \texttt{master} a bien avancé
et que le tag que vous avez créé précédemment est bien resté en place.
\section{Les branches}
Nous allons créer une nouvelle branche nommée \texttt{develop}, puis
revenir dans la branche \texttt{master}.
\begin{lstlisting}[language=sh]
git checkout -b develop
cp file.txt file_copy2.txt
git add file_copy2.txt
git commit -m "message dev1"
\end{lstlisting}
Vérifier que HEAD pointe bien sur le bon commit de \texttt{develop}.
\begin{lstlisting}[language=sh]
git checkout master
cp file.txt file_copy2.txt
git add file_copy2.txt
git commit -m "message 5"
\end{lstlisting}
Vérifier que HEAD pointe bien sur le bon commit de \texttt{master}.
Et nous allons faire le merge (sauvegarder sans modifier le message)
\begin{lstlisting}
git merge develop
\end{lstlisting}
Vérifier que le commit a bien deux parents et que le tree pointe vers
le même fichier.
\section{Git perd la tête~?}
Dans cette section, nous allons comprendre comment un dépôt peut se
retrouver dans une situation de «~tête détachée~» et pourquoi il
convient de prendre ses précautions dans ce cas-là.
\subsection{Reprendre le travail depuis un commit antérieur}
Récupérez l'identifiant du commit correspondant à la branche
\texttt{develop}. On peut par exemple utiliser~:
\begin{lstlisting}
git show develop
\end{lstlisting}
Notez l'identifiant du commit, et récupérez (\texttt{checkout}) les
données de ce commit~:
\begin{lstlisting}
git checkout <numéro-du-commit>
\end{lstlisting}
Normalement, Git doit vous avertir que vous passez en état «~tête
détachée~», mais c'est simplement un avertissement.
Créez un nouveau fichier et faites un commit~:
\begin{lstlisting}[language=sh]
mon_editeur_prefere fichier3.txt # inserer quelques lignes
git add fichier3.txt
git commit -m "message détaché 1"
\end{lstlisting}
Vérifiez que votre commit est bien dans le journal des révisions~:
\begin{lstlisting}[language=sh]
git log --graph --oneline
\end{lstlisting}
Notez mentalement le numéro de commit. Revenez à la branche master et
regardez le journal des révisions~:
\begin{lstlisting}[language=sh]
git checkout master
git log --graph --oneline
\end{lstlisting}
Mais où est donc passé le commit dans lequel vous aviez ajouté le
fichier \texttt{fichier3.txt}~? Il n'est référencé par aucune branche,
donc inaccessible, sauf si l'on connaît précisément son identifiant
(ou alors si l'on fait une recherche exhaustive dans les fichiers du
dépôt).
Dans un dépôt Git, les seuls fichiers visibles facilement sont les
fichiers qui sont des ancêtres d'un point d'entrée de l'arbre des
révisions, ces points d'entrée étant~:
\begin{itemize}
\item des branches~;
\item des tags~;
\item le pointeur \texttt{HEAD} (la tête).
\end{itemize}
Nous allons rendre notre commit visible en la fusionnant dans
la branche \texttt{develop}~:
\begin{lstlisting}
git checkout develop
git merge <numéro-du-commit> # le numéro est celui du commit
# dans lequel on a créé fichier3.txt
\end{lstlisting}
Une autre solution possible était de créer une nouvelle branche
directement à partir de ce numéro de commit, avec%
\lstinline{git branch <nouvelle-branche> <numéro-du-commit>}.
\subsection{Reprendre le travail depuis une branche antérieure}
Revenez sur la branche master~:
\begin{lstlisting}
git checkout master
\end{lstlisting}
Nous allons maintenant effectuer les mêmes opérations mais en
repartant de la branche \texttt{develop}, et non de son commit
associé.
\begin{lstlisting}[language=sh]
git checkout develop
mon_editeur_prefere fichier3.txt # inserer quelques lignes
git add fichier3.txt
git commit -m "message dev2"
git checkout master
\end{lstlisting}
Revenez sur la branche \texttt{develop} et vérifiez que rien n'est
perdu~:
\begin{lstlisting}[language=sh]
git checkout develop
git log --graph --oneline
\end{lstlisting}
C'est normal. Lorsque l'on travaille à partir d'une branche, le
pointeur de la branche avance avec la tête. Lorsque l'on change de
branche, nos commits ne sont pas perdus.
\subsection{Et les tags, dans tout ça~?}
Revenez au tag \texttt{v0.1} créé dans la section~\ref{sec:tags}. À
votre avis, êtes-vous en situation de tête détachée (comme si vous
aviez récupéré un numéro de commit), ou pas~? Pourquoi~?
\section{Pour conclure\dots{}}
À l'issue de ce TP, vous devriez avoir une compréhension détaillée des
structures de données sous-jacentes au stockage de l'historique d'un
dépôt. C'est un graphe orienté, avec un certain nombre de points
d'entrées. La plupart des commandes de Git servent soit à créer de
nouveaux nœuds dans le graphe, soit à créer de nouveaux points
d'entrée, soit à naviguer. Si vous avez compris cela, vous avez tout
compris.
\end{document}
%%% Local Variables:
%%% mode: latex
%%% TeX-master: t
%%% ispell-local-dictionary: "francais"
%%% End:
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment