This is an old revision of the document!
Table of Contents
Git
Un bon tutoriel pour jouer de manière interactive : https://learngitbranching.js.org/
Commençons par créer un dépôt Git “remote” vide, qui se trouve en principe sur un serveur distant. Dans cet exemple, il se trouvera dans le répertoire /tmp/remote de la machine locale.
mkdir /tmp/remote cd /tmp/remote git init --bare --shared
Nous pouvons maintenant “clôner” notre dépôt Git en local dans un répertoire “local”.
git clone /tmp/remote /tmp/local cd /tmp/local
A partir de maintenant nous pouvons commencer à travailler dans le dépôt local.
Tout d'abord, modifions un peu la configuration globale de Git sur la machine :
# mail / user name git config --global user.name "orel" git config --global user.mail aurelien.esnard@u-bordeaux.fr # editeur de texte git config --global core.editor emacs # coloration syntaxique git config --global color.diff auto git config --global color.status auto git config --global color.branch auto
Pour afficher votre configuration :
git config --global -l
Commandes de base
Ensuite, on va pouvoir commencer à jouer le depôt local (/tmp/local). Tout d'abord, on crée un fichier “date.txt”. Initialement, ce fichier a comme le statut untracked, c'est-à-dire non suivi.
date > date.txt git status
Pour suivre ce fichier dans le dépôt Git, il va falloir tout d'abord l'ajouter à l'index (git add). Puis dans un second temps, on va pouvoir effectuer le commit, ce qui consiste à conserver dans le dépôt local une version de ce fichier. On prendra garde de mettre des commentaires compréhensibles lors des commits.
git add date.txt git commit -m "premier commit" git status
A tout moment, la commande git status permet de vérifier le statut des différents fichiers afin d'éviter les bétises : à utiliser sans modération ! Personnellement, j'aime bien la version courte : git status -s.
Dans un second temps, on modifie le fichier… On va souhaiter committer cette nouvelle version dans le dépôt local. Attention, il ne faut pas oublier de signaler la modification d'un fichier en faisant un git add avant d'effectuer le commit !
date > date.txt git status # le fichier est indiqué comme "modifié" git add date.txt git commit -m "second commit"
Synchronisation avec le dépôt distant
Les commits sont uniquement locaux et n'ont aucun effet sur le dépôt distant (remote). D'ailleurs, il n'est pas nécessaire d'être connecté à Internet pour effectuer ces commits ! Pour synchroniser le dépôt local avec le dépôt distant (remote), il faut faire un push. Ainsi tous les commits vont être “poussés” sur ce serveur pour y être archivés.
git push
A l'inverse, pour mettre à jour son dépôt local, quand le dépôt remote a été modifié (par quelqu'un d'autre), il faut faire un pull.
git pull
Log & Diff
La commande log permet de suivre l'historique des “commits”. On notera que chaque commit produit une nouvelle version de l'ensemble du dépôt, identifié par un ID de la forme “83109ce0d335a…4e8bd58f”.
git log
En un peu plus complet :
git log --summary
En un peu plus joli :
git log --graph --oneline --all
Par ailleurs, la commande diff permet de voir quelles modifications ont été effectuées pour tous les fichiers ou pour un fichier particulier :
git diff [file]
Il existe plusieurs variantes de diff :
git diff <commit> <commit> [file] # comparaison explicite entre deux commits git diff <commit> [file] # comparaison du workspace avec un commit git diff [file] # comparaison du workspace avec HEAD
avec <commit>, un identifiant de commit qui peut être :
- un ID explicite comme “83109ce0d335a…4e8bd58f” tel qu'affiché par git log ;
- HEAD, qui désigne le dernier commit dans la branche courante du dépôt local ;
- HEAD~1, qui désigne l'avant dernier commit dans la branche courante du dépôt local ;
- un nom de branche sur le dépôt local comme master ;
- un nom de branche sur le dépôt distant (origin), comme origin/master.
Une option intéressante permet d'afficher uniquement le nom des fichiers modifiés~:
git diff --name-only
Gestion des conflits
Imaginons maintenant que deux développeurs ont commité des modifications sur leur copie locale respective. Que se passe-t-il au moment de la synchronisation ? On va devoir fusionner ces modifications, ce qui peut engendrer un conflit quand les modifications portent sur le même fichier !
Simulons le problème avec deux copies locales du dépôt : local1 et local2. Dans ce premier cas, nous allons ajouter concurremment deux fichiers différents :
# récupérons deux copies loales du dépôt git clone /tmp/remote /tmp/local1 git clone /tmp/remote /tmp/local2 # ajout de date1.txt dans local1 cd /tmp/local1 date > date1.txt git add date1.txt git commit -m "ajout de date1" # ajout date2.txt dans local2 cd /tmp/local2 date > date2.txt git add date2.txt git commit -m "ajout de date2" # fusion cd /tmp/local1 git push # ok cd /tmp/local2 git push # ko (rejected, pull before!) git pull # ok après merge automatique...
Regardons maintenant ce qu'il se passe, si on modifie concurrement le même fichier, disons “date1.txt”…
# modification de date1.txt dans local1 cd /tmp/local1 date >> date1.txt git add date1.txt git commit -m "modif de date1" # modification de date1.txt dans local2 cd /tmp/local2 date >> date1.txt git add date1.txt git commit -m "modif aussi de date1" cd /tmp/local1 git push # ok cd /tmp/local2 git push # ko (rejected, pull before!) git pull # conflit, le merge automatique échoue !!!
Pour résoudre le conflit, il faut éditer le fichier “date1.txt” responsable du conflit et faire la fusion à la main… Le fichier en cause marque explicitement la zone de conflit et affiche les deux versions à comparer…
<<<<<<< HEAD ma version HEAD dans le dépôt local ======= l'autre version qui vient du dépôt remote >>>>>>> <commit>
On corrige à la main, on commit et on push à nouveau
Les branches locales et distantes
Par défaut, nous travaillons sur la branche master du dépôt local.
Nous allons maintenant créer une nouvelle branche hotfix, afin de corriger un bug.
git branch hotfix git branch hotfix * master
Nous sommes encore dans la branche master comme l'indique “*”. Passons dans la branche hotfix et corrigeons le bug…
git checkout hotfix git branch * hotfix master date >> date.txt git add date.txt git commit -m "deux dates dans hotfix"
Une fois le bug corrigé, nous pouvons le commiter dans la branche courante hotfix. Notons que cela n'a aucun impact sur la branche master. Pour propager cette modification vers la branche master, il va falloir repasser dans la branche master et effectuer un merge.
git checkout master git merge hotfix
On peut finalement supprimer la branche quand cette dernière n'est plus utile.
git branch -d hotfix
Si l'on souhaite que sa branche locale mybranch deviennent une branche distante (ou “remote”) :
git checkout mybranch git push --set-upstream origin mybranch
Pour voir toutes les branches (locales et distantes) :
git fetch -p git branch -a
Nota Bene : le fetch permet de mettre à jour son cache local et éventuellement (option -p) d'effacer dans ce cache les références à des branches mortes !
Pour récupérer une branche distante et la suivre via une branche locale :
git checkout --track origin/mybranch
Puis pour supprimer la branche distante (enfin presque…), il faut faire ceci :
git push origin --delete mybranch
Expliquer le rebase simple :
git checkout mybranch git rebase master git checkout master git merge mybranch git branch -d mybranch
Pour aller plus loin :
Les Tags
En bref :
# création d'un tag git tag -a v1.4 -m "my version 1.4" # liste des tags git tag # afficher les infos sur un tag git show v1.4 # push le tag sur le serveur git push origin v1.4 # création d'une nouvelle branche locale à partir d'un tag git checkout -b version-1.4 v1.4 # git checkout -b [branchname] [tagname]
En détail : https://git-scm.com/book/en/v2/Git-Basics-Tagging
Restaurer un fichier supprimé ou une ancienne version
Si l'on souhaite annuler les modifications faites dans le working directory après le dernier commit…
git checkout
Ou bien pour récupérer un fichier myfile dans sa dernière version commitée :
git checkout -- myfile
Lorsque le fichier path/to/myfile a été supprimé plus loin dans l'historique, il faut examiner les log en détail afin d'identifier le “commit” juste avant la suppression :
git log --summary git checkout <commit> -- <path/to/myfile>
Si l'on souhaite annuler les derniers commits dans le dépôt local pour revenir à la version précédente identifiée par <commit> :
git reset --hard <commit>
Je n'ai pas compris ce qui se passe si on revient à une version précédente au dernier push ?
A compléter… avec revert !
D'autres commandes
Pour éviter de devoir toujours taper son mot de passe au moment de push/pull, il est possible de demander à Git de sauvegarder les credentials :
git config credential.helper store
Si l'on souhaite supprimer du dépôt tous les fichiers non suivis, la commande clean permet de faire le ménage. Attention, tout de même à ne pas supprimer des fichiers par erreur ! Personnellement, j'aime bien les options suivantes : en interactif (-i), suppression des directory aussi (-d) et ignore de .gitignore (-x) !
git clean -i -x -d
Si l'on souhaite faire une archive toto.zip (ou toto.tgz) de son dépôt master pour un projet Git toto :
git archive --format=zip --prefix=toto/ --output /tmp/toto.zip master git archive --format=tar --prefix=toto/ master | gzip > /tmp/toto.tgz
Statistique : pour connaitre le nombre de commit git par utilisateur…
git shortlog -sn
Utilisation du Stash
Une petite “étagère locale” pour sauvegarder toutes les modifications efectués dans un dépôt sans les commiter, par exemple avant de change de branche… cela conserme également les fichiers “non suivis”.
# ... hack hack hack ... $ git stash $ edit emergency fix $ git commit -a -m "Fix in a hurry" $ git stash pop # ... continue hacking ..
Savane
Pour créer son projet Git hébergé au CREMI, il faut utiliser Savane. Choisir un projet privé
Pour aller encore plus loin
- Submodules : https://git-scm.com/book/en/v2/Git-Tools-Submodules