Avant-propos
1. Environnement
Vous pouvez installer depuis le site officiel.
Nous utilisons ici la version 2.32.1
en ligne de commande.
Mais vous pouvez bien sûr utiliser un client graphique (comme https://www.sourcetreeapp.com ou https://www.gitkraken.com/).
Je vous recommande tout de même de connaître les commandes en ligne, c’est souvent utile! Pour vous familiariser avec les commandes en ligne, ne pas hésiter à utiliser le site https://learngitbranching.js.org/ (disponible en français si besoin). |
2. Principes généraux
Ce modèle est controversé et ne fait pas l’unanimité. Nous verrons dans la suite qu’il y a plus simple. |
2.1. Git c’est quoi ?
-
Un programme de gestion de version de code source (VCS — Version Control System)
-
Gratuit et open source
-
Distribué (contrairement à Subversion par exemple)
-
Créé à Linus Torvalds (2005)
2.2. Concepts clefs
-
Répertoire (directory or folder)
-
CLI: Common Line Interface
-
Dépôt (repository)
-
GitHub.com
(ouGitLab.com
ougitlab.iut-blagnac.fr
)
2.3. Avant de commencer
On initialise certaine variables (une fois pour toute en général) :
$ git config --global user.name "JM Bruel"
$ git config --global user.email jbruel@gmail.com
$ git config --global alias.co checkout
Ces informations sont stockées dans le fichier Voici un extrait du mien :
Ce qui donne :
|
3. Scénario classique (et idéal)
3.1. Etape 1 : création du repository local
On démarre la gestion de version :
$ git init
Génération d’un répertoire
|
3.2. Etape 2 : ajout des fichiers
On ajoute les fichiers courants au dépôt :
$ git add .
|
|
3.3. Etape 2 (suite) : vérification
On peut visualiser les actions en vérifiant l'état courant du dépôt :
$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
# Changes not staged for commit:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: Generalites.txt
# deleted: S3/128056_56.d
...
3.4. Etape 3 : Commit
Pour entériner les changements :
$ git commit -m "First draft"
[master (root-commit) 4f40f5d] First draft
0 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 titi.txt
create mode 100644 toto.txt
|
3.5. Etape 3 (suite) : Gestion "locale"
Exemple de scénario type (suppression exceptionnelle et rattrapage) :
$ rm titi.txt
$ git status
# On branch master
# Changes not staged for commit:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# deleted: titi.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
$ git checkout -f
$ ls titi.txt
titi.txt
3.6. Etape 4 : Trouver un hébergement distant
Il existe de nombreux endroits disponibles pour héberger du code libre. Les plus connus sont GitHub et GitLab.
3.7. Etape 4 (suite) : déclarer le dépôt distant
Après avoir créé un dépôt distant, il n’y a plus qu’à associer ce dépôt distant avec le notre.
$ git remote add origin git@github.com:jmbruel/first_app.git (1)
$ git push -u origin master (2)
Counting objects: 3, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 225 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:jmbruel/first_app.git
* [new branch] master -> master
Branch master set up to track remote branch master from origin.
1 | Il est possible d’avoir plusieurs dépôts distants, celui-ci sera référencé par origin . |
2 | L’option -u origin master permet d’associer une fois pour toute les git push suivants au fait
de "pousser" sur la branche master du dépôt origin (comme l’indique la dernière ligne). |
3.8. Etape 5 : branch, edit, commit, merge
En cas d’édition et de commit local :
$ git checkout
Your branch is ahead of 'origin/master' by 1 commit.
3.9. Etape 5 (suite) : branching
$ git checkout -b testModifTiti
Switched to a new branch 'testModifTiti'
$ git branch
master
* testModifTiti (1)
1 | La branche courante est repérée par un * . |
3.10. Etape 5 (suite) : edit
Après modification :
$ git status
# On branch testModifTiti
# 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: titi.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
3.11. Etape 5 (suite) : commit
On "sauvegarde" les changements :
$ git commit -am "modif de titi"
[testModifTiti 4515b5d] modif de titi
1 files changed, 7 insertions(+), 0 deletions(-)
|
3.12. Etape 5 (suite) : utilisation des branches
On peut "zapper" d’une branche à l’autre à volonté :
$ ll titi*
-rw-rw-r-- 1 bruel staff 331 12 nov 12:39 titi.txt
$ git co master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
$ ll titi*
-rw-rw-r-- 1 bruel staff 0 12 nov 12:40 titi.txt
3.13. Etape 5 (suite) : merge
Maintenant que la branche a été développée (testée, etc.) on peut l’intégrer à la branche principale :
$ git co master
Switched to branch 'master'
$ git merge testModifTiti
Merge made by recursive.
titi.txt | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
|
3.14. Etape 6 : push
Maintenant que notre dépôt est satisfaisant, on peut le synchroniser avec le dépôt distant :
$ git push
Counting objects: 11, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (9/9), 977 bytes, done.
Total 9 (delta 2), reused 0 (delta 0)
To git@github.com:jmbruel/first_app.git
6103463..3aae48a master -> master
3.15. Etape 7 : pull request (demande)
3.16. Etape 7 (suite) : pull request (acceptation)
$ git checkout -b develop origin/develop
$ ... (1)
$ git checkout master
$ git merge --no-ff develop (2)
$ git push origin master (3)
1 | Vérifiez ce qui va être intégré |
2 | On merge localement pour gérer les problèmes |
3 | On pousse sur master |
3.17. Dépôts existants
Si vous devez partir d’un dépôt existant :
$ git clone git@github.com:jmbruel/first_app.git
|
4. Principes de bases
4.1. Les 3 espaces
4.2. Stash
Même après un git add !
|
5. Illustration des branches
Voici une illustration de l’utilisation des branches (tirée de git-scm).
On part d’une situation type :
On crée une branche (appelée iss53
ici pour indiquer qu’elle traite de l'issue numéro 53) :
$ git checkout -b iss53
On modifie et on commit :
$ edit ...
$ git commit -m "blabla iss53"
master
On revient à la branche maître pour tester une autre solution :
$ git checkout master
$ git checkout -b hotfix
$ edit ...
$ git commit -m "blabla hotfix"
master
)On intègre cette solution à la branche principale :
$ git checkout master
$ git merge hotfix
On continue à travailler sur la branche iss53
:
$ git branch -d hotfix (1)
$ git checkout iss53
$ edit ...
$ git commit -m "blabla iss53"
1 | Destruction de la branche devenue redondante avec master . |
iss53
On intègre cette branche :
$ git checkout master
$ git merge iss53
|
6. Bonne utilisation
6.1. Avoir une procédure concertée
Revenons sur l’exemple type :
6.2. Ne pas versionner n’importe quoi!
Ce qu’il ne faut pas versionner :
-
les exécutables
-
les zip dont le contenu change sans arrêt
-
les images générées
-
tous les binaires en général!
6.3. Les "releases"
En on peut taguer des branches et c’est ce mécanisme qui
permet de gérer simplement les releases.
Dans l’exemple ci-dessous on tague le commit ebb0a7
avec le tag v1.0
.
$ git tag -a v1.0 ebb0a7 -m "Release 1.0 as required by client"
$ git tag
v1.0
$ git push origin v1.0
ne pas oublier de "pousser" le tag. |
On peut voir les détails d’un commit tagué :
$ git show v1.0
tag v1.0
Tagger: Jean-Michel Bruel <jbruel@gmail.com>
Date: Fri Sep 16 14:27:20 2016 +0200
Release 1.0 as required by client
commit 47da474098d95f8ef5c3ca838be8b87d7a7ed729
Author: Jean-Michel Bruel <jbruel@gmail.com>
Date: Fri Sep 16 12:38:20 2016 +0200
On peut aussi taguer a posteriori :
$ git tag -a v1.2 9fceb02 (1)
1 | ajoute le tag v1.2 au commit dont le [SHA-1] commence par 9fceb02 |
Par défaut les tags ne sont pas poussés sur le dépôt distant.
|
7. La gestion de version n’est pas un long fleuve tranquille
7.1. Oups! j’ai oublié un truc
$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend
7.2. Oups! j’ai mis trop de truc
$ git add *.*
$ git reset *.class
Aucun danger |
7.3. CTRL+Z
$ working on some file README.adoc ...
$ git checkout -- README.adoc
Danger! |
7.4. Où j’en suis
$ git status
8. Gestion des branches
Pour faire simple, je vous conseille une gestion qui marche bien pour les petites équipes, tiré de l’excellent livre Pro Git :
-
Deux branches seulement:
master
etdevelop
.$ git branch * develop (1) master (2)
1 develop
est la branche de travail qui contient la dernière version des codages en cours.2 master
est toujours stable et sert au déploiement -
On fork
develop
pour traiter un bug ou une feature.-
On merge dans
develop
-
On détruit la branche devenue inutile
-
Ce qui donne le flot suivant dès que vous devez faire une amélioration (corriger un bug ou ajouter une fonctionnalités) :
-
Créer une branche (e.g.,
fix-451
) -
Travailler sur cette branche
-
Merger cette branche dans
develop
-
Rejouer les tests
-
Régler les conflits éventuels
-
Quand tout fonctionne ⇒ Etape 7 : pull request (demande)
-
On peut livrer à partir de
master
9. Les différents merge
Les illustrations suivantes (qui sont des GIF animés dans la version Web) sont tirés de : https://developer.atlassian.com/blog/2014/12/pull-request-merge-strategies-the-great-debate/?utm_source=twitter&utm_medium=social&utm_campaign=atlassian_pull-request-merge-strategies-the-great-debate. |
9.5. merge
vs. rebase
Here is an illustration using http://git-school.github.io/visualizing-git/ :
Initial situation:
git merge JMB
:
git rebase JMB
:
10. Gestion des conflits
10.1. À la main
$ git checkout master
$ git merge other_branch
Auto-merging toto.txt
CONFLICT (content): Merge conflict in toto.txt
Automatic merge failed; fix conflicts and then commit the result.
$ more toto.txt
<<<<<<< HEAD (1)
Salut monde
======= (2)
hello world!
>>>>>>> other_branch (3)
$ vi toto.txt (4)
$ git commit (5)
1 | Voilà où commence la différence entre la branche courante (HEAD )
et la branche qu’on essaye de merger (other_branch ) |
2 | Séparation |
3 | Voilà où se termine cette différence |
4 | on édite le fichier à la main pour choisir la bonne version |
5 | on commit pour valider la modif |
Il est déconseillé d’en profiter pour faire une nouvelle modif dans le fichier… |
10.2. Avec un peu d’aide
-
git diff
-
git difftool
-
…
11. Git avancé
11.1. Les outils clonés de git dans un dépôt git
Ne pas simplement cloner, car soucis de synchro plus tard.
Faire :
$ git submodule add https://github.com/chaconinc/DbConnector
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
Vous devez voir apparaître, en plus du répertoire cloné, un fichier .gitmodules (si c’est la 1ère fois).
|
11.2. Git-Flow
11.3. Résumé des commandes
Voici un schéma pour résumer la philosophie (tiré de http://osteele.com) :
11.4. Liens utiles
- Le site de référence
- Les "hébergeurs"
-
-
GitHub
-
gitlab
-
- Un excellent livre en ligne sur
- Comparaison entre merge/rebase/etc.
-
https://developer.atlassian.com/blog/2014/12/pull-request-merge-strategies-the-great-debate/?utm_source=twitter&utm_medium=social&utm_campaign=atlassian_pull-request-merge-strategies-the-great-debate Un excellent tutoriel en Français et dynamique : http://learngitbranching.js.org/
- Git pour les nuls
- Best practices
-
https://dev.to/bholmesdev/git-github-best-practices-for-teams-opinionated-28h7
11.5. Glossaire
- fast_forward
-
Quand on merge une branche depuis un noeud situé sur le même "historique". Il s’agit donc pour d’un simple déplacement de pointeur! Cf. illustration ici.