Foire aux questions - Git
Un ensemble de réponses à un ensemble de questions naturelles sur Git
- Visualiser l’état du dépôt
- Gérer un conflit
- Récupérer un état catastrophique
- Renommer les auteurs des commits
- Modifier des commits passés
- Se connecter à son dépôt
- Configurer son usage de git
- Ignorer la présence de fichiers
- Étiqueter les commits
- Pour aller plus loin …
Visualiser l’état du dépôt
La commande suivante permet de visualiser l’état du dépôt :
git status
Selon l’état dans lequel se trouve le dépôt, il est possible d’obtenir une somme d’informations comme :
On branch master •Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) •Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: README.txt •Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: authors.txt •Untracked files: (use "git add <file>..." to include in what will be committed) liste_des_courses.txt
Git est un logiciel assez prévenant, et il est donc possible de voir ici 4 items (mis en évidence par les ‘•’) :
-
Que le dépôt local n’a pas encore communiqué ses modifications au dépôt distant (“Your branch is ahead of ‘origin/master’ by 2 commits”)
-
Qu’un commit est en préparation, avec le fichier
README.txt
, et qu’il ne demande qu’à être communiqué avec la commandegit commit
. -
Qu’un fichier
authors.txt
a été modifié localement mais n’est pas inclus dans le commit précédent. -
Qu’un fichier
liste_des_courses.txt
est à l’intérieur du dépôt local, mais n’est pour l’instant pas géré par git.
Gérer un conflit
Du fait de la présence de multiples dépôts dans lesquels le code peut être modifié, il est possible que la même branche
master
ait divergé entre deux dépôts (typiquement avec la même branche sur un dépôt distant, commeorigin/master
). Dans ce cas, une fusion/merge risque d’amener à un conflit. Il convient de ne surtout pas paniquer, cela fait partie des tracas standards du développement logiciel.
Mettons que la dernière fusion/merge ait amené au résultat suivant :
Auto-merging authors.txt
CONFLICT (content): Merge conflict in authors.txt
Automatic merge failed; fix conflicts and then commit the result.
Un conflit peut aussi être visualisé à l’aide de la
commande git status
, qui devrait indiquer :
On branch master
Your branch and 'origin/master' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: authors.txt
no changes added to commit (use "git add" and/or "git commit -a")
Il faut bien noter que l’opération de fusion/merge ne s’est pas terminée (“no changes added to commit”). Git vous met dans un état où il est possible de l’assister à terminer cette fusion correctement.
Pour chaque fichier en conflit, appliquer la procédure suivante :
-
Ouvrir le fichier dans un éditeur (dans notre exemple
authors.txt
). -
Rechercher dans l’éditeur les blocs de la forme suivante :
<<<<<<< HEAD David, le programmeur extrémiste. ======= David, le programmeur de l'extrême. >>>>>>> origin/master
Git a modifié de lui-même le fichier pour inclure, aux endroits qui lui semblaient différents, les deux versions. Il est facile de rechercher ces blocs car les marqueurs
<<<<<<<
,=======
et>>>>>>>
ne sont quasiment jamais utilisés.-
La zone délimitée par
<<<<<<<
et=======
représente la version locale du code (branchemaster
). -
La zone délimitée par
=======
et>>>>>>>
représente la version distante du code (brancheorigin/master
).
-
-
Modifier le code de manière à éliminer tous les marqueurs.
Il est ainsi facile de choisir une version des deux versions à garder, ou de faire une sorte de mélange des deux si besoin.
-
A la fin des modifications, ajouter le code au commit (ici le fichier en conflit)
git add authors.txt
-
Une fois tous les fichiers en conflit gérés, terminer la fusion (un message de commit est généré automatiquement) :
git commit
Récupérer un état catastrophique
Il est toujours possible de se retrouver dans une situation dans
laquelle continuer à faire des commandes git
est
difficile ou met en péril l’état du code source sur lequel on
travaille. Il peut s’agir en particulier :
-
d’une situation où les commits sont rejetés par le serveur (penser avant tout à bien configurer
git
, et ensuite tenter d’appliquer la procédure décrite ici avant) -
d’une situation où du code est écrit dans le dépôt sans avoir été committé, mais toute action faite avec
git
risquerait de perdre ce code (c’est normalement difficile, mais avec beaucoup de malchance et/ou de mauvaise volonté, on ne sait jamais)
La procédure suivante consiste à reprendre la dernière version du
dépôt sur la forge, y copier ses modifications et les committer. Si
vous l’appliquez à la lettre, elle assure de ne perdre aucune
information pour ce qui est du code. Dans les exemples de commandes,
la procédure fait l’hypothèse que le dépôt
s’appelle chabadabada
.
Si vous en arrivez à cette appliquer cette procédure, c’est forcément après avoir vérifié qu’il n’existait pas une méthode moins grossière pour sauver votre travail de développement.
-
Se placer dans le répertoire parent du répertoire correspondant à votre dépôt, et le renommer.
mv chabadabada chabadabada.old
-
Recréer une version du dépôt local.
git clone https://<user>@thor.enseirb-matmeca.fr/git/chabadabada
-
Copier les données de l’ancien dépôt dans le dépôt nouvellement créé.
cp -R chabadabada.old/* chabadabada/
-
Communiquer les modifications dans le dépôt distant.
cd chabadabada/ git commit -m -a "Récupération catastrophique" git push origin
A la fin de la procédure, le dépôt chabadabada
contiendra la dernière version du code du dépot initial. Tous les
commits intermédiaires auront été perdus. Les fichiers supprimés du
dépôt entre temps devront être supprimés à nouveau. Si vous estimez
ne plus avoir besoin des vieux commits, vous pouvez après coup
supprimer le dépôt chabadabada.old
.
Renommer les auteurs des commits
Cette procédure permet de modifier les noms et emails d’utilisateurs de certains commits. Dans le cas où ces commits sont rejetés par la forge, elle permet de récupérer une situation mal engagée. Dans tous les cas, commencez par configurer votre dépôt et n’appliquez cette procédure qu’après avoir fait une copie dudit dépôt.
Commencez par compter combien et quels sont les commits fautifs :
-
Si il n’y en a qu’un seul, et que c’est le dernier, appliquer la commande suivante :
git commit --amend --reset-author
Cela remplacer l’auteur du commit par celui défini dans la configuration.
-
Si il y en a plus d’un, ou ce n’est pas le dernier, alors appliquer l’une des commandes suivantes depuis les machines de l’école :
~fmorandat/bin/rewrite-author.sh --rename "Ancien Nom" --reemail "ancien@email.com"
L’option
--rename
permet de réécrire un nom en utilisant celui spécifié dans la configuration, et--reemail
de réécrire un email. Faire bien attention à ne pas réécrire les commits corrects (qu’ils vous appartiennent ou pas), ainsi que les commits déjà poussés sur la forge.
Modifier des commits passés
Cette procédure permet de modifier entièrement un ensemble de commits n’ayant pas encore été poussés sur la forge. Dans le cas où ces commits sont rejetés par la forge. Dans tous les cas, commencez par configurer votre dépôt et n’appliquez cette procédure qu’après avoir fait une copie dudit dépôt.
Commencez par compter combien et quels sont les commits fautifs :
-
Si il n’y en a qu’un seul, et que c’est le dernier, préparez une modification du code comme si c’était un nouveau commit (par exemple en appliquant des
git rm
). Validez enfin le commit avec la commande suivante :git commit --amend
Cela élimine le dernier commit et le remplace par un nouveau commit dans le nouvel état.
-
Si il y a plusieurs commits, alors il va falloir les reprendre un par un. Noter la révision du dernier commit transmis à la forge, et appliquer la commande suivante :
git rebase --interactive <revision>
Cette commande permet de rejouer l’ensemble des commits depuis la révision donnée en paramètre. Il suffit alors d’éditer les commits fautifs, et de les amender au fur et à mesure. La procédure est décrite dans le Git Book.
Se connecter à son dépôt
Les utilisateurs de machines personnelles possèdent une configuration propre qui est parfois différente de celle des machines de l’école. En particulier, leur login peut différer. Pour éviter ce genre de problème, lorsqu’on clone un dépôt, on référence usuellement le login dans l’URL de connexion :
git clone https://<user>@thor.enseirb-matmeca.fr/git/chabadabada
Il est aussi possible de positionner cette information après coup, en
modifiant le fichier .git/config
à l’intérieur de son dépôt :
[remote "origin"]
url = https://<user>@thor.enseirb-matmeca.fr/git/chabadabada
fetch = +refs/heads/*:refs/remotes/origin/*
Noter que les informations pour se connecter sur un serveur sont propres au serveur. Ainsi, le mot de passe utilisé pour se connecter à la forge de l’école est le même que celui pour se connecter sur les machines de l’école (et pas son mot de passe personnel par exemple).
Configurer son usage de git
Il est possible de configurer un certain nombre de préférences pour
l’utilisation de tous ses dépôts git. Le fichier de configuration
est usuellement placé dans son répertoire personnel
comme $HOME/.gitconfig
. En cas de perte de son fichier,
ou pour revenir à une configuration initiale, il suffit
d’appliquer :
ssh <login_enseirb>@ssh.enseirb-matmeca.fr /net/ens/renault/local/bin/init-gitconfig.sh > ~/.gitconfig
Le fichier .gitconfig
est un fichier texte de la forme
suivante :
[http]
sslVerify = false
[color]
ui = auto
Il est parfaitement possible de modifier ce fichier dans un éditeur, mais il est aussi possible de le faire à l’aide de la commande suivante :
git config --global color.ui "auto"
Si la commande précédente ne comporte pas le
--global
, et qu’elle est effectuée depuis un dépôt git, alors la configuration ne concernera que ce dépôt.
Parmi les préférences que l’on peut définir dans ce fichier, il y en a deux qui sont particulièrement importantes :
-
user.name
, qui définit le nom de l’utilisateur à associer aux commits, -
et
user.email
, qui définit son adresse email.
Sans ces deux préférences, git fera des choix automatiques au moment de communiquer les révisions, et ces choix sont moins que judicieux. N’oubliez donc pas de positionner ces variables correctement.
Tout dépôt GIT utilisé sur la forge de l’ENSEIRB ne peut être utilisé qu’avec une configuration correcte, à savoir un nom d’utilisateur valide et un email propre à l’école. Toute utilisation du dépôt en dehors de ces conditions d’utilisation pourra être rejetée.
Les éléments qui sont testés actuellement sont le nom de la personne réalisant le commit et son adresse mail. Le script
init-gitconfig.sh
décrit ci-dessus génère un fichier de configuration acceptable.
Ignorer la présence de fichiers
Le fichier .gitignore
à la racine du dépôt permet de
lister les fichiers que Git va ignorer, à savoir ceux qui
n’apparaîtront pas dans la section Untracked files
lors
des appels à la commande git status
.
-
Ce fichier n’existe pas originellement dans le dépôt. Il faut donc le créer si le besoin d’ignorer des fichiers se fait sentir.
-
Il s’agit d’un fichier de script classique, les commentaires sont les lignes commençant par un
#
, et chaque ligne peut contenir un nom de fichier relatif à la racine ou une expression régulière. -
Il est versionné, comme les autres fichiers de code, ce qui permet de le faire évoluer au fur et à mesure du développement, et de communiquer ses modifications à des dépôts distants.
Un exemple de fichier .gitignore
pour des projets
en C
:
# .gitignore -- List of files ignored by git
*.[oa]
*~
Étiqueter les commits
Il est possible d’étiqueter (tag) des commits particuliers en leur donnant un nom plus lisible que les commits classiques. Ces étiquettes permettent ainsi de mettre en valeur des commits correspondant à des versions intéressantes (par exemple correspondant à la version finale du code). Il existe dans git deux types d’étiquettes :
-
les tags “légers” (lightweight ou unannotated), sont de simples étiquettes attachées à un commit, à savoir un nom particulier de référence;
-
les tags “annotés (annotated) permettent en plus de l’étiquette d’ajouter un message expliquant à quoi le commit correspond.
Typiquement, la commande suivante permet de créer un tag local nommé
version-1.0
:
git tag version-1.0
L’étiquette reste locale, tant que l’on ne l’a pas versée dans un dépôt distant. Pour cela, il suffit de faire :
git push origin version-1.0
Une fois un tag disponible dans un dépôt, il devient possible de récupérer la version correspondante simplement avec son nom :
git checkout version-1.0
Enfin, la commande suivante affiche la liste des tags existants :
git tag # Display the list of available tags
Pour des informations complémentaires, consulter la man page de git tag et la page de documentation du livre Pro Git.
Pour aller plus loin …
Il est bien évident que cette page passe sous silence un nombre de détails gigantesques quant à ce logiciel tentaculaire qu’est git, et c’est pourquoi il est possible de trouver d’autres sources de documentations plus génériques et/ou plus avancées en se référant à :
-
Le livre Pro Git accessible en ligne, et qui dispose d’une version en français, rassemble la documentation de référence du langage de manière très lisible.
-
Le site Git, the simple guide résume les commandes git de base de manière très synthétique, et a le bon goût de les rassembler dans une aide-mémoire allant à l’essentiel.
-
A visual Git reference explique la plupart des opérations effectuées par git de manière visuelle. Il permet de se faire une idée assez concrète du fonctionnement interne de git.
-
Learn Git Branching (déconseillé aux débutants), un site simulant les interactions avec un dépôt git dans un navigateur, et fournissant des exercices pour s’entraîner avec les concepts les plus complexes de l’outil.
-
Un ensemble de slides écrits par E. Fleury, extrêmement complets et didactiques pour comprendre le fonctionnement de git.
-
La foire aux questions du logiciel Git-Tower, qui, bien que faisant un peu de publicité à leurs produits, fournit des conseils clairs et détaillés.
-
L’aide-mémoire proposé sur github constitue une autre liste de commandes plus complète que la précédente, mais donc aussi plus fouillée.
-
Une discussion sur les différences entre merge et rebase donnant aussi des conseils sur la façon de bien gérer l’historique des commits.