\input{../_preamble} \input{../_preamble_bbl} % \usepackage{biblatex} % \addbibresource{../bibliography} \usepackage{menukeys} \title{Git} \usepackage{float} \usepackage{dingbat} \usepackage[newfloat]{minted} \SetupFloatingEnvironment{listing}{listname=Listings} \setminted{ bgcolor=Lavender, breaklines, breaksymbolright=\small\carriagereturn} \setmintedinline{bgcolor=Lavender} \usepackage{capt-of} \usepackage{soul} \makeindex[name=cmds, intoc, title={Liste des commandes et instructions}, options={-s \jobname.ist}] \NewDocumentCommand{\commande}{s m O{}}{ \IfBooleanTF{#1}{\index[cmds]{#2@\texttt{#2}|#3textbf}} {\index[cmds]{#2@\texttt{#2}#3}} } \NewDocumentCommand{\inputfile}{O{} m m O{application/x-sh}}{ \marginpar{\attachandlink{scripts/#3}[#4]{Fichier attaché}{\textcolor{blue}{Ouvrir le fichier}}} \inputminted[#1]{#2}{scripts/#3} } \usepackage{pdflscape} \usepackage{adjustbox} \begin{document} \maketitle \renewcommand{\contentsname}{Sommaire} \tableofcontents \listoffigures % \listoflistings % \needspace{3\baselineskip} % \listoftables \chapter{Introduction} \label{cha:introduction} \paragraph{Avertissement} Dans les pages qui suivent, on cherche à donner au lecteur quelques éléments sur la notion de \emph{système de contrôle de version} en général et sur \emph{Git} en particulier. L'ouvrage de référence, par \citeauthor{Chacon.Straub2018}, \citetitle{Chacon.Straub2018}, traduit en français, est disponible en ligne\autocite{Chacon.Straub2018}. \section{Les systèmes de contrôle de version} \label{sec:vers-contr-syst} Les \enquote{systèmes de contrôle de version}, en anglais \emph{version control systems} (VCS), sont des logiciels qui permettent de suivre toutes les modifications des fichiers et des répertoires qui se trouvent dans un répertoire donné. À partir du moment où l'on décide de suivre le contenu d'un répertoire, on peut retrouver l'état qui était le sien dans le passé à tout moment. Supposons que l'on ait quelque part modifié un paragraphe dans un texte, ajouté ou retranché des lignes: le système de contrôle de version permet alors de retrouver la chronologie de toutes les modifications et de les afficher clairement, l'une après l'autre. On a ainsi l'assurance de ne jamais rien perdre de son travail. Le contrôle de version permet également de travailler en même temps sur différentes \emph{branches}. On distingue ainsi la \emph{branche principale} de toutes les \emph{branches secondaires} que l'on peut ouvrir à tout moment. Prenons un exemple: à un moment donné, on souhaite revenir sur une page complexe que l'on a rédigée et y apporter des modifications. Mais pour autant, on n'approuve pas encore ces modifications et on voudrait ne rien perdre de la version originale. On ouvre alors une \emph{branche secondaire} dans laquelle on modifie à souhait la page. Durant tout le travail sur la branche secondaire, le travail enregistré dans la branche principale n'est pas altéré. Une fois terminé le travail sur la branche secondaire, on peut l'abandonner ou bien, si le résultat est satisfaisant, le conserver. Dans ce cas, on demande au système de contrôle de version de \emph{fusionner} dans la branche principale la branche secondaire sur laquelle on a travaillé. Puis on continue le travail dans la branche principale, après avoir effacé la branche secondaire, tout en sachant qu'à tout moment, toutes les étapes de ces modifications peuvent être retrouvées. Bien entendu, le système permet d'ouvrir simultanément autant de branches qu'on le souhaite. \subsection{Différents concepts, différentes approches} \label{sec:diff-conc-diff} On distingue trois types de systèmes de contrôle de version: \begin{enumerate} \item \textbf{Les systèmes locaux} qui enregistrent les modifications dans une base de données. Quand un fichier est modifié, ces systèmes enregistrent non pas les deux versions du fichier modifié, mais un seul fichier, en plus du fichier initial, dans lequel sont simplement notées les \emph{différences} de l'un à l'autre. \item \textbf{Les systèmes centralisés} qui font la même chose que les systèmes locaux, mais dans lesquels la base de données se trouve sur un serveur. L'avantage est que l'on peut alors organiser un travail de groupe. Mais l'inconvénient est que si le serveur est en panne, alors la base de données est inaccessible et personne ne peut travailler. \item \textbf{Les systèmes distribués} dans lesquels les différents utilisateurs travaillent non pas sur des fichiers reconstitués à l'aide de la somme des modifications enregistrées sur un serveur, mais sur une version autonome et dupliquée de tous les fichiers qui sont sur le serveur. Chacun travaille sur ses fichiers, même hors réseau. Puis une fois le travail terminé, on envoie sur le serveur un nouvel état de la base de données que les autres peuvent synchroniser à tout moment. \end{enumerate} Git est un système de contrôle de version \emph{distribué}. Par rapport à d'autres systèmes de la même catégorie, il offre un avantage considérable: celui de travailler non pas sur les \emph{différences} entre les modifications des fichiers, mais sur des \emph{instantanés} complets. Prenons un exemple. Soit le fichier suivant (\verb|recherche.txt|):\label{ref:recherche} \begin{minted}[linenos]{text} PREMIÈRE PARTIE =============== COMBRAY ------- I Longtemps, je me suis couché très tôt. Parfois, à peine ma bougie éteinte, mes yeux se fermaient si vite que j'avais juste le temps de me dire: «Je m'endors.» \end{minted} Puis l'auteur se ravise et écrit: \begin{minted}[linenos]{text} PREMIÈRE PARTIE =============== COMBRAY ------- I Longtemps, je me suis couché de bonne heure. Parfois, à peine ma bougie éteinte, mes yeux se fermaient si vite que je n'avais pas le temps de me dire: «Je m'endors.» \end{minted} Si l'on demande maintenant à un système informatique d'analyser les différences entre les deux états de \verb|recherche.txt|, il pourra produire un résultat comparable à celui-ci: \label{ref:diff} \begin{minted}[linenos,escapeinside=||]{text} --- recherche.txt 2018-10-03 12:35:05.848903296 +0200 +++ recherche.txt 2018-10-03 12:31:04.292356175 +0200 |\textcolor{Blue}{@@ -6,6 +6,6 @@}| I |\textcolor{Red}{-Longtemps, je me suis couché très tôt. Parfois, à peine ma}| |\textcolor{Red}{-bougie éteinte, mes yeux se fermaient si vite que j'avais juste le}| |\textcolor{Green}{+Longtemps, je me suis couché de bonne heure. Parfois, à peine ma}| |\textcolor{Green}{+bougie éteinte, mes yeux se fermaient si vite que je n'avais pas le}| temps de me dire: «Je m'endors.» \end{minted} \paragraph{Commentaire} La ligne~3 du rapport ci-dessus permet de comprendre que les modifications n'interviennent pas avant la ligne~6 du fichier original \verb|recherche.txt|. Ensuite, nous trouvons les modifications, entourées de \emph{deux lignes non modifiées qui donnent le contexte}: ce sont les lignes~5 et 10 du rapport, qui renvoient respectivement aux lignes~7 et 11 du fichier original. Enfin, nous trouvons les modifications: dans le rapport, les lignes~6 et 7, rendues en rouge et précédées du signe $-$, ont été remplacées dans la deuxième version par les lignes~8 et 9, rendues en vert, et précédées du signe $+$. Les systèmes de contrôle de version peuvent donc procéder de deux manières différentes: \begin{enumerate} \item Enregistrer le fichier original seulement, puis tous les rapports successifs qui donnent les modifications. Ainsi, pour donner l'état le plus récent d'un fichier, il suffit de prendre l'original puis de lui appliquer toutes les modifications successives. \item Enregistrer toutes les versions successives des fichiers sous la forme d'\emph{instantanés}. Dans ce cas, les rapports qui enregistrent les modifications ne sont pas eux-mêmes enregistrés, mais peuvent toujours être produits à partir de deux instantanés enregistrés. \textbf{C'est ainsi que procède Git}. \end{enumerate} Bien entendu, quand on travaille sur de nombreux fichiers simultanément et que, d'une étape à l'autre de son travail, on n'en modifie que quelques-uns, Git ne prend pas d'instantané des fichiers non modifiés. Au lieu de faire cela, il enregistre simplement un \emph{pointeur} vers le dernier instantané du fichier, c'est-à-dire vers la dernière version modifiée de ce fichier. Cette méthode présente de nombreux avantages dont le plus évident tient à la sécurité. En effet, les systèmes qui enregistrent seulement les rapports de modifications ne sont plus en mesure de restituer un fichier donné si l'un de ces rapports est corrompu. Si un chaînon est manquant, c'est toute la chaîne qui est brisée. Git n'est pas vulnérable sur ce point. \section{Prise en main de Git} \label{sec:prise-en-main} \href{https://notabug.org/ralessi/courses/wiki#installation-de-git}{Une fois Git installé}, il faut l'initialiser en lui indiquant votre nom et votre email. Pour cela, il suffit d'entrer successivement les deux lignes suivantes, en veillant à substituer à la fin de chaque ligne les informations de l'exemple par celles de votre identité. On veillera également à placer le prénom et le nom, séparé par un espace, entre guillemets doubles: \begin{minted}[linenos]{text} git config --global user.name "John Doe" git config --global user.email johndoe@example.com \end{minted} Ensuite, \href{./01-ligne-de-commande.pdf}{muni du cours sur la ligne de commande}, il est possible de créer un répertoire de travail. Nous allons créer ce répertoire à l'intérieur de notre répertoire \verb|Documents|, puis nous rendre à l'intérieur de ce répertoire à l'aide de la commande \verb|cd|: \begin{minted}{text} [robert@kiddo ~]$ cd Documents [robert@kiddo Documents]$ mkdir travail [robert@kiddo Documents]$ cd travail [robert@kiddo travail]$ \end{minted} L'étape suivante consiste à demander à Git de suivre le contenu de ce répertoire: \begin{minted}{text} [robert@kiddo travail]$ git init Dépôt Git vide initialisé dans /home/robert/Documents/travail/.git/ \end{minted} La réponse donnée par Git nous indique où sera maintenue sa base de données: dans un \href{./01-ligne-de-commande.pdf#lnk_hidden}{répertoire caché} \verb|.git| à l'intérieur du répertoire \verb|travail|. Commençons donc le travail. À l'aide d'un éditeur de texte, saisissons le fichier \mintinline{text}|recherche.txt| donné \vpageref{ref:recherche} et enregistrons-le dans sa première version. La commande suivante \verb|git status| demande à Git de nous \emph{fournir un état} du répertoire: \begin{minted}[linenos,escapeinside=||]{text} [robert@kiddo travail]$ git status Sur la branche master Validation initiale Fichiers non suivis: (utilisez "git add ..." pour inclure dans ce qui sera validé) |\textcolor{Red}{recherche.txt}| aucune modification ajoutée à la validation mais des fichiers non suivis sont présents (utilisez "git add" pour les suivre) \end{minted} \paragraph{Commentaire} Comme on le voit, Git est toujours très explicite. Voici ce qu'il faut retenir ici de ce rapport: \begin{enumerate} \item Ligne~2: par défaut, la \emph{branche principale} est appelée par Git \verb|master|. \item Ligne~6 et suivantes: Git donne une simple liste de fichiers trouvés dans le répertoire et indique qu'on ne lui a pas (encore) demandé de les \emph{suivre}. C'est un point important qu'il faut bien comprendre: \emph{Git ne suivra que les fichiers qu'on lui a demandé d'indexer}. \item Ligne~7: Git nous donne la commande à utiliser pour indexer le fichier qui a été trouvé: \mintinline{bash}|git add | \end{enumerate} Exécutons cette commande, puis demandons à Git un nouveau rapport: \begin{minted}[linenos,escapeinside=||]{text} [robert@kiddo travail]$ git add recherche.txt [robert@kiddo travail]$ git status Sur la branche master Validation initiale Modifications qui seront validées : (utilisez "git rm --cached ..." pour désindexer) |\textcolor{Green}{nouveau fichier : recherche.txt}| \end{minted} La commande \mintinline{bash}|git add recherche.txt| a eu pour effet de placer \verb|recherche.txt| \emph{dans la zone d'index de Git} que l'on appelle \emph{zone de travail} ou \emph{staging area}. La dernière opération consiste à enregistrer le fichier dans la base de données de Git: cela se fait à l'aide de la commande \mintinline{bash}|git commit|. La syntaxe de cette commande est la suivante: \begin{minted}{bash} git commit -m "" \end{minted} où \verb|| est le nom du ou des fichiers à enregistrer, et \verb|| une petite ligne susceptible de servir d'aide-mémoire: \begin{minted}{text} [robert@kiddo travail]$ git commit recherche.txt -m "version initiale" [master (commit racine) fa1ec00] version initiale 1 file changed, 11 insertions(+) create mode 100644 recherche.txt \end{minted} \paragraph{Poursuite du travail} Git enregistre tous les \emph{commits} dans un fichier journal, en anglais \emph{log file} ou plus simplement \emph{log}. Dans les exemples qui suivent, nous avons inséré dans le fichier \verb|recherche.txt| donné \vpageref{ref:recherche} les modifications correspondant à la deuxième version du fichier. Comme ce fichier est indexé, la commande \verb|git diff| nous montre immédiatement quelles sont les différences (v. plus haut \vpageref{ref:diff}): \begin{minted}[linenos,escapeinside=||]{text} [robert@kiddo travail]$ git diff diff --git a/recherche.txt b/recherche.txt index 3baf502..f230132 100644 --- a/recherche.txt +++ b/recherche.txt |\textcolor{Blue}{@@ -6,6 +6,6 @@}| COMBRAY I |\textcolor{Red}{-Longtemps, je me suis couché très tôt. Parfois, à peine ma}| |\textcolor{Red}{-bougie éteinte, mes yeux se fermaient si vite que j'avais juste le}| |\textcolor{Green}{+Longtemps, je me suis couché de bonne heure. Parfois, à peine ma}| |\textcolor{Green}{+bougie éteinte, mes yeux se fermaient si vite que je n'avais pas le}| temps de me dire: «Je m'endors.» \end{minted} Pour terminer, enregistrons ces modifications: \begin{minted}{text} [robert@kiddo travail]$ git commit recherche.txt -m "nouvelle version de l'incipit" [master 83b6c3e] nouvelle version de l'incipit 1 file changed, 2 insertions(+), 2 deletions(-) \end{minted} Et demandons à Git de nous fournir un extrait de son journal: \begin{minted}[linenos,escapeinside=||]{text} [robert@kiddo travail]$ git log |\textcolor{Brown}{commit 83b6c3e6dad72116eac5ce7d1ba70968e4e57ebb}| Author: Robert Alessi Date: Wed Oct 3 15:05:32 2018 +0200 nouvelle version de l'incipit |\textcolor{Brown}{commit fa1ec001efdca9c69cc768dc9cf83706bdb6e603}| Author: Robert Alessi Date: Wed Oct 3 14:49:10 2018 +0200 version initiale \end{minted} Nous voyons aux lignes~2 et 8 qu'à chaque \emph{commit} est associé un \emph{numéro de registre}, en notation hexadécimale, formé d'une séquence de~40 caractères allant de \verb|0| à \verb|9| et de \verb|a| à \verb|f|. \subsection{Résumé des commandes} \label{sec:resume-des-commandes} \begin{enumerate} \item \verb|git config --global| $\rightarrow$ paramétrage initial de Git. \item \verb|git init| $\rightarrow$ initialisation de Git dans un nouveau répertoire. \item \verb|git status| $\rightarrow$ demande à Git un \emph{rapport d'état}. \item \verb|git add| $\rightarrow$ indexe des fichiers dans la zone de travail. Les fichiers indexés sont ceux qui seront suivis par Git. \item \verb|git commit -m ""| $\rightarrow$ enregistre dans la base de données de Git les versions modifiées des fichiers sous forme d'instantanés. \item \verb|git diff| $\rightarrow$ montre les différences entre la version actuelle des fichiers et leur dernière version enregistrée par % \verb|git commit|. \item \verb|git log| $\rightarrow$ affiche le journal de Git. \end{enumerate} \section{Git en mode graphique} \label{sec:git-gui} \hfill\verb|../.. à suivre| \begin{landscape} \begin{figure} \centering \adjustimage{frame,width=\linewidth}{images/02-gitk.png} \caption{gitk} \label{fig:gitk} \end{figure} \end{landscape} \end{document}