GIT

A la découverte de l'outil de gestion de version

Créée par Tony MEMBOT via l'API de présentation Reveal.js

Suivons l'histoire vraie de Robin

Création d'un site internet

  • Indexer ses films préférés
    • Trotro le coquin / Robocar Polly fait des bêtises / ...
  • Évolutif
    • Critique de série
    • Réseau social
    • Streaming
    • Création d'une crypto-monnaie ...

Première version

Une première évolution ...

  • Ajout de blocs de publicité un peu partout sur le site
    • Nécessite l'inclusion de plusieurs librairies javascript
    • Modification de la majorité des pages
    • Modification de la base de données
    • Etc.

... qui se passe mal

Il faut revenir en arrière !

  • Trop de fichiers modifiés
  • Pas de sauvegarde du site avant la modification
  • Des heures de bonheur en vue ...

Première VRAIE évolution

Mise en place d'un système de gestion de version

Robin part à la chasse et tombe sur GIT

Pourquoi choisir GIT ?

Il était une fois l'histoire de GIT

Il était une fois l'histoire de GIT

  • 2002 : Linus Torvalds utilise BitKeeper pour Linux, logiciel propriétaire.

Il était une fois l'histoire de GIT

  • 2002 : Linus Torvalds utilise BitKeeper pour Linux, logiciel propriétaire.
  • Début 2005 : BitKeeper arrête sa version gratuite.
  • Avril 2005 : Linus Torvald crée GIT, répondant à ses besoins (en 5 jours).
    • Système de fichier évolué
    • Décentralisé
    • Libre
  • Versions : Environs tous les trois mois
    • Dernière version : 2.23.10 (16/08/2019)
    • Version de la formation : 2.21.10 (24/02/2019)

Centralisé VS décentralisé

Les ingrédients de GIT

  • Tout est SHA1 : Identifiant unique de chaque objet
    • Blob : contenu des fichiers
    • Tree : répertoire de blob et/ou autre tree
    • Commit :
      • Un Tree
      • 0 ou N commits parents
      • Un message de description
    • Tag

Les objets GIT

Cheminement des commits

Les références

  • Système de pointeur vers des commit
  • Ce qui conduit à un système évolué de branching (déviation)
  • Merge rapides et simplifiés, accompagnés d'outils
  • Travail en parallèle
  • Travail sur plusieurs sujets différents
  • Reprise de commit d'une autre branche
  • etc.

L'espace de travail

Particularités

  • Tout est ajout
    • Même les suppressions de fichiers / dossiers
    • Même les merge
  • Les liens / commit déférencés sont automatiquement supprimés (branches mortes)
  • Hautement scriptable / automatisable

Différence de stockage

Git est optimiser pour ...

  • Être rapide
  • Être robuste
  • Gérer un grand nombre de fichier
  • Réaliser des développements distribués
  • Rendre trivial la gestion des branches et des merge
  • Sa compatibilité : SVN / CVS / HTTP / SSH / ...

... mais l'est moins pour

  • Gérer les gros fichiers binaires
  • Son côté non "user friendly" / brouillon aux premiers abords
    • Nombreuses commandes
    • Très paramétrables
    • ...
  • Les interfaces UI => vive la console !

Robin est fan de la console

Robin est convaincu, il part sur GIT

Mise en place de GIT

Installation

  • Systèmes Linux
    yum install git
    sudo apt-get install git
  • Systèmes windows (émulation git bash)
    http://gitforwindows.org/

Installation

  • Systèmes Linux
    • Conseillé d'installer depuis les sources (paquet distrib trop vieux)
    • Il faut installer gitk soit même :
      sudo apt-get install gitk
  • Systèmes Windows
    • Emulation avec git bash / intégrer au système
    • Gitk fournit de base

Installation sous windows (2.17.0)

Installation sous windows (2.17.0)

Installation sous windows (2.17.0)

Installation sous windows (2.17.0)

Installation sous windows (2.17.0)

Installation sous windows (2.17.0)

Installation sous windows (2.17.0)

Installation sous windows (2.17.0)

Ce que n'installe pas (et n'est pas) GIT

  • Pas d'exposition http des repository
  • Pas de système de contrôles (commit / etc)
  • Pas de gestion d'authentification
  • Pas de gestion d'autorisation
  • Pas d'interface d'administration

Vérification de l'installation

  • Linux : dans un terminal
  • Windows : dans git bash

Paramétrer GIT

  1. Locale (repository)
    
    									git config --local [action]
    								
  2. Global (user)
    
    									git config --global [action]
    								
  3. Système (tout users)
    
    									git config --system [action]
    								

Identifiez vous !


git config --global user.name r.hood

git config --global user.email robin.hood@gmail.com
                        

Paramétrer GIT

  • Vérifier ses paramètres
    
                                        git config --list
    								
  • Vérifier un paramètre spécifique
    
                                        git config user.email
    								
  • Supprimer une entrée dans la config
    
                                        git config --global --unset user.email
    								

Paramétrer GIT

  • Editer un fichier de config manuellement
    
                                        git config --global --edit
    								

Exemple de git config


[user]
name = Tony MEMBOT
email = t.membot@tatayoyo.com

[color]
# Enable colors in color-supporting terminals
ui = auto

[url "https://github.com/"]
insteadOf = git@github.com:
insteadOf = git://github.com/
insteadOf = git+https://github.com/
insteadOf = git+ssh://git@github.com:
insteadOf = ssh://git@github.com:
insteadOf = ssh+https://git@github.com/

[pull]
# This is GREAT… when you know what you're doing and are careful
# WARNING! This option, which does away with the one gotcha of
# auto-rebasing on pulls, is only available from 1.8.5 onwards.
rebase = preserve

[difftool "sourcetree"]
cmd = 'D:/dev/bekom/apps/Perforce/p4merge.exe' -C utf8 \"$LOCAL\" \"$REMOTE\"

[mergetool "sourcetree"]
cmd = 'D:/dev/bekom/apps/Perforce/p4merge.exe' -C utf8 \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"
trustExitCode = true

[status]
# Recursively traverse untracked directories to display all contents
showUntrackedFiles = all

[tag]
# Sort tags as version numbers whenever applicable, so 1.10.2 is AFTER 1.2.0.
sort = version:refname

[alias]
logall = log --graph --abbrev-commit --decorate --date=relative --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white) - %an%C(reset) %C(bold yellow)%d%C(reset)' --all
c = checkout
oups = commit --amend

[http]
proxy = http://proxy.ici.net:1234

[https]
proxy = http://proxy.ici.net:1234

# permet de supprimer les branches remotes obsolètes lorsqu'un fetch est réalisé.
[remote "origin"]
prune = true
                        

Get Started


git init
touch readme.txt
git status
git add readme.txt
git status
git commit -m "My first commit !"
git status
git log
                        

Robin met en pratique

  1. Installer git sur le poste
  2. Vérifier l'installation
  3. Configurer git au niveau user
  4. Initialiser un repo vide
  5. Créer un fichier vide dans ce repo et le commit

Robin est prêt à mettre en place GIT

Maîtriser les bases

Initialiser un nouveau repository


							git init
						
  • Permet d'initialiser un repository vierge
  • Crée un dossier .git
  • Initialise une branche nommée master
  • Initialise une référence HEAD
  • Initialise un working tree/arbre de travail
  • Peut être utilisé dans un dossier contenant déjà des dossiers/fichiers

Dossier .git

  • Seulement présent à la racine du projet
  • Contient :
    • config : Fichiers de configuration (style .ini)
    • objects/* : Repository des objets
    • refs/heads/* : Branches
    • refs/tags/* : Tags
    • logs/* : Logs
    • refs/remotes/* : Tracking des remotes
    • index : le "cache index" (staging)
    • HEAD : pointeur sur un commit de la branche courante (parent du prochain commit)

Les options intéressantes

  • Options :
    • --bare : Création d'un repository sans arbre de travail.
    • --shared : Partager son repository (user linux)

Note : Pour obtenir de l'aide sur une commande

git [command] --help

Rappel structure du working tree

Status du repository


							git status
						
  • Permet de voir l'état du working tree
  • Identifie les éléments
    • Prêts à être commit (staged)
    • Suivis mais non staged (tracked)
    • Non suivis (untracked)
  • Aide à la prochaine action

Git status

Les options intéressantes

  • Options :
    • --short | -s : affiche le statut en short-format
    • --branch | -b : avec short affiche les infos de branche
    • --untracked-files= | -u : paramètre l'affichage des untracked
      • --untracked-files=no | -uno : n'affiche rien
      • --untracked-files=normal | -unormal : affichage normal
      • --untracked-files=all | -uall : affichage verbeux
    • --ignored : voir les fichiers ignorés

Git status

Les options intéressantes


git config --global color.status.added "green bold"

git config --global color.status.changed "red bold"

git config --global color.status.untracked "cyan bold"

git config --global status.showUntrackedFiles all
						

Mettre à jour l'index

Mettre à jour l'index


							git add [filename]
						
  • Permet d'ajouter des fichiers dans la zone d'index (staging)
  • Permet d'ajouter des portions de code dans la zone d'index
  • Se base sur le contenu du working tree
  • Ignore les fichiers / dossiers du .gitignore

Les options intéressantes

  • Options :
    • --all | -A : Ajout des modifications / suppressions
    • --patch | -p : Ajout partiel
    • --dry-run | -n : Test, sans appliquer la commande
    • --ignore-removal : Ignorer les fichiers supprimés

Quelques exemples

  • Tous les png du dossier image (et sous dossiers)
    
    		        					git add image/\*.png
            						
  • Tous les properties à la racine (sans les sous dossiers)
    
    		        					git add *.properties
            						

Quelques exemples

  • Ajouter tous les fichiers et sous dossiers à partir de la commande
    
    		        					git add .
            						
  • Prendre en compte toutes les modifications
    
    		        					git add -A
            						

Quelques exemples

Quelques exemples

  • Ajouter du code partiellement
    
    y - stage this hunk
    n - do not stage this hunk
    q - quit; do not stage this hunk or any of the remaining ones
    a - stage this hunk and all later hunks in the file
    d - do not stage this hunk or any of the later hunks in the file
    g - select a hunk to go to
    / - search for a hunk matching the given regex
    j - leave this hunk undecided, see next undecided hunk
    J - leave this hunk undecided, see next hunk
    k - leave this hunk undecided, see previous undecided hunk
    K - leave this hunk undecided, see previous hunk
    s - split the current hunk into smaller hunks
    e - manually edit the current hunk
    ? - print help
                                    

Remarque


							git add [filename]
						

==


							git stage [filename]
						

Stocker mon travail

Stocker mon travail


							git commit
						
  • Permet de stocker l'index dans un commit
  • Une description est obligatoire !

Git commit

Les options intéressantes

  • Options :
    • --all | -a : Réalise un add avant de faire le commit (sauf pour les nouveaux fichiers)
    • --patch | -p : Pour réaliser un commit partiel
    • --dry-run : Test, sans appliquer la commande
    • --message "message" | -m "message" : Appliquer une description
    • --amend : met à jour le précédent commit plutôt que d'en recréer un
    • Il est possible de spécifier un dossier/fichier pour ne commit que lui

Les options intéressantes


git config --global core.editor nano

git config --global commit.template ~/.template.txt

git config --global commit.status true
						

Quelques exemples

  • Réaliser un commit de l'index en place avec description
    
    		        					git commit -m "feat(section3): init section"
            						
  • Réaliser un commit en réalisant un add
    
    touch readme.txt
    edit hello.txt
    rm privateKey.txt
    git commit -a
            						
  • Si on ne donne aucune description

Historique des commit


							git log
						
  • Permet de visualiser l'historique de commit

Les options intéressantes

  • Options :
    • --oneline : Affiche un commit sur une ligne
    • --decorate=full : Permet d'afficher les références
    • --format= : Pour spécifier un format custom (short / fuller / ...)
    • Il est possible de spécifier un path pour connaître son historique
    • Possibilité de filtrer sur
      • Des dates (since / after / until / ...)
      • Des numéros de commit, des auteurs
      • Des merges, regex, ...

Quelques exemples

  • Récupérer le maximum d'informations
    
    		        					git log --decorate=full --format=fuller
            						

Quelques exemples

  • Avoir une vue rapide sur l'ensemble des commits
    
    		        					git log --oneline
            						

Quelques exemples

  • Retrouver les trois avant derniers commits d'un auteur
    
    		        					git log --oneline --author Tony -n 3 --skip 1
            						

Full

Quelques exemples

  • Retrouver des commits selon le message
    
    		        					git log --grep session
            						

Les options intéressantes


git config --global format.pretty fuller

git config --global log.date relative
						
  • Format par défaut : médium
  • Date par défaut : Sat May 8 19:35:34 2010 -0500

Quelques exemples

  • En mode graph, avec les branches, format custom, date relative ...
    
    git log --graph --abbrev-commit --decorate --date=relative --all
    --format=format:'%C(bold blue)%h%C(reset) -
    %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset)
    %C(dim white) - %an%C(reset) %C(bold yellow)%d%C(reset)'
            						

J'arriverai jamais à retenir cette longue commande !

Les alias


git config --global alias.logall "log --graph --abbrev-commit --decorate
--date=relative --all --format=format:'%C(bold blue)%h%C(reset) -
%C(bold green)(%ar)%C(reset) %C(white)%s%C(reset)
%C(dim white) - %an%C(reset) %C(bold yellow)%d%C(reset)'"
        						

git config --global alias.ca "commit --amend"
        						

git config --global alias.addjs "add \*.js"
        						

Robin met en pratique

  1. Initialiser un repo GIT dans un projet existant (index.html)
  2. Ajouter tous les fichiers du repo à l'index
  3. Réaliser le commit d'initalisation
  4. Créer un fichier index.css & index.js. Modifier index.html sur 2 lignes différentes
  5. Gérer et vérifier l'index pour ne commit que index.js
  6. Gérer et vérifier l'index pour ne commit que la deuxième modification d'index.html
  7. Commit également index.css & le reste d'index.html
  8. Supprimer physiquement index.css et réaliser le commit
  9. Vérifier via la commande log les commits réalisés

Robin est content

  • Il a commit son projet, il est en mesure d'être safe dans ses développements
  • Mais il a des besoins un peu plus poussés
    • Comment revenir sur un add/commit malencontreux
    • Comment vérifier les différences entre deux versions
    • Comment dominer le monde (du cinéma) ...

Ignorer des ressources


							.gitignore
						
  • Le fichier (A la racine du projet) permet de spécifier les ressources à ignorer

### IntellIJ ###
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/dictionaries

### Java ###
*.class
*.jar
*.war

### Maven ###
target/
pom.xml.releaseBackup
pom.xml.versionsBackup
                        

Ignorer des ressources

  • Toutes les commandes GIT ignoreront par défaut les ressources (non déjà tracked) définis dans le fichier
  • Le fichier .gitignore doit être commit
  • Il existe des générateurs : https://www.gitignore.io/

Une petite note sur HEAD

  • HEAD est une référence (pointeur) à la branche courante (master) et au commit courant
  • HEAD^ == HEAD~1 désigne le commit précédent
  • HEAD^^ == HEAD~2 désigne l'avant dernier commit
  • HEAD~X désigne le Xème commit en partant de HEAD
  • Ces annotations sont valables sur les branches : master~2

Voir les différences entre deux états

Voir les différences entre deux états


							git diff
						
  • Permet de visualiser les différences entre
    • Le répertoire de travail et l'index (défaut)
    • L'index et le HEAD
    • Deux commits
    • ...
  • Pour tout le projet, ou des fichiers définis

Les options intéressantes

  • Options :
    • --no-index [path] [path] : Comparer deux fichiers
    • --cached [commit] : Comparer l'index et un commit
    • --staged [commit] : idem cached
    • [commit] [commit] : Comparer deux commits
    • --diff-algorithm={algo}: choisir l'algo de diff
      • myers : greedy, par défaut
      • minimal : myers avec une limite CPU
      • patience : plus lent mais précis
      • histogram : extension de patience

La boite de pandore

  • Git diff est très complet, nombreuses options
  • Commandes spécialisées (raw output format)
    • git-diff-index [tree-ish]
    • git-diff-index --cached [tree-ish]
    • git-diff-tree [-r] [tree-ish-1] [tree-ish-2]
    • git-diff-files

Quelques exemples

Diff par défaut (dév vs index)


                                git diff
                            

Quelques exemples

Diff par défaut avec mots colorés


                                git diff --color-words
                            

Quelques exemples

Diff entre le staged et le HEAD


                                git diff --staged
                            

Quelques exemples

Diff entre deux commits


                                git diff 6813253 71ba976
                            

Diff entre deux commits

Attention à l'ordre !


                                git diff HEAD^ HEAD
                            
!=

                                git diff HEAD HEAD^
                            


                                git diff [source] [target]
                            

Les options intéressantes


git config --global color.diff.old "red bold"
git config --global color.diff.new "green bold"
git config --global diff.algorithm histogram
                            

  • color.diff. : context, old, new, commit, whitespace, oldMoved, newMoved, ...
  • value : normal, black, red, green, yellow, blue, magenta, cyan, white, bold, dim, ul, blink, reverse

Algorithm myers vs patience


git config --global diff.algorithm patience
                            

Annuler mes modification en cours

Annuler mes modification en cours


							git checkout [filename]
						
  • Met à jour un fichier dans le répertoire de travail avec la version de l'index ou du repository
  • Une fois fait les modifications sont perdues !

Git checkout


                            git checkout -- index.html
                        

Quelques exemples

  • Supprimer également ce qu'il y a dans l'index
    
    		        					git checkout HEAD -- index.html
            						

Quelques exemples

  • Se mettre à jour selon un commit
    
    		        					git checkout 0e40D47 index.html
            						

Quelques exemples

  • Oups, j'ai supprimé un fichier
    
                                        git checkout -- '*.html'
            						

Annuler le dernier commit ou l'index

Annuler un commit ou un index


git reset [path]
git reset [toTargetCommit]
						
  • En précisant une ressource, la désindexe pour la remettre en statut modifiée
    • C'est l'inverse du git add
  • En précisant un commit, annule tout jusqu'à ce commit et remet les ressources associées en statut modifiées
    • C'est l'inverse du git commit

Désindexer une ressource


							git reset index.html
						

Désindexer une ressource partiellement


							git reset -p index.html
						

Supprimer un commit


git reset 027def7
git reset HEAD
						

Les options intéressantes

  • Options :
    • --soft : Conserve les ressources reset (default)
    • --hard : Supprime les ressources reset

Quelques exemples

  • Supprimer totalement les deux derniers commits
    
    		        					git reset--hard HEAD~2
            						

Annuler un commit plus ancien

Annuler un commit plus ancien


                            git revert [TargetCommit]
						
  • Crée un nouveau commit avec l'effet inverse du commit ciblé
    • Les fichiers créés sont supprimés et inversement
    • Les modifications sont inversées
    • Etc.
  • La commande peut entraîner des conflits

Les options intéressantes

  • Options :
    • --no-edit : Pour laisser git gérer le message du commit revert
    • --no-commit : Pour ne pas laisser git faire un commit
    • En cas de conflit :
      • --continue : pour continuer après la résolution du conflit
      • --abort : pour abandonner le revert en cours

Quelques exemples

  • Revert un commit au milieu de l'arbre
    
    		        					git revert 0e40d47
            						

Quelques exemples

  • Revert un commit au milieu de l'arbre avec conflit
    
    		        					git revert 0e40d47
            						

Quelques exemples

  • Revert avec conflit mais qu'on abandonne
    
    		        					git revert 0e40d47
            						

Quelques exemples

  • Revert plusieurs commits (premier non inclus)
    
    		        					git revert ca82cb2..0e40d47
            						

Robin met en pratique

  1. Modifier index.html, l'add à l'index (sans le commit)
  2. Modifier index.html puis revenir à l'état de l'index
  3. Créer un fichier test.txt à la racine et faire que git l'ignore
  4. Réaliser le commit du gitignore sans commit index.html
  5. Réaliser le commit d'index.html
  6. Vérifier le diff entre le commit HEAD~1 et le HEAD
  7. Revert le commit du git ignore
  8. Reset le revert réalisé précédemment

Robin se sent un maître en git

  • Mais il a besoin de faire des évolutions en parallèle ...
  • Mais aussi de faire des poc de librairies / fonctions ...
  • ... tout ça sans casser son code principal

Travailler avec des branches

Travailler avec des branches

  • C'est l'un des grands intérêts de GIT
  • Travailler en parallèle, switcher rapidement d'évolutions
  • Une branche n'est qu'un pointeur sur un commit
  • On travaille depuis le début sur une branche : master
  • Qui dit branch, dit merge, mais GIT est optimisé pour

Exemple d'arbre GIT

Il se passe quoi si je commit sur master (HEAD) ?

Commit sur master

Il se passe quoi si je commit sur feat2 ?

Commit sur feat2

Gérer les branches


							git branch
						
  • Permet de lister / créer / supprimer une branche
  • Permet d'avoir une vision d'ensemble des branches
  • Ne manipule pas l'arbre en lui même, juste les références

Les options intéressantes

  • Options :
    • --list : Affiche la liste des branches locales
    • --all | -a : Affiche les branches locales et remotes
    • --no-merged : liste les branches non merged
    • --delete | -d : Supprime la branche si elle est merged
    • --delete --force | -D : Supprime la branche
    • --move | -m : renomme une branche
    • --contain [commit] : liste les branches contenant le commit

Quelques exemples

  • Créer une branche sur le commit pointé par HEAD
    
    		        					git branch feat1
            						
  • Créer une branche sur le commit désigné
    
    		        					git branch feat2 0e40d47
            						
  • Lister les branches
    
    		        					git branch --list
            						

Quelques exemples

  • Savoir quelles branches contient mon commit
    
    		        					git branch --contain 300a98f
            						

Quelques exemples

  • Renommer une branche
    
    		        					git branch -m feat1 feature1
            						
  • Supprimer une branche
    
                                        git branch -d feature1
            						
    
                                        git branch -D feature1
            						
  • Attention Git interdit de supprimer la branche courante

Pourquoi git protège le delete

  • Pour vivre dans git un commit doit être attaché à une référence
  • Un commit non référencé passe dans le garbage
  • Supprimer une branche non mergé, c'est "perdre" les commits qui s'y trouvent

Tag un commit


							git tag nomTag [branch | commit]
						
  • Permet de placer une référence statique sur un commit
  • Si on cible une branche, c'est le commit HEAD de la branche qui est tag
  • Le nom du tag doit être unique

Quelques exemples

  • Lister les tags
    
    		        					git tag
            						
  • Créer un tag sur le commit associé au HEAD
    
                                        git tag v1.0
            						
  • Créer un tag sur une branche
    
                                        git tag v1.0 feat2
            						

Voir les tags dans les logs

git_tag_log.png

Les options intéressantes

  • Possibilité pour un tag d'être :
    • supprimé
    • annoté
    • signé (GPC)
    • ...

Checkout

Switcher de révision


							git checkout [branch | commit]
						
  • Checkout ne sert pas qu'à reset l'index
  • Permet de (dé)placer son working tree
    • Sur un commit (SHA-1)
    • Sur une branche
    • Sur un tag
  • Le switch peut être bloqué si modifications "bloquantes" dans l'index

Switcher sur une branche


							git checkout feat1
						

Switcher sur un commit


							git checkout 2
						

Commit en Detached Head


							git commit -am "I'll lost my work"
						

Perdre des commits


							git checkout master
						

Switcher sur un tag


							git checkout V1.0.0
						

Créer et switcher de branche


							git checkout -b feat4
						

Robin met en pratique

  1. Analyser les logs entre chaque commande
  2. Depuis master avec la commande branch la branche "br1"
  3. Créer avec la commande checkout la branche "br2"
  4. Commit sur br2 en ajoutant un nouveau fichier
  5. Tenter de supprimer "br2"
  6. Commit sur master en ajoutant un autre fichier
  7. Supprimer "br1" qui est en fait inutile
  8. Tenter de supprimer "br2"
  9. Réellement supprimer "br2"
  10. Checkout sur un vieux commit et y réaliser un nouveau commit puis revenir sur master

Robin maîtrise son arbre !

  • Mais maintenant que ses features sont terminées, il veut tout fusionner ...
  • Et certaines branches sont un peu moches, il aimerait réorganiser ...

Fusionner deux branches

Fusionner deux branches


                            git merge targetBranch
						
  • Récupère le contenu de targetBranch pour le fusionner dans la branche courante
  • Tous les commits depuis le point d'origine commun aux deux branches sont récupérés
  • La commande peut entraîner des conflits

Fusionner sur master qui n'a pas dévié


							git merge feat1
						

Fusionner sur master qui a dévié


							git merge feat1
						

Les options intéressantes

  • Options :
    • --no-ff : Pour forcer un merge avec commit
    • --ff-only : Pour autoriser que les merge fast forward
    • -m : Pour préciser le message de commit de merge
    • En cas de conflit :
      • --continue : pour continuer après la résolution du conflit
      • --abort : pour abandonner le merge en cours

Résoudre un conflit

  • Plusieurs opérations peuvent produire un conflit
  • La résolution se fait en plusieurs étapes
    1. Identifier les fichiers en conflit avec git status
    2. Editer les fichiers et résoudre les conflits
    3. Réaliser un git add ou git rm sur les fichiers en conflits
    4. Réaliser un git merge --continue pour continuer le merge
  • A tout moment, on peut abandonner le merge
    
                                        git merge --abort
                                    

Résoudre un conflit manuellement

  • Dans un fichier, il faut se repérer aux marqueurs de conflits
    • <<<<<<< HEAD : ce qui suit est la branche locale
    • ======= : ce qui suit est la branche en cours de merge
    • >>>>>> branchName : marque la fin du conflit

Résoudre un conflit graphiquement

  • Résoudre un conflit est parfois complexe manuellement
  • Les éditeurs de texte ont quasi tous un plugin permettant de le gérer
  • On peut paramétrer git sur un logiciel externe pour gérer les conflits
    
                                        git config merge.tool vimdiff
    						        
  • Pour le lancer lors d'un conflit :
    
                                        git mergetool
                                    

Résoudre un conflit graphiquement

Travailler l'arbre de commit


                            git rebase [branch | commit]
						
  • De base, récupère les commits de la branche courante pour les remettre à partir de la révision ciblée
  • Permet également de travailler ses commits :
    • Renommer
    • Réordonner
    • Supprimer
    • Fusionner
    • Éditer

Rebase sur une révision

Changer l'ordre de commit

Fusionner des commits

Quelques exemples

  • Se rebaser (branche courante) sur master
    
                                        git rebase master
            						
  • Travailler les deux derniers commits de la branche
    
    		        					git rebase -i HEAD~2
            						

Quelques exemples

Edition du fichier de travail

Modifier les messages de commit sera ignoré ici

Les options intéressantes

  • Options :
    • -i : Active le mode interactif
    • --onto : Permet de spécifier la cible (par défaut l'upstream)
    • --exec : Exécute une commande pour chaque étape de rebase
    • En cas de conflit :
      • --continue : pour continuer après la résolution du conflit
      • --abort : pour abandonner le rebase en cours

Rebase hiérarchique


                            git rebase master
                        

Rebase hiérarchique


                            git rebase feat1 feat2 --onto master
                        

Les commandes déjà vues

  • git diff branch1 branch2
  • git log branch1
  • Sur un commit de merge :
    • git reset HEAD
    • git revert HEAD -m numParent

Revert un merge


git show HEAD
git revert HEAD -m 2
                        

Robin met en pratique

  1. Consulter les logs entre chaque commande
  2. Depuis master, créer les branches feat1, feat2, feat3
  3. Commit sur feat2 et merger feat2 sur master
  4. Commit sur feat1 en modifiant index.html
  5. Commit sur master en modifiant index.html au même endroit
  6. Merger feat1 sur master
  7. Sur feat3, réaliser trois commit nommés "un" / "deux" / "trois" puis en changer l'ordre
  8. Rebase feat3 sur master puis merger feat3 sur master
  9. Sur master, faire deux commit nommés "done" / "oups"
  10. Avec rebase fusionner "oups" dans "done"

Robin est un vrai bûcheron

  • Mais il a maintenant trop de sujets pour travailler seul ...
  • Et il souhaite ouvrir son magnifique code au monde entier

Travailler en collaboratif avec un repo distant

Initialiser un repository distant

  • Sur un cloud : github / bitbucket / assembla / ...
  • Sur un réseau entreprise : Git / Gitlab / ...
  • Normalement sans working tree
    
                                        git init --bare
                                    
  • Différent type de communication : Git / SSH / HTTPS

Cloner un repository distant

Cloner un repository distant


                            git clone targetUrl
						
  • Duplique un repository distant en local
  • Récupère tout l'état du repo (git fetch et pull sont automatiquement réalisés)
  • Place automatiquement le working tree sur la branche du remote (généralement master)
  • La branche locale est automatiquement liée à sa remote

Cloner un repository distant

Et si je commit ?

Cloner un repo cloné ?

  • Clone ne crée que la branche par défaut du repo (celle sur laquelle le repo distant est positionné)
  • Si on clone un repo cloné, on ne récupère que ses infos à lui sans les infos remote
    => On ne récupère que les branches existantes (pas les remote du remote).

Les options intéressantes

  • Options :
    • -l | --local : Permet de cloner en passant un chemin
    • --bare : Pour cloner sans créer de working tree
    • --mirror : Avec bare, permet de créer un mirror du repo

Quelques exemples

  • Cloner un repository local
    
                                        git clone --local /home/robin/projets/myProject
                                    
  • Cloner un repository distant en https (recommandé)
    
                                        git clone https://github.com/reivon/FormationGit.git
                                    
  • Cloner un repostory distant en ssh / git
    
    git clone git@github.com:reivon/FormationGit.git
    git clone ssh://git@example.org/~/example.git
                                    

La variable origin

  • Lors d'un clone origin est automatiquement créée pour le repo
  • Contient l'url de repo remote
  • Variable utilisée dans les différentes commandes
  • On peut modifier origin
    
    git remote -v
    # origin  https://github.com/user/repo.git (fetch)
    # origin  https://github.com/user/repo.git (push)
    
    git remote set-url origin https://github.com/user/repo2.git
                                    

La variable origin

  • Sa déclaration est dans le git config du repo
    
                                        git config --local --edit
                                    

Récupérer l'état du repo distant

Récupérer l'état du repo distant


                            git fetch [remote]
						
  • Met à jour les références remotes (branches/tags) en local
  • Ne modifie pas les branches locales
  • Si remote n'est pas spécifié => origin

Les options intéressantes

  • Options :
    • -all : Fetch tous les remotes (pas seulement origin)
    • --dry-run : Montre ce qui va être réalisé, sans l'appliquer
    • --prune | -p : Avant le fetch, supprime toute les références remote qui n'existent plus dans le repo distant

                            git config --global fetch.prune true
                        

Quelques exemples


                            git fetch --prune
                        

Une petite note sur checkout


                            git checkout feat1
                        

Mettre à jour son local

Mettre à jour son local


                            git pull [options] [remote] [branch]
						
  • Met à jour sa branche locale selon la branche distante
  • C'est une combinaison d'un git fetch et d'un git merge
  • Par défaut, le merge est fast forward
  • Si l'upstream est configuré, pas besoin de préciser remote et branch
  • Ne fonctionnera pas si on a du travail en cours

Les options intéressantes

  • Options :
    • --rebase | -r =[false|true|preserve|interactive] : Pour réaliser un rebase au lieu d'un merge
    • --no-edit : Pour accepter le message de merge auto
    • --no-ff : Pour forcer un commit de merge
    • --ff-only : Refuse le merge si non fast forward

Quelques exemples


                            git pull origin master
                        

Quelques exemples


                            git pull --rebase=true origin master
                        

Mettre à jour le repo distant

Mettre à jour le repo distant


                            git push [options] [remote] [branch]
						
  • Met à jour le repo distant avec son local
  • Si l'upstream est configuré, pas besoin de préciser remote et branch
  • Ne fonctionnera pas si le remote a été mis à jour entre temps

Les options intéressantes

  • Options :
    • -u | --set-upstream : Permet de lier la remote au local
    • --delete : Pour supprimer les références en paramètre (pareil que :)
    • -f | --force : Pour forcer le push quoi qu'il arrive
    • -n | --dry-run : Pour faire un fake push et voir ce qu'il se passe

Quelques exemples


                            git push -u origin master
                        

Quelques exemples

  • Supprimer une remote branch (mais pas en local)
    
    git push origin :myBranch
    git push -d origin myBranch
                                    
  • Tenter un push sur un remote qui a bougé
    
                                        git push origin feat3
                                    

Forcer un push


                            git push origin master -f
                        

Init un repo distant

Première solution

  1. Créer le repo distant
  2. Cloner en local ce repo
  3. Copier les fichiers projets dans ce repo
  4. Réaliser les commandes suivantes

git add .
git commit -m "init du projet"
git push origin master
						

Init un repo distant

Deuxième solution


git init
git add .
git commit -m "init du projet"
git remote add origin [remote_repository_URL]
git push origin master
						

Au fait, c'est quoi une pull request ?

  • N'appartient pas à git (surcouche)
  • Commit bloqué pour approbation avant merge

Robin met en pratique

  1. Cloner le projet suivant (repo1) et checkout feat1 puis feat2 : https://github.com/reivon/formationGitRemote.git
  2. Cloner le repo que vous venez de cloner (repo2)
  3. Dans repo1, branch master, modifier et commit index.html ligne 3
  4. Dans repo2
    • Merge feat2 dans feat1 sans avoir de commit de merge et push feat1
    • Supprimer la branche feat2 (local et remote)
    • Sur master, modifier et commit le fichier index.html ligne 3
    • Pusher master sans perdre aucun commit

Robin maîtrise le teamwork

  • Il travaille avec de nombreux sous fifres
  • Mais chacun à sa méthode de push
  • Personne ne sait sur quelle branche travailler
  • Il ne comprend rien à l'organisation des commits
  • Il est temps de normer tout ça ...

Git flow

Git flow

  • Une entreprise = un git flow ...
  • ... mais il y a des règles communes à toute
  • Définit des normes / process :
    • Message de commit
    • Merge ou rebase ? (ff ou no ff)
    • Master ou branches features / develop
    • ...

Ne pas réécrire l'arbre du repo public

When I push force

Le côté obscur

Normer son message de commit

  • Commencer par une courte description d'au plus 50 caractères
  • Laisser la deuxième ligne vide
  • Réaliser une description détaillée dans les lignes suivantes
  • Le # défini un commentaire et est ignoré

Normer son message de commit

  • On utilise de plus en plus la norme angular
    
    <type>(<scope>): <subject>
    <BLANK LINE>
    <body>
    <BLANK LINE>
    <footer>
                                    
  • Type : build / ci / docs / feat / fix / perf / refactor / style / test
  • Scope : A définir par l'entreprise : customer / payment / ...
  • Subject : Court mais évocateur
  • Utiliser l'impératif au possible
  • Si tout est respecté, permet de générer des changelogs !

Commit souvent, push rarement

  • Sur sa branche isolée, on DOIT commit régulièrement
    • Permet de revenir en arrière rapidement
    • Structure ses étapes de travail
    • Sauvegarde sur le serveur
  • Une fois la feature validée
    1. On rebase son travail pour nettoyer l'arbre
    2. On merge sur la branche de destination
    3. On push l'esprit tranquille !

Travail rebase VS travail bâclé

Un commit clair (atomique) peut être revert / cherry-pick / ...

Le principe git flow

L'outil git flow


git flow init
git flow feature start [nom]
git flow feature finish [nom]
git flow release start/finish [nom]
git flow hotfix start/finish [nom]
						

De nombreux autres flow !

De nombreux autres flow !

De nombreux autres flow !

Une seule règle pour les gouverner toutes

Les clients GIT

Sourcetree

Git Kraken

IntellIJ

Et bien d'autres

  • tortoisegit
  • github
  • egit
  • smartgit
  • git cola

Les extras utiles

Planquer son travail temporairement


							git stash [command]
						
  • Sauvegarde l'état courant des modifications dans une zone tampon et clean le working tree vers le HEAD
  • Permet de sauvegarder un état pour réaliser d'autres actions sur le repo

Cas d'utilisation


# ... hack hack hack ...
$ git checkout -b my_wip
$ git commit -a -m "WIP"
$ git checkout master
$ edit emergency fix
$ git commit -a -m "Fix in a hurry"
$ git checkout my_wip
$ git reset --soft HEAD^
# ... continue hacking ...
						

# ... hack hack hack ...
$ git stash
$ edit emergency fix
$ git commit -a -m "Fix in a hurry"
$ git stash pop
# ... continue hacking ...
						

Git stash

Les options intéressantes

  • Options :
    • list : Liste les stash du repo
    • show : Permet d'inspecter un stash
    • push : Permet de créer un stash
      • -m : pour nommer son stash
    • apply : Applique un stash sans l'effacer
    • pop : Applique un stash et le drop
    • drop : Supprime un stash
    • clear : Supprime tous les stash

Quelques exemples

  • Créer un stash nommé
    
    		        					git stash push -m "temp"
            						
  • Appliquer et supprimer un stash
    
    		        					git stash pop
            						

C'est une liste LIFO

Voir les détails d'un objet git


                            git show [options] [object]
                        
  • Permet de consulter les détails
    • Commit : log message & diff
    • branches : log message & diff du dernier commit de la branche
    • tags : tag message et objets référencés

Les options intéressantes

  • Options :
    • --abbrev-commit : Pour avoir le sha1 version courte
    • --pretty=[format] | --format=[format] : Formatter les infos de commit
    • --color-words : Pour avoir un diff aux mots
    • Plus toutes les options de git log et git diff ...

Quelques exemples

  • Avoir les détails d'un commit
    
                                        git show f6ef819
                                    

Quelques exemples

  • Récupérer la liste des fichiers impactés dans un commit
    
                                        git show --pretty="" --name-only 7f6ce03
                                    
  • Récupérer la liste des fichiers impactés avec leur stat
    
                                        git show --stat 7f6ce03
                                    

Copier un commit sur une autre réf


                            git cherry-pick [options] [commit]
                        
  • Peut appliquer plusieurs commit à la fois
  • Le head doit être propre (aucune modification en cours)
  • Des merges peuvent avoir lieu, ils sont résolus de manière classique
  • Utile pour des branches "patch" ou pour débloquer un développement
  • Attention cependant à ne pas le généraliser

Les options intéressantes

  • Options :
    • --edit | -e : Permet d'éditer le message de commit
    • En cas de conflit
      • --continue : En cas de conflit, une fois résolu, permet de continuer
      • --quit : Permet de quitter en l'état le process
      • --abort : Permet de revenir en arrière sur le process
    • --no-commit | -n : Pour appliquer un cherry-pick sans commit

Quelques exemples


                            git cherry-pick 5397e5b
                        

Quelques exemples

Culpabiliser ses collègues


                            git blame [file]
                        
  • Pour chaque ligne du fichier indique
    • L'auteur de la dernière modification
    • Le commit (révision) de la dernière modification

Les options intéressantes

  • Options :
    • -L [start],[end] : Pour préciser les lignes souhaitées
    • --since=[date] : Pour ne voir que les modifications depuis une date

Quelques exemples

  • Voir les modifications sur le fichier index.html
    
                                        git blame index.html
                                    

Quelques exemples

  • Voir les modifications des lignes 40 à 60
    
                                        git blame -L 40,60 index.html
                                    
  • Voir les modifications de moins de trois semaines
    
                                        git blame --since=3.weeks -- index.html
                                    

Déplacer/renommer un fichier


                            git mv [options] [source] [dest]
                        
  • Permet de déplacer un dossier/fichier
  • Tombe en erreur si
    • La ressource dest existe déjà
    • La ressource source n'existe pas
  • Equivalent des commandes :

$ mv LISEZMOI.txt LISEZMOI
$ git rm LISEZMOI.txt
$ git add LISEZMOI
                        

Les options intéressantes

  • Options :
    • --dry-run | -n : Ne réalise pas vraiment les actions
    • --force | -f : Force le renommage / déplacement
    • -k : Skip l'action en cas d'erreur

Attention à windows ! Case sensitive

La perte d'historique

  • Git permet de ne pas perdre l'historique lors d'un move simple
  • Si dans le même commit, on réalise un move et beaucoup de modifications sur le fichier, git considère que ce sont deux fichiers différents
  • Pour avoir le full history d'un fichier qui a été déplacé, il est parfois nécessaire de préciser l'option --follow

                            git log --follow index.html
                        

Rechercher le commit coupable


                            git bisect [cmd]
                        
  • Permet de parcourir l'arbre GIT pour trouver un commit.
  • Fonctionne sur le principe de dichotomie
  • Indispensable sur un arbre git de type "lierre"
  • La recherche démarre lorsqu'au moins 1 bon & 1 mauvais commit ont été notifiés

Les options intéressantes

  • Options :
    • start : démarre le
    • good [commit] : Permet de setter le plus vieux commit ou de dire que le commit courant est correct
    • bad [commit] : Permet de setter le commit d'erreur ou de dire que le commit courant est incorrect
    • reset : Pour stopper le bisect courant et revenir à l'état initial
    • run [script] : Permet d'exécuter un script permettant de donner l'état du commit. Doit retourner 0 pour un bon commit. Doit retourner 1 pour un mauvais commit.

Un petit exemple


mkdir git_bisect_tests
cd git_bisect_tests
git init

echo Fais > test.txt
git add -A && git commit -m "Adding the word 'Fais'"
echo dodo >> test.txt
git add -A && git commit -m "Adding the word 'dodo'"
echo colas >> test.txt
git add -A && git commit -m "Adding the word 'colas'"
echo mon >> test.txt
git add -A && git commit -m "Adding the word 'mon'"
echo petit >> test.txt
git add -A && git commit -m "Adding the word 'petit'"
echo frère >> test.txt
git add -A && git commit -m "Adding the word 'frère'"
sed -i -e 's/frère/monstre/g' test.txt
git add -A && git commit -m "Changing the word 'frère' to 'monstre'"
echo fais >> test.txt
git add -A && git commit -m "Adding the word 'fais'"
echo dodo >> test.txt
git add -A && git commit -m "Adding the word 'dodo'"
echo "stp j'en peux plus" >> test.txt
git add -A && git commit -m "Adding the true end of song"
                        

Aller plus loin

  • git reflog : log des activités git
  • git remote : gestion des remotes
  • git rm : suppression d'un fichier du file system git
  • git clean : suppression des fichiers inconnus de git
  • git for-each-ref : opération itérative
  • git worktree : Gestion de multiple working tree
  • gitk : interface graphique "native"
  • ...

Quelques ressources

Maintenant vous maîtriser GIT
comme Robin


https://gitexercises.fracz.com/