Préalable

modifier

Nous allons maintenant entrer dans le vif du sujet et faire une première modification dans le code source d'une application.

Cette première expérience va nous permettre de découvrir plusieurs notions importantes : l'espace de travail et l'index.

On reprend l'exemple précédent.

git clone https://gerrit.wikimedia.org/r/p/test/mediawiki/extensions/examples.git
cd examples

Faisons d'abord un

git branch

qui va nous répondre

* master

Git nous indique qu'il existe une seule branche appelée master et que c'est sur cette branche que nous travaillons comme l'indique l'astérisque en face de master.

Cela nous est confirmé par

git status

qui nous répond

# On branch master
nothing to commit, working directory clean

Vous pouvez faire un

git log

Pour voir quel est l'auteur et la date de la dernière modification : cela nous servira de repère pour la suite.

Ajouter un fichier dans la zone de transit

modifier

Commençons par une modification simple : l'ajout d'un fichier dans la staging area (la zone de transit vers la sauvegarde). Cela peut être une première étape si vous avez créer un dépôt vide.

Par exemple, créons un fichier mon_nouveau_fichier.txt avec un petit texte dedans.

echo "Ceci est un test de git" > mon_nouveau_fichier.txt

Voyons la façon dont git perçoit ce nouveau fichier

git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#	mon_nouveau_fichier.txt
nothing added to commit but untracked files present (use "git add" to track)

Il nous indique qu'on est toujours sur la branche master, qu'il y a un fichier mon_nouveau_fichier.txt mais qu'il n'est pas suivi (« untracked ») par git.

Comme nous voulons intégrer ce fichier au projet, on ne peut pas encore faire le commit, car commit n'envoie que les fichiers qui sont *tracked*, c'est à dire dans l'index (*staging*). Ajoutons le fichier, comme git nous le suggère, avec add

git add mon_nouveau_fichier.txt

On refait un

git status

Et, cette fois, git nous répond

# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	new file:   mon_nouveau_fichier.txt
#

Le fichier mon_nouveau_fichier.txt sera bien intégré dans notre prochain commit. Allons-y :

git commit -m "mon premier commit"

Remarquons ici qu'avec -m, nous avons choisi de préciser le message de commit directement sur la ligne de commande. En lançant git commit tout court, l'éditeur de texte ($EDITOR) s'ouvre automatiquement pour inviter à saisir un commentaire de soumission.

[master 17eaa3e] mon premier commit
 1 file changed, 1 insertion(+)
 create mode 100644 mon_nouveau_fichier.txt

Constatons immédiatement l'effet de ce commit :

git log

Notre dernier commit apparaît, en premier de la liste (c'est le plus récent).

commit 17eaa3e060b29d708a87867dcb725b7ec64ffaeb
Author: Michel Boudran <michel.boudran@fr.wikibooks.org>
Date:   Tue Jul 22 22:00:39 2014 +0200

    mon premier commit

Avec

git log --graph

On voit clairement que notre commit est lié au commit précédent.

Modifier un fichier

modifier

Faisons une autre modification. Par exemple, modifions le fichier mon_nouveau_fichier.txt en ajoutant une ligne.

echo "Une seconde ligne pour un second test de git" >> mon_nouveau_fichier.txt

Voyons ce que git nous dit :

git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#   (use "git push" to publish your local commits)
#
# 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:   mon_nouveau_fichier.txt
#
no changes added to commit (use "git add" and/or "git commit -a")

Git nous indique bien que le fichier a été modifié, voyons le résumé de ces modifications telles qu'elles sont perçues par git :

git diff
diff --git a/mon_nouveau_fichier.txt b/mon_nouveau_fichier.txt
index a031263..762359c 100644
--- a/mon_nouveau_fichier.txt
+++ b/mon_nouveau_fichier.txt
@@ -1 +1,2 @@
 Ceci est un test de git
+Une seconde ligne pour un second test de git

Git nous montre la ligne qui a été ajoutée (le « + » en début de ligne).

Pour comparer une branche distante avec une locale, utiliser ".." :

 git diff origin/master..master

sinon :

 git diff master origin/master

On va maintenant faire le commit. Comme précédemment, il faut ajouter le fichier au *staging* :

git add mon_nouveau_fichier.txt
 

Si vous voulez ajouter au staging tous les changements qui ont été effectués (fichiers ajoutés, modifiés, supprimés), il vous suffit de faire[1]

git add --all

ou

git add -A
// ou
git add .
git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#   (use "git push" to publish your local commits)
#
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	modified:   mon_nouveau_fichier.txt
#
git commit -m "ma première modification"
[master 5556307] ma première modification
 1 file changed, 1 insertion(+)

Remarquez le code « 5556307 » : il s'agit d'une abréviation de l'identifiant unique de l'objet Git (en l'occurrence une soumission). Chaque objet est haché en SHA-1. L'identifiant complet est en fait 5556307824d8d0425b38c9da696b84430e30f09f, mais généralement les huit premiers caractères suffisent à l'identifier à coup sûr.

git log --graph
* commit 5556307824d8d0425b38c9da696b84430e30f09f
| Author: Michel Boudran <michel.boudran@fr.wikibooks.org>
| Date:   Tue Jul 22 22:18:08 2014 +0200
| 
|     ma première modification
|  
* commit 17eaa3e060b29d708a87867dcb725b7ec64ffaeb
| Author: Michel Boudran <michel.boudran@fr.wikibooks.org>
| Date:   Tue Jul 22 22:00:39 2014 +0200
| 
|     mon premier commit
|

On voit bien que nos deux commits se succèdent.

Supprimer un fichier

modifier
git rm mon_nouveau_fichier.txt
git status
# 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)
#
#	deleted:    mon_nouveau_fichier.txt
#

Il n'est pas nécessaire de faire un add.

git commit -m "ma première suppression de fichier"
[master 77ea581] ma première suppression de fichier
 1 file changed, 2 deletions(-)
 delete mode 100644 mon_nouveau_fichier.txt

Annuler une suppression

modifier

Certains outils comme PyCharm sont dotés d'un historique local (en plus de celui de Git) qui permet d'annuler un "git rm". Il est accessible via un clic droit sur le dossier à restaurer.

Regrouper des modifications

modifier

Il est possible de fusionner une soumission avec la dernière révision, via l'argument amend, sans avoir à réécrire leur résumé avec no-edit :

git commit --amend --no-edit

Généralement on l'utilise pour mettre à jour un commit :

git add -A && git commit --amend --no-edit && git push -f

Si la cible n'est pas la dernière révision, on peut annuler les intermédiaires (via git reset) jusqu'à ce qu'elle le devienne, puis ensuite, replacer les commits annulés avec :

  • git cherry-pick xxx (où xxx est l'ID du commit)

Par ailleurs, certains logiciels clients Git permettent de rassembler plusieurs révisions sélectionnées depuis une liste, comme la fonction cherry-pick de SmartGit ou NetBeans qui permet de sélectionner des commits existant pour les intégrer à sa branche, ou git blame pour afficher les auteurs de chaque passage.

En console, annuler ou modifier un commit peut être réalisé de plusieurs manières :

  • git commit --amend --no-edit
  • git reset HEAD~1
  • git rebase -i (puis squash)

 

En cas de réécriture d'historique, le hash du commit change, ce qui ne pose pas de problème en local mais complexifie considérablement les rebases des branches issues de celle réécrite, car Git voit des conflits entre le commit original et celui réécrit[2].

Pour modifier le résumé d'un ancien commit (xxx) : git rebase --interactive 'xxx^'

 La réécriture d'historique est une étape importante pour transformer les sauvegardes de brouillons en code livrable. En effet, un commit = une étape testable ou facilitant la lecture de la MR.

Il faut donc éviter de les multiplier : ne pas en enchainer plusieurs avec le même résultats, ou en créer des “fix” du précédent. Il faut les casser et les regrouper. Ainsi les rebase auront moins de conflit, les git blame seront parlant et les git revert de feature deviendront possibles. Dans cette optique, il faut d'ailleurs préférer les rebases aux merges pour éviter l'ajout d'un commit de merge inutile nuisant à la lisibilité et à la taille du dépôt.

Enfin, éviter d’embarquer dans un commit un fichier qui ne contient qu’une modification d’espace ou de retour chariot pour limiter les tailles d’historique et les conflits de merge.

Recherche dans l'historique

modifier

Pour rechercher un mot dans tous les historiques de tous les fichiers (du répertoire et des sous-répertoires du script) :

git rev-list --all | (
    while read revision; do
        git grep -F 'mon_mot_clé' $revision
    done
)

Par ailleurs, git bisect permet de rechercher dans l'historique des révisions en définissant les mauvais et bon commits[3].

Continuer

modifier

Vous maîtrisez désormais le strict minimum pour travailler avec git. Vous pouvez ajouter, modifier et supprimer des fichier et enregistrer les changements dans votre dépôt local ainsi que consulter l'historique des modifications. Cela reste toutefois une vision simpliste de la gestion de projet et nous verrons dans la suite comment exploiter les branches locales et comment partager votre travail avec d'autres contributeurs en publiant vos modifications sur un dépôt distant et en récupérant les modifications des autres contributeurs.

Références

modifier