« VCS/Git » : différence entre les versions

De TartareFR
Aller à la navigation Aller à la recherche
Aucun résumé des modifications
Aucun résumé des modifications
 
Ligne 1 : Ligne 1 :
==Two ways git merge/git pull can fail==
[[Fichier:LogoGit.svg|thumb|97px]]


There are 2 ways in which git merge (or a git pull, which is a git fetch and then a git merge) can fail:
Git ''The information manager from hell'' (le gestionnaire d'information issu de l'enfer) est un système de contrôle de versions distribué (DVCS) développé par Linus Torvalds pour le noyau Linux.
Les anglophones seront probablement surpris du choix de ce nom, voici l'explication fournie par Linus en personne, libre à vous d'interpréter  : ''I'm an egotistical ***, and I name all my projects after myself. First 'Linux', now 'git'.'' (Je suis un *** égocentrique, et je nomme mes projets d'après moi-même, d'abord 'Linux', maintenant 'git').


===Git can fail to start the merge===
Git est quotidiennement utilisé par des projets de grande envergure (Linux, Qt, GNOME, etc ...) et a prouvé sa robustesse ainsi que sa versatilité.
This occurs because git knows there are changes in either your working directory or staging area that could be written over by the files that you are merging in. If this happens, there are no merge conflicts in individual files. You need to modify or stash the files it lists and then try to do a git pull again. The error messages are as follows:
Quelques avantages de Git sur d'autres (D)VCS :
* rapidité et efficacité : le leitmotiv de Git, il est de loin le plus rapide des VCS existants et les dépôts Git sont particulièrement compacts.
* intégrité des données : le secret de Git est d'utiliser des fonctions de hash pour identifier et suivre les données. Les données et l'historique sont immutables garantissant une exécution rapide.
* transaction atomique : lorsque vous appliquez des modifications, Git assure qu'elles seront toutes prises en compte ou rien du tout. En cas de problème, votre dépôt Git ne sera pas corrompu.
* création de branches : rien n'est plus simple que de créer/fusionner les branches avec Git. Fini les créations pénibles de branches avec cvs et les fusions encore plus pénibles avec le tronc.
* staging area: contrairement à la majorité des VCS qui considérent que vos fichiers peuvent être sous deux états (modifié/committé), Git lui rajoute un état transitionnaire (''staged''). Au lieu de committer directement vos modifications, Git place un snapshot dans une zone intermédiaire la ''staging area'' (également connu sous le nom d'index). Vous pouvez ainsi continuer à modifier le fichier sans vous soucier d'un commit ultérieur. La staging area est au coeur d'une des fonctionnalités phare de Git qu'est la réécriture de l'historique en permettant d'organiser à votre guise vos commits.


error: Entry '<fileName>' not uptodate. Cannot merge. (Changes in working directory)
== Installation de Git ==


or
Git est disponible dans les dépôts :
# yum install git


error: Entry '<fileName>' would be overwritten by merge. Cannot merge. (Changes in staging area)
Pour installer l'ensemble des outils git, utiliser le méta-paquet <paquet>git-all</paquet> :
# yum install git-all


===Git can fail during the merge===  
=== Configuration de l'environnement ===
This occurs because you have committed changes that are in conflict with someone else's committed changes. Git will do its best to merge the files and will leave things for you to resolve manually in the files it lists. The error message is as follows:


  CONFLICT (content): Merge conflict in <fileName>
Afin de faciliter la gestion de projet, il est recommandé que chaque membre du projet configure un nom utilisateur et une adresse mail permettant de l'identifier.
  Automatic merge failed; fix conflicts and then commit the result.
  $ git config --global user.name "John Doe"
$ git config --global user.email john@doe.com
  $ git config --global core.editor vim


==Common questions for when git fails during the merge==
Par défaut, la coloration des sorties n'est pas activée dans Git (certains barbus n'aiment pas ça), mais il est très facile d'arranger ça :
$ git config --global color.ui auto


===How do I know which files have conflicts in them?===
Vous avez également la possibilité configurer plus finement la coloration :
If your merge failed to even start, there will be no conflicts in files. If git finds conflicts during the merge, it will list all files that have conflicts after the error message. You can also check on which files have merge conflicts by doing a 'git status'.  
$ git config --global color.diff auto  # coloration des patch
$ git config --global color.status auto # coloration de la commande status
$ git config --global color.branch auto # coloration de la commande branch


Example:
Plus de renseignements dans la page du manuel git-config.


  # Changes to be committed:
Fichier <path>~/.gitconfig</path>
  #  (use "git reset HEAD <file>..." to unstage)
<syntaxhighlight lang="ini">
  #
[user]
  #    modified:  <Some file>
        name = didier
  #
        email = dfabert@b2pweb.com
  # Changed but not updated:
[color]
  #  (use "git add <file>..." to update what will be committed)
        diff = auto
  #  (use "git checkout -- <file>..." to discard changes in working directory)
        status = auto
  #
        branch = auto
  #    unmerged:  <file>
[alias]
  #
        stat = status
        ci = commit
        co = checkout
        fp = format-patch
        lg = log --graph --pretty=tformat:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%an %cr)%Creset' --abbrev-commit --date=relative
[core]
        pager = less
        editor = vim
</syntaxhighlight>


"Changes to be committed": All committed changes to files that are not affected by the conflict are staged.
=== Personnaliser le prompt ===


"Changed but not updated ... unmerged": All files that have conflicts that must be resolved before repository will be back to working order.
Git est fourni avec un script d’auto-complétion que vous allez activer :
cp /usr/local/git/contrib/completion/git-completion.bash ~/.git-completion.bash


===How do I find conflicts within the file itself?===
Dans le cas où vous ne trouveriez pas le script dans votre installation, vous pouvez le télécharger en bas de cet article, pour le placer de la même façon dans votre dossier utilisateur.


Conflicts are marked in a file with clear line breaks:
Editez ensuite le fichier <path>~/.profile</path> (en le créant si nécessaire) et ajoutez y (à la fin) les lignes :
source ~/.git-completion.bash
export GIT_PS1_SHOWDIRTYSTATE=1
GIT_PS1_SHOWSTASHSTATE=1
GIT_PS1_SHOWUNTRACKEDFILES=1
export PS1='\[\033[35m\u@\h:\033[36m\W\[\033[0m\033[33m$(__git_ps1 " (%s)")\033[0m\$ '


  <<<<<<< HEAD:mergetest
Vous pouvez retrouver ce prompt directement chez son auteur https://gist.github.com/834949
  This is my third line
  =======
  This is a fourth line I am adding
  >>>>>>> 4e2b407f501b68f8588aa645acafffa0224b9b78:mergetest


'''<<<<<<<''': Indicates the start of the lines that had a merge conflict. The first set of lines are the lines from the file that you were trying to merge the changes '''into'''.
Lorsque vous avez fait ceci, fermez votre terminal et relancez le pour bénéficier de votre personnalisation.


'''=======''': Indicates the break point used for comparison. Breaks up changes that user has committed (above) to changes coming from merge (below) to visually see the differences.
Ces petits réglages vont vous rendre bien des services :


'''>>>>>>>''': Indicates the end of the lines that had a merge conflict.
* En premier lieu, vous allez maintenant bénéficier d’une auto-complétion très pratique à l’usage : si vous saisissez git checkout or+tab vous obtenez directement git checkout origin/master. Cela marche notamment pour les noms de tag, de branche, de stash... ce qui permet de ne plus hésiter à utiliser des noms longs explicites, pour plus de confort.
* Vous bénéficiez aussi d’un prompt qui affiche automatiquement la branche active, et le statut du repository courant dès que vous êtes dans un dossier versionné avec Git.<pre>cedric@iMac-de-Cedric-2:gitsession (master %)$</pre>Vous pouvez voir ici que la branche master est utilisée pour mon répertoire gitsession. Le statut est indiqué sous forme d’un flag :


===How do I resolve a merge conflict in a file?===
== Guide de survie avec Git ==
You resolve a conflict by editing the file to manually merge the parts of the file that git had trouble merging. This may mean discarding either your changes or someone else's or doing a mix of the two. You will also need to delete the '<<<<<<<', '=======', and '>>>>>>>' in the file.
{{Admon/note|Le nom des commandes Git|Parfois, certaines documentations présentent les commandes Git sous la forme ''git-commande''. Cette forme a été rendue obsolète depuis Git 1.5.4 (fin 2006) et il est '''fortement''' recommandé d'utiliser la forme ''git commande''. Avec Git <nowiki>>=</nowiki> 1.6.0, l'ancienne forme n'est plus supportée par défaut et n'est pas garantie d'être présente dans les versions futures.}}


===What do I do after I've resolved conflicts in all affected files?===
Git offre un tutoriel en ligne sous la forme de deux pages du manuel :
git add the file(s), git commit and git push (Push only for branches tracked.)
$ man gittutorial
$ man gittutorial-2 # deuxième partie


('''Note''' added by Chin - need to commit everything, not just the resolved conflict file.)
=== Création de dépôt ===


==Tools to help you resolve both types of merge conflicts==
Supposons que l'on veuille créer un nouveau dépôt vide dans le répertoire ~/git :
The following git tools below can help you resolve both simple and more complicated git merges.
$ git init ''<depot>'' # le répertoire mon_depot doit être créé auparavant


===General tools===
Si vous comptez publier votre dépôt, il est nécessaire de créer un dépôt ''nu'' (bare repository en Anglais) avec l'option --bare. Un dépôt nu ne possède pas de copie de travail, et par convention possède l'extension '''.git''' :
$ git --bare init .


====git diff====
Ensuite, pour ajouter les fichiers contenus dans mon nouveau dépôt :
$ cd ''<depot>''
$ git add *
$ git commit -m "first import"


[[VCS/Git#Commandes_de_base|'''git diff''']]: a command that helps find differences between states of a repository/files. Useful in predicting and preventing merge conflicts.
Pour créer un dépôt à partir d'un autre déjà existant (local ou distant) :
$ git clone ''<nowiki>http://git.example.com/projet.git <depot></nowiki>''


'''git diff origin/master <fileName>''': Find the differences between the current index (HEAD) of fileName and what is in the central repository (origin/msater)
=== Commandes de base ===


diff --git a/mergetest b/mergetest
Ceci est une (trop) brève introduction à Git, présentant les commandes de base.<br/>
index 9be56b9..0aeffac 100644
N'hésitez pas à utiliser la documentation interactive :
--- a/mergetest
  $ git help # aide générale
+++ b/mergetest
  $ git help ''ma_commande''
@@ -1,3 +1,4 @@
  hello
  +I am also editing this line
  This is a test
  -This is my third line
+This is a fourth line I am adding


Changes coming from origin/master are marked with '''+''', while changes that are in your local repository (HEAD) are marked with '''-'''. This syntax does not notify which lines are added are deleted but just which lines originate in which state of the file.
Notez que les révisions Git sont identifiées par une somme SHA1 (pour simplifier, on parlera de révision ''X'', ''Y'', etc ...) :


'''git diff FETCH_HEAD <fileName>''': Will provide the same output as above except is limited to the index of the last fetch that the user did. This may not be latest revision in the central repository.
Afficher le statut des fichiers dans le dépôt :
$ git status


====git status====
Ajouter un fichier au contrôle de versions (placement dans la staging area) :
[[VCS/Git#Commandes_de_base|'''git status''']]: a command provides an overview of all files that have been modified and are in conflict at the time of the merge.
$ git add ''<fichier>''


Example:
Supprimer un fichier du contrôle de versions (reste présent dans l'historique) :
$ git remove ''<fichier>''


    # Changes to be committed:
Alias pour ajouter/supprimer les fichiers modifiés :
    #  (use "git reset HEAD <file>..." to unstage)
$ git addremove
    #
    #  modified:  <Some file>
    #
    # Changed but not updated:
    #  (use "git add <file>..." to update what will be committed)
    #  (use "git checkout -- <file>..." to discard changes in working directory)
    #
    #  unmerged:  <file>
    #


* "Changes to be committed": All changes to files that are not affected by the conflict are staged.
Valider une transaction ou commit (l'option -m permet d'ajouter un message de log) :
$ git commit -m "first import"


* "Changed but not updated ... unmerged": All files that have conflicts that must be resolved before repository will be back to working order.
Afficher les modifications effectuées par rapport à la dernière révision :
$ git diff


===Tools specifically for when git refuses to start merge===
Afficher les modifications effectuées par rapport à la dernière révision dans {{app|kompare}}
$ git difftool -t kompare -y


====git stash====
Afficher les modifications effectuées par rapport à une révision précédente :
'''IMPORTANT: Do not use git stash if git went through with the merge and there were merge conflicts! Only use git stash if git refused to merge because it foresees there being conflicts.'''
$ git diff ''<rev>''


[[VCS/Git#Commandes_de_base|'''git stash''']]: stashes away any changes in your staging area and working directory. This command is useful in saving all changes not ready to be committed and the user wants to have an updated repository.
Afficher l'historique :
$ git log


'''git stash save "<Save Message>"''': Save changes to files in working directory and staging area that git is aware of
Revenir sur une modification non commitée :
  git stash save "Saved changes for stash example"
$ git checkout ''<fichier>''
  Saved working directory and index state "On master: Saved changes for stash example"
  HEAD is now at 4e2b407 Added second file for example.


'''git stash pop''': Removes the most recent stash or any stash specified and applies changes as a merge. If merge fails the stash is not removed from the list and must be removed manually.
Revenir sur un commit particulier (crée un commit inverse) :
$ git revert ''<rev>''


====git checkout====
Annuler tout les commit depuis une révision précédente :
$ git reset ''<rev>''


[[VCS/Git#Commandes_de_base|'''git checkout <fileName>''']]: Can be used to trash changes in the working directory so as to allow a '''git pull'''.
Annuler tout les commit depuis une révision précédente et remettre à jour la copie de travail :
$ git reset --hard ''<rev>''


====git reset --mixed====
Supprimer une modification de la staging area :
$ git reset HEAD ''<fichier>''
{{Admon/note|reset|La raison pour laquelle l'option ''--hard'' n'est pas activée par défaut, c'est pour permettre une utilisation avancée de reset qui est la réécriture de l'historique.
Les lecteurs attentifs me feront remarquer que cela est contradictoire avec l'une des caractéristiques essentielles d'un VCS qui est de conserver l'historique. Une utilisation récurrente (et pratique) de reset est de regrouper plusieurs commits. '''À éviter si l'on travaille en groupe !'''.}}


[[VCS/Git#Commandes_de_base|'''git reset --mixed''']]: Can be used to unstage files so as to allow a '''git pull'''.
Corriger le dernier commit (modifier la description, modifier les fichiers etc ...) :
$ git commit --amend


===Tools specifically for when git conflicts arise during a merge===
Générer une tarball à partir du head :
$ git archive --format=tar --prefix=''<projet>/'' HEAD | bzip2 > ../''<projet>''.tar.bz2 # ne pas oublier le slash !


====git reset====
Nettoyage du dépôt (à effectuer plus ou moins souvent selon la fréquence des commits pour ne pas pénaliser les performances du dépôt) :
$ git count-objects  # pour visualiser le nombre d'objets "temporaires" de Git
$ git gc && git prune


[[VCS/Git#Commandes_de_base|here]] for more information).
=== Travailler avec un dépôt tiers ===


'''IMPORTANT: Do not use any other options other than --hard for reset when resolving a situation where git failed during the merge, as they will leave conflict line markers in file and you can end up committing files with conflict markers still present.'''
Avant d'exporter vos modifications, il faut nettoyer son dépôt :  
$ git repack && git prune
L'opération repack optimise le stockage des objets Git en interne, prune supprime les fichiers inutiles. Avec les versions récentes de Git, on peut se contenter de l'opération gc.


==Scenarios==
Enregistrer un dépôt distant :
===Git refuses to start a merge/pull===
$ git remote add ''<alias>''  ssh://user@git.example.com/projet


Error Messages:
Lister les dépôts distants enregistrés :
  error: Entry '<fileName>' not uptodate. Cannot merge. (Changes in working directory)
  $ git remote -v


  error: Entry '<fileName>' would be overwritten by merge. Cannot merge. (Changes staged, but not commited)
Exporter ses modifications sur un dépôt distant :
  $ git push ''<alias>'' ''<branche>''
{{Admon/warning||Il est déconseillé de faire un push sur un dépôt non nu. Jusqu'à Git 1.7, le push mettait automatiquement à jour la copie de travail ce qui pouvait entraîner des pertes de données. Il est fortement de recommandé de préférer l'opération pull à push, ou bien d'utiliser un dépôt nu pour le push.}}


Steps toward Resolution:
Importer les modifications à partir d'un dépôt distant :
# git stash save "<Message that describes what is being Saved>" (Stashes away any changes in your staging area and working directory in a separate index.) '''OR''' git checkout <file> (throws out your changes so that you can do a merge)
$ git fetch ''<alias>'' ''<branche>''
# git status (Verify all changes are staged)
# git pull or git merge (Bring in changes from central repository or another branch)
# Only if did a 'git stash' in step 1: git stash pop (Will repopulate your changes into your working directory, may have to resolve merge conflicts)


===Git is unable to resolve a merge/pull===
Fusionner les modifications en local :
$ git merge ''<alias>''/''<branche>''


Error Message:
Les deux opérations précédentes peuvent être effectué en une étape:
$ git pull ''<alias>'' ''<branche>''


CONFLICT (content): Merge conflict in <fileName>
Suivre une branche distante à partir d'une branche locale (on ne travaille jamais sur une branche distante directement) :
  Automatic merge failed; fix conflicts and then commit the result.
$ git branch --track ''<branche_locale>'' ''<alias>''/''<branche>''
ou
  $ git checkout -b ''<branche>'' ''<alias>''/''<branche>''


Steps toward Resolution:
=== Collaborer ===
# git status (Shows all files that are in conflict as unmerged changed in working directory.)
 
# [[ResolvingMerge#Common_questions_for_when_git_fails_during_the_merge|Resolve merge conflicts]]
Plus prosaïquement, nous allons nous intéresser à la création, puis à l'application de correctifs. Supposons que vous ayez trouvé un bogue dans votre logiciel favori à la version x.y et que vous voudriez le corriger. D'abord on pull le dépôt du projet, puis reste à écrire le correctif. Quant vous avez terminé, il ne reste plus qu'à soumettre votre patch.
# git add <files>
Le plus simple, reste d'utiliser la commande diff :
# git commit -m "<Informative commit message>"
$ git diff -p ''<rev>'' > ''<patch>''
[[Category:Git]]
 
Vous l'envoyez au mainteneur du projet qui pourra appliquer votre patch très simplement :
$ git apply ''<patch>''
 
Il peut également tester si votre patch est applicable à la branche active avec l'option ''check'' :
$ git apply --check ''<patch>((
Néanmoins, pour des projets très importants comme le noyau Linux, cette méthode devient rapidement fastidieuse. D'où la commande ''format-patch'' qui permet de générer un patch pour chaque commit (d'où l'intérêt de pouvoir regrouper les commits comme on l'a vu précédemment) sous la forme d'un courriel prêt à envoyer.
$ git format-patch ''<rev>''
 
Plus fort encore, git permet même d'envoyer directement un patch à une adresse mail. Il faut d'abord installer le paquet git-email :
# yum install git-email
 
Je vous conseille de configurer Git pour se connecter à votre SMTP, bien évidemment, vous pouvez également passer ces options en ligne de commande (git help send-mail) :
$ git config --global sendemail.smtpserver ''<smtp.example.com>''
$ git config --global sendemail.smtpserverport 465
$ git config --global sendemail.smtpencryption tls
$ git config --global sendemail.smtpuser ''<utilisateur>''
$ git config --global sendemail.smtp.pass ''<password>''
 
Pour envoyer votre patch :
$ git send-mail -to devel@projet.example.com ''<patch>''
 
Et l'apothéose, c'est la facilité avec laquelle on peut appliquer les patchs depuis une  boite mbox :
$ git am -3 ''<boite.mbox>'' # l'option -3 demande à Git d'effectuer un merge
 
Et les commits seront également correctement mis en forme avec l'auteur, la date etc... Et si par malchance, un des patchs est défectueux, Git s'arrêtera et demandera au développeur de corriger l'erreur manuellement. Après correction, le développeur peut continuer l'application des patchs, avec l'option ''resolved'' qui créera automatiquement un commit pour lui.
$ git am --resolved
 
=== Gestion des tags ===
 
Afin de faciliter la vie au mainteneur de paquet, il convient de taguer un commit après une modification majeure avec un numéro de version.
 
Taguer un commit en version 0.4
git tag -a v0.4 -m 'Version 0.4'
 
Propager un tag les dépôts distants
git push --tag
 
=== Gestion des branches ===
 
Pour la plupart des utilisateurs de Git, la fonctionnalité clé de Git est sa gestion extrêmement souple des branches. Mais qu'est-ce qu'une branche ? Une branche est tout simplement un ensemble de révisions différenciés du tronc.<br/>
Une branche est utile lorsque l'on doit maintenir plusieurs versions d'un projet ou que l'on souhaite travailler sur une idée avant de l'inclure dans le tronc.
Il faut retenir que la branche '''master''' est le nom attribué à la branche principale.
 
Afficher les branches existantes :
$ git branch # l'étoile signale la branche actuellement dans le répertoire de travail
 
Créer une branche locale:
$ git branch ''<branche>''
 
Suivre une branche distante:
$ git checkout -b ''<branche_locale>'' ''origin''/''<branche_distante>''
 
Changer de branche :
$ git checkout ''<branche>''
 
Fusionner la branche experimentale dans la branche principale :
$ git checkout master
$ git merge experimental
 
Pour effacer la branche experimentale '''après''' une fusion réussie :
$ git branch -d experimental
 
Pour effacer une branche qui après réflexion ne sera pas fusionnée avec la branche principale
$ git branch -D ''<branche>''
{{Admon/note|git rebase|L'opération rebase est un cas particulier, elle permet d'appliquer les changements intervenus dans une branche (souvent la branche principale) à une autre branche. Supposons que vous ayez corrigé un bogue dans ''master'' mais que le travail dans ''experimental'' n'est pas terminé, il suffit '''rebaser''' experimental sur master  }}
 
Pour rebaser la branche experimental sur master :
$ git checkout experimental
$ git rebase master
{{Admon/warning||Ce paragraphe traite principalement des branches dites ''légères'' ou ''locales'' (lightweight branches). Elles sont internes à un dépôt git.
Il existe un autre type de branches dans Git qui a été implicitement traité auparavant : les clones ! Pour les distinguer des branches ''légères'', on les désigne sous le nom de branches ''lourdes'' (heavy branches).}}
 
=== La mise en lieu sûr ===
 
Il arrive fréquemment qu'en plein milieu de son travail, il faille changer de branche (pour travailler sur un autre aspect du projet) ou bien soumettre une partie des changements sur un dépôt distant. Le problème est que cela implique pour pouvoir revenir dessus plus tard, soit de committer un travail à moitié fini, soit diverses solutions de contournement (voire perdre les changements en cours pour certains !).
 
C'est là qu'intervient le stashing ou '''mise en lieu sûr'''. La mise en lieu sûr consiste à sauvegarder l'état du dépôt à un instant donné pour pouvoir le restaurer plus tard si besoin est sans que cela impacte l'historique du dépôt. La fonctionnalité de mise en lieu sûr permet également de conserver une pile de sauvegardes ou stash, par exemple, lorsqu'on doit travailler sur plusieurs branches simultanément.
 
Sauvegarder l'état du dépôt (retour à l'état initial '''après''' le dernier commit) :
$ git stash
 
Afficher la pile courante :
$ git stash list
 
Appliquer le dernier stash :
$ git stash apply
 
La commande précédente rétablit les changements sans rétablir l'index :
$ git stash apply --index
 
Appliquer le stash numéro 1 :
$ git stash apply stash@{1}
 
Supprimer le stash numéro 3 :
$ git stash drop stash@{3}
 
Git permet également de créer une nouvelle branche (par exemple test-stash) à partir d'un stash :
$ git stash branch test-stash
 
=== Importer un dépôt subversion ===
 
Si votre projet est déjà hébergé dans un référentiel Subversion, migrer vers un autre VCS peut s'avérer problématique si vous perdez l'historique associé. Une extension standard de Git permet d'importer un projet Subversion et l'historique associé.
Pour installer git-svn :
# yum install git-svn
 
$ git svn clone mon_depot_subversion mon_depot.git -s # l'option -s suppose que le dépôt subversion utilise l'organisation (layout) standard
 
Vous pourrez vérifier que l'importation de l'historique s'est bien faite avec la commande log
$ git log
 
Il est également possible de récupérer une partie des révisions du référentiel:
$ git svn clone -r31:58  mon_depot_subversion mon_depot.git
 
Mieux encore, git-svn permet même de se synchroniser avec un dépôt svn ! Il faudra prendre en compte que contrairement à Git, subversion a une gestion linéaire de l'historique. Si le dépôt subversion reste la référence, il faudra ''rebaser'' votre branche avant tout commit. Si vous êtes plusieurs à utiliser git-svn, il est recommandé de créer un dépôt git maitre intermédiaire afin d'éviter la duplications des commits. Même si on perd une partie de la souplesse qui a rendu Git célèbre, on gagne par rapport à subversion : le travail hors-ligne, des utilitaires plus rapides et plus puissants, ce qui paradoxalement fait de Git, l'un des meilleurs clients svn qui soit !
 
On récupère les modifications sur le dépôt maître svn. L'option ''-s'' permet de signaler à git-svn que le dépôt utilise le layout (organisation) standard de svn.
$ git svn -s fetch
 
Pour '''rebaser''' notre branche sur le dépôt maître svn :
$ git svn rebase
 
On commit nos modifications :
$ git svn dcommit
 
Créer une branche subversion :
$ git svn branch '''ma branche'''
 
N'hésitez pas à utiliser l'option ''--dry-run'' (commandes ''fetch'', ''rebase'', ''dcommit'', ''branch'', ''tag'') pour visualiser les changements avant de les soumettre.
 
Cela permet de bénéficier des nombreux avantages de Git sans pour autant brusquer les autres contributeurs.
 
== Publier un dépôt ==
 
Il existe plusieurs manières pour publier un dépôt git, nous nous limiterons à deux méthodes :
* <app>git-daemon</app> : le plus efficace car utilisant le protocole git. La différence qui saute aux yeux est l'URL qui commence par <tt>git://</tt>.
* <app>CGI</app> : plus pratique mais beaucoup moins efficace, le support de HTTP dans Git n'étant pas optimal.
 
==== Configurer Git-daemon ====
 
# yum install git-daemon
 
Avec un compte user, on exporte notre dépôt
cd /tmp
git clone --bare file:///home/didier/vcs/scripts scripts.git
 
Le paquet git-daemon offre une configuration initiale satisfaisante utilisant le service xinetd.
 
On vérifie la présence de la ligne suivante dans le fichier /etc/services :
$ grep 9418 /etc/services
git            9418/tcp                # Git Version Control System
 
Par défaut, la configuration exporte les dépôts git présents dans les répertoires utilisateurs <path>~/vcs</path> (paramètre user-path) et <path>/var/lib/git</path> (paramètre base-path).
 
On supprimera le switch --export-all pour limiter l'export aux seuls dépôts possédant le fichier <path>git-daemon-export-ok</path>.
<syntaxhighlight lang="c">
$ cat /etc/xinetd.d/git
# default: off
# description: The git dæmon allows git repositories to be exported using \
# the git:// protocol.
service git
{
disable = no
        socket_type    = stream
        wait            = no
        user            = git
        group          = git
        server          = /usr/libexec/git-core/git-daemon
        server_args    = --base-path=/var/lib/git --user-path=~/vcs --syslog --inetd --verbose --enable=receive-pack
        log_on_failure  += USERID
        # xinetd doesn't do this by default. bug #195265
        flags = IPv6
}
</syntaxhighlight>
 
Ajout de l'utilisateur et du groupe '''git'''
useradd -r -d /var/lib/git -s /bin/false -c 'Git user for git-daemon'
groupadd git # s'l n'existe pas encore
 
Création du répertoire de travail de git
mkdir -p /var/lib/git
 
Déplacement du dépôt précédemment exporté et on change l'utilisateur et le groupe
mv /tmp/*.git /var/lib/git/
chown -R git:git *.git
 
On autorise l'export de notre projet par le service git
# touch /var/lib/git/scripts.git/git-daemon-export-ok
 
Bien évidemment, il faudra redémarrer le service xinetd pour que celui-ci prenne en compte les modifications apportées.<pre>systemctl restart xinetd.service</pre>
 
Pour permettre le push, il faudra configurer un accès ssh pour chaque développeur. Attribuer le dépôt git à un groupe unix puis rattacher les développeurs à celui-ci est une bonne pratique.
Git offre un shell de connexion minimaliste git-shell ne permettant que les opérations push et pull. <br />
Ici, on crée un compte pour l'utilisateur joe avec git-shell pour shell de connexion et l'ajouter au groupe depot1 :
# useradd joe -s /usr/bin/git-shell -G depot1
 
==== Configuration du CGI ====
 
Il existe différents scripts CGI pour publier des dépôts Git comme l'excellent <app>cgit</app> (cgit chez [http://cgit.freedesktop.org/ Freedesktop.org]) ou bien <app>gitweb</app> intégré dans la distribution officielle de Git.<br/>
Dans ce tutoriel, nous nous intéresserons à la mise en place de <app>gitweb</app>. On commence bien évidemment par l'installer :
# yum install gitweb
 
Vous pouvez tester gitweb rapidement à l'aide de la commande <cmd>instaweb</cmd>. Celle-ci permet démarrer un serveur web (par défaut lighttpd, Apache2 et webrick sont également supportés). Pour le démarrer :
$ cd mon_depot
$ git instaweb
le dépôt devrait être visible dans votre navigateur web à l'adresse http://127.0.0.1:1234 . Pour l'arrêter :
$ git instaweb --stop
 
Nous nous fixons pour objectif de mettre à disposition une collection de dépôts Git à l'adresse git.domaine.com à l'aide de gitweb.
 
La première étape consiste à configurer le CGI pour lui indiquer notamment où sont situés nos dépôts. Le CGI est installé dans le répertoire <path>/var/www/git</path>, on crée le fichier de configuration <path>gitweb_config.perl</path> avec le contenu suivant :
<syntaxhighlight lang="perl">
# emplacement de nos dépôts
$projectroot = "/srv/git";
# Nom donné aux projets dans l'interface.
$home_link_str = "Mes projets";
# Les fichiers nécessaires pour personnaliser l'affichage de votre site
@stylesheets = ("gitweb.css");
$logo = "git-logo.png";
$favicon = "git-favicon.png";
# fichier html contenant le bandeau du site
$site_header = "";
# fichier html à inclure dans la page d'accueil
$home_text = "indextext.html";
# fichier html contenant le pied de page du site
our $site_footer = "";
# Nom du site
$site_name = "Mes dépôts Git";
</syntaxhighlight>
On crée un dépôt vide destiné à accueillir notre projet :
# mkdir /srv/git/machin.git
# cd /srv/git/machin.git
# git --bare init  # l'option bare
# cp hooks/post-update.sample hooks/post-update
# sed -i 's/git-post/git post/' hooks/post-update # pour que les clones
 
On prépare notre dépôt, on édite le fichier <path>.git/description</path> avec quelques lignes décrivant le projet, puis on rajoute dans le fichier <path>.git/config</path> :
<syntaxhighlight lang="ini">
[gitweb]
  owner = "Johnny"
</syntaxhighlight>
===== Avec Apache =====
 
On installe nos dépôts dans le répertoire /srv/git et si on utilise SELinux, on leur attribue le bon contexte.
# semanage fcontext -a -t httpd_sys_content_t '/srv/git(/.*)?'
 
Fedora fournit déjà une configuration fonctionnelle du CGI avec Apache, si vous ouvrez votre navigateur à la page http:/127.0.0.1/git, vos dépôts sont déjà accessibles.
Pour la configuration du sous-domaine git, voici un exemple d'hôte virtuel fonctionnel :
<syntaxhighlight lang="apache">
<VirtualHost 127.0.0.1>
    ServerName git.zangetsu.com
    DocumentRoot /var/www/git/
    <Directory /var/www/git/>
        DirectoryIndex gitweb.cgi
        AddHandler cgi-script .cgi
        Options ExecCGI FollowSymLinks
        Order allow,deny
        Allow from all
        AuthUserFile /etc/srv/passwd
        AuthName "git"
        AuthType Digest
        <Limit POST PUT>
            Require valid-user
        </Limit>
RewriteEngine on
        RewriteBase /
        RewriteRule ^$ gitweb.cgi [L]
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule (.*) gitweb.cgi/$1 [QSA,L]
    </Directory>
</VirtualHost>
</syntaxhighlight>
 
===== Avec lighttpd =====
La première chose à faire est d'attribuer à l'utilisateur lighttpd le répertoire <path>/srv/git</path> :
# chown lighttpd:lighttpd /srv/git
 
Créer le fichier de configuration git.conf dans le répertoire <path>/etc/lighttpd/conf.d</path> avec le contenu suivant :
<syntaxhighlight lang="perl">
# pensez à activer les mod_fastcgi et mod_rewrite
# si vous utilisez le cgi, remplacez mod_fastcgi par mod_cgi
# server.modules += ( "mod_fastcgi" )
# server.modules += ( "mod_rewrite" )
# server.modules += ( "mod_auth" )
# server.modules += ( "mod_setenv" )
# server.modules += ( "mod_redirect" )
 
url.rewrite-once = ( "^/([a-zA-Z]+.git)(.*)$" => "/gitweb.cgi/$1$2" )
 
# accès par le sous domaine
 
$HTTP["host"] =~ "(^|\.)git" {
server.document-root = "/var/www/git"
server.errorlog = "/var/log/lighttpd/git-error.log"
accesslog.filename = "/var/log/lighttpd/git-access.log"
index-file.names = ( "gitweb.cgi" )
cgi.assign = ( "gitweb.cgi" => "" )
#url.rewrite-once = ( "^/([a-zA-Z]+.git)(.*)$" => "/gitweb.cgi/$1$2" )
}
 
# accès par le sous-répertoire
url.rewrite += (
"^/git([/?].*)?$" => "/gitweb.cgi$1"
)
 
$HTTP["url"] =~ "^/gitweb.cgi([/?].*)?$" {
server.document-root = "/var/www/git"
        cgi.assign = ( ".cgi" => "" )
}
 
# quick hack to fix broken display
alias.url += (
  "/gitweb.css" => "/var/www/git/gitweb.css",
  "/git-logo.png" => "/var/www/git/git-logo.png",
  "/git-favicon.png" => "/var/www/git/git-favicon.png",
)
</syntaxhighlight>
 
== les Interfaces utilisateurs ==
 
Voici quelques interfaces graphiques à Git
* <app>gitk</app> : une simple interface tk à Git.
* <app>giggle</app> : une interface Gtk+ à Git.
* <app>gitg</app> : une autre interface Gtk+ assez complète.
* <app>git-cola</app> : une interface PyQt4 caféiné.
* <app>QGit</app> : une interface Qt4 qui se distingue en étant compatible avec l'extension StGit.
* <app>TeamGit</app> : une autre interface Qt4 à git
 
Environnement de développement et éditeurs de textes
* <app>Anjuta</app> : support de Git inclut par défaut.
* <app>QtCreator</app> : support de Git inclut par défaut.
* <app>Emacs</app> : via l'extension emacs-magit.
* <app>Geany</app> : par l'intermédiaire du plugin geanyvc (paquet <paquet>geany-plugins-geanyvc</paquet>)
 
== Quelques liens utiles ==
 
* http://git-scm.com/ : site officiel de Git, la partie documentation est très bien fournie, avec le réputé Git Community Book.
* http://alexgirard.com/git-book/ : le Git Community book traduit en Français.
* http://progit.org/book/ : pro-Git un livre publié chez Apress, disponible en ligne  sous licence CC By-NC-SA 3.0 (non libre mais redistribuable si gratuitement)
* http://code.google.com/p/support/wiki/DVCSAnalysis
 
[[Catégorie:Développement et Programmation|GIT]]
[[Catégorie:Systèmes de contrôle de versions|GIT]]
{{Author|Haikel Guemar}}

Dernière version du 20 septembre 2013 à 12:44

LogoGit.svg

Git The information manager from hell (le gestionnaire d'information issu de l'enfer) est un système de contrôle de versions distribué (DVCS) développé par Linus Torvalds pour le noyau Linux. Les anglophones seront probablement surpris du choix de ce nom, voici l'explication fournie par Linus en personne, libre à vous d'interpréter  : I'm an egotistical ***, and I name all my projects after myself. First 'Linux', now 'git'. (Je suis un *** égocentrique, et je nomme mes projets d'après moi-même, d'abord 'Linux', maintenant 'git').

Git est quotidiennement utilisé par des projets de grande envergure (Linux, Qt, GNOME, etc ...) et a prouvé sa robustesse ainsi que sa versatilité. Quelques avantages de Git sur d'autres (D)VCS :

  • rapidité et efficacité : le leitmotiv de Git, il est de loin le plus rapide des VCS existants et les dépôts Git sont particulièrement compacts.
  • intégrité des données : le secret de Git est d'utiliser des fonctions de hash pour identifier et suivre les données. Les données et l'historique sont immutables garantissant une exécution rapide.
  • transaction atomique : lorsque vous appliquez des modifications, Git assure qu'elles seront toutes prises en compte ou rien du tout. En cas de problème, votre dépôt Git ne sera pas corrompu.
  • création de branches : rien n'est plus simple que de créer/fusionner les branches avec Git. Fini les créations pénibles de branches avec cvs et les fusions encore plus pénibles avec le tronc.
  • staging area: contrairement à la majorité des VCS qui considérent que vos fichiers peuvent être sous deux états (modifié/committé), Git lui rajoute un état transitionnaire (staged). Au lieu de committer directement vos modifications, Git place un snapshot dans une zone intermédiaire la staging area (également connu sous le nom d'index). Vous pouvez ainsi continuer à modifier le fichier sans vous soucier d'un commit ultérieur. La staging area est au coeur d'une des fonctionnalités phare de Git qu'est la réécriture de l'historique en permettant d'organiser à votre guise vos commits.

Installation de Git

Git est disponible dans les dépôts :

# yum install git

Pour installer l'ensemble des outils git, utiliser le méta-paquet <paquet>git-all</paquet> :

# yum install git-all

Configuration de l'environnement

Afin de faciliter la gestion de projet, il est recommandé que chaque membre du projet configure un nom utilisateur et une adresse mail permettant de l'identifier.

$ git config --global user.name "John Doe"
$ git config --global user.email john@doe.com
$ git config --global core.editor vim

Par défaut, la coloration des sorties n'est pas activée dans Git (certains barbus n'aiment pas ça), mais il est très facile d'arranger ça :

$ git config --global color.ui auto

Vous avez également la possibilité configurer plus finement la coloration :

$ git config --global color.diff auto  # coloration des patch
$ git config --global color.status auto # coloration de la commande status
$ git config --global color.branch auto # coloration de la commande branch

Plus de renseignements dans la page du manuel git-config.

Fichier <path>~/.gitconfig</path>

[user]
        name = didier
        email = dfabert@b2pweb.com
[color]
        diff = auto
        status = auto
        branch = auto
[alias]
        stat = status
        ci = commit
        co = checkout
        fp = format-patch
        lg = log --graph --pretty=tformat:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%an %cr)%Creset' --abbrev-commit --date=relative
[core]
        pager = less
        editor = vim

Personnaliser le prompt

Git est fourni avec un script d’auto-complétion que vous allez activer :

cp /usr/local/git/contrib/completion/git-completion.bash ~/.git-completion.bash

Dans le cas où vous ne trouveriez pas le script dans votre installation, vous pouvez le télécharger en bas de cet article, pour le placer de la même façon dans votre dossier utilisateur.

Editez ensuite le fichier <path>~/.profile</path> (en le créant si nécessaire) et ajoutez y (à la fin) les lignes :

source ~/.git-completion.bash
export GIT_PS1_SHOWDIRTYSTATE=1
GIT_PS1_SHOWSTASHSTATE=1
GIT_PS1_SHOWUNTRACKEDFILES=1
export PS1='\[\033[35m\u@\h:\033[36m\W\[\033[0m\033[33m$(__git_ps1 " (%s)")\033[0m\$ '

Vous pouvez retrouver ce prompt directement chez son auteur https://gist.github.com/834949

Lorsque vous avez fait ceci, fermez votre terminal et relancez le pour bénéficier de votre personnalisation.

Ces petits réglages vont vous rendre bien des services :

  • En premier lieu, vous allez maintenant bénéficier d’une auto-complétion très pratique à l’usage : si vous saisissez git checkout or+tab vous obtenez directement git checkout origin/master. Cela marche notamment pour les noms de tag, de branche, de stash... ce qui permet de ne plus hésiter à utiliser des noms longs explicites, pour plus de confort.
  • Vous bénéficiez aussi d’un prompt qui affiche automatiquement la branche active, et le statut du repository courant dès que vous êtes dans un dossier versionné avec Git.
    cedric@iMac-de-Cedric-2:gitsession (master %)$
    Vous pouvez voir ici que la branche master est utilisée pour mon répertoire gitsession. Le statut est indiqué sous forme d’un flag :

Guide de survie avec Git

Note.png
Le nom des commandes Git
Parfois, certaines documentations présentent les commandes Git sous la forme git-commande. Cette forme a été rendue obsolète depuis Git 1.5.4 (fin 2006) et il est fortement recommandé d'utiliser la forme git commande. Avec Git >= 1.6.0, l'ancienne forme n'est plus supportée par défaut et n'est pas garantie d'être présente dans les versions futures.

Git offre un tutoriel en ligne sous la forme de deux pages du manuel :

$ man gittutorial
$ man gittutorial-2 # deuxième partie

Création de dépôt

Supposons que l'on veuille créer un nouveau dépôt vide dans le répertoire ~/git :

$ git init <depot> # le répertoire mon_depot doit être créé auparavant

Si vous comptez publier votre dépôt, il est nécessaire de créer un dépôt nu (bare repository en Anglais) avec l'option --bare. Un dépôt nu ne possède pas de copie de travail, et par convention possède l'extension .git :

$ git --bare init .

Ensuite, pour ajouter les fichiers contenus dans mon nouveau dépôt :

$ cd <depot>
$ git add *
$ git commit -m "first import"

Pour créer un dépôt à partir d'un autre déjà existant (local ou distant) :

$ git clone http://git.example.com/projet.git <depot>

Commandes de base

Ceci est une (trop) brève introduction à Git, présentant les commandes de base.
N'hésitez pas à utiliser la documentation interactive :

$ git help # aide générale
$ git help ma_commande

Notez que les révisions Git sont identifiées par une somme SHA1 (pour simplifier, on parlera de révision X, Y, etc ...) :

Afficher le statut des fichiers dans le dépôt :

$ git status

Ajouter un fichier au contrôle de versions (placement dans la staging area) :

$ git add <fichier>

Supprimer un fichier du contrôle de versions (reste présent dans l'historique) :

$ git remove <fichier>

Alias pour ajouter/supprimer les fichiers modifiés :

$ git addremove

Valider une transaction ou commit (l'option -m permet d'ajouter un message de log) :

$ git commit -m "first import"

Afficher les modifications effectuées par rapport à la dernière révision :

$ git diff

Afficher les modifications effectuées par rapport à la dernière révision dans kompare

$ git difftool -t kompare -y

Afficher les modifications effectuées par rapport à une révision précédente :

$ git diff <rev>

Afficher l'historique :

$ git log

Revenir sur une modification non commitée :

$ git checkout <fichier>

Revenir sur un commit particulier (crée un commit inverse) :

$ git revert <rev>

Annuler tout les commit depuis une révision précédente :

$ git reset <rev>

Annuler tout les commit depuis une révision précédente et remettre à jour la copie de travail :

$ git reset --hard <rev>

Supprimer une modification de la staging area :

$ git reset HEAD <fichier>
Note.png
reset
La raison pour laquelle l'option --hard n'est pas activée par défaut, c'est pour permettre une utilisation avancée de reset qui est la réécriture de l'historique. Les lecteurs attentifs me feront remarquer que cela est contradictoire avec l'une des caractéristiques essentielles d'un VCS qui est de conserver l'historique. Une utilisation récurrente (et pratique) de reset est de regrouper plusieurs commits. À éviter si l'on travaille en groupe !.

Corriger le dernier commit (modifier la description, modifier les fichiers etc ...) :

$ git commit --amend

Générer une tarball à partir du head :

$ git archive --format=tar --prefix=<projet>/ HEAD | bzip2 > ../<projet>.tar.bz2 # ne pas oublier le slash !

Nettoyage du dépôt (à effectuer plus ou moins souvent selon la fréquence des commits pour ne pas pénaliser les performances du dépôt) :

$ git count-objects  # pour visualiser le nombre d'objets "temporaires" de Git
$ git gc && git prune

Travailler avec un dépôt tiers

Avant d'exporter vos modifications, il faut nettoyer son dépôt :

$ git repack && git prune

L'opération repack optimise le stockage des objets Git en interne, prune supprime les fichiers inutiles. Avec les versions récentes de Git, on peut se contenter de l'opération gc.

Enregistrer un dépôt distant :

$ git remote add <alias>  ssh://user@git.example.com/projet

Lister les dépôts distants enregistrés :

$ git remote -v

Exporter ses modifications sur un dépôt distant :

$ git push <alias> <branche>
Warning.png
Il est déconseillé de faire un push sur un dépôt non nu. Jusqu'à Git 1.7, le push mettait automatiquement à jour la copie de travail ce qui pouvait entraîner des pertes de données. Il est fortement de recommandé de préférer l'opération pull à push, ou bien d'utiliser un dépôt nu pour le push.

Importer les modifications à partir d'un dépôt distant :

$ git fetch <alias> <branche>

Fusionner les modifications en local :

$ git merge <alias>/<branche>

Les deux opérations précédentes peuvent être effectué en une étape:

$ git pull <alias> <branche>

Suivre une branche distante à partir d'une branche locale (on ne travaille jamais sur une branche distante directement) :

$ git branch --track <branche_locale> <alias>/<branche>

ou

$ git checkout -b <branche> <alias>/<branche>

Collaborer

Plus prosaïquement, nous allons nous intéresser à la création, puis à l'application de correctifs. Supposons que vous ayez trouvé un bogue dans votre logiciel favori à la version x.y et que vous voudriez le corriger. D'abord on pull le dépôt du projet, puis reste à écrire le correctif. Quant vous avez terminé, il ne reste plus qu'à soumettre votre patch. Le plus simple, reste d'utiliser la commande diff :

$ git diff -p <rev> > <patch>

Vous l'envoyez au mainteneur du projet qui pourra appliquer votre patch très simplement :

$ git apply <patch>

Il peut également tester si votre patch est applicable à la branche active avec l'option check :

$ git apply --check <patch>((

Néanmoins, pour des projets très importants comme le noyau Linux, cette méthode devient rapidement fastidieuse. D'où la commande format-patch qui permet de générer un patch pour chaque commit (d'où l'intérêt de pouvoir regrouper les commits comme on l'a vu précédemment) sous la forme d'un courriel prêt à envoyer.

$ git format-patch <rev>

Plus fort encore, git permet même d'envoyer directement un patch à une adresse mail. Il faut d'abord installer le paquet git-email :

# yum install git-email

Je vous conseille de configurer Git pour se connecter à votre SMTP, bien évidemment, vous pouvez également passer ces options en ligne de commande (git help send-mail) :

$ git config --global sendemail.smtpserver <smtp.example.com>
$ git config --global sendemail.smtpserverport 465
$ git config --global sendemail.smtpencryption tls
$ git config --global sendemail.smtpuser <utilisateur>
$ git config --global sendemail.smtp.pass <password>

Pour envoyer votre patch :

$ git send-mail -to devel@projet.example.com <patch>

Et l'apothéose, c'est la facilité avec laquelle on peut appliquer les patchs depuis une boite mbox :

$ git am -3 <boite.mbox> # l'option -3 demande à Git d'effectuer un merge 

Et les commits seront également correctement mis en forme avec l'auteur, la date etc... Et si par malchance, un des patchs est défectueux, Git s'arrêtera et demandera au développeur de corriger l'erreur manuellement. Après correction, le développeur peut continuer l'application des patchs, avec l'option resolved qui créera automatiquement un commit pour lui.

$ git am --resolved

Gestion des tags

Afin de faciliter la vie au mainteneur de paquet, il convient de taguer un commit après une modification majeure avec un numéro de version.

Taguer un commit en version 0.4

git tag -a v0.4 -m 'Version 0.4'

Propager un tag les dépôts distants

git push --tag

Gestion des branches

Pour la plupart des utilisateurs de Git, la fonctionnalité clé de Git est sa gestion extrêmement souple des branches. Mais qu'est-ce qu'une branche ? Une branche est tout simplement un ensemble de révisions différenciés du tronc.
Une branche est utile lorsque l'on doit maintenir plusieurs versions d'un projet ou que l'on souhaite travailler sur une idée avant de l'inclure dans le tronc. Il faut retenir que la branche master est le nom attribué à la branche principale.

Afficher les branches existantes :

$ git branch # l'étoile signale la branche actuellement dans le répertoire de travail

Créer une branche locale:

$ git branch <branche>

Suivre une branche distante:

$ git checkout -b <branche_locale> origin/<branche_distante>

Changer de branche :

$ git checkout <branche>

Fusionner la branche experimentale dans la branche principale :

$ git checkout master
$ git merge experimental

Pour effacer la branche experimentale après une fusion réussie :

$ git branch -d experimental

Pour effacer une branche qui après réflexion ne sera pas fusionnée avec la branche principale

$ git branch -D <branche>
Note.png
git rebase
L'opération rebase est un cas particulier, elle permet d'appliquer les changements intervenus dans une branche (souvent la branche principale) à une autre branche. Supposons que vous ayez corrigé un bogue dans master mais que le travail dans experimental n'est pas terminé, il suffit rebaser experimental sur master

Pour rebaser la branche experimental sur master :

$ git checkout experimental
$ git rebase master
Warning.png
Ce paragraphe traite principalement des branches dites légères ou locales (lightweight branches). Elles sont internes à un dépôt git. Il existe un autre type de branches dans Git qui a été implicitement traité auparavant : les clones ! Pour les distinguer des branches légères, on les désigne sous le nom de branches lourdes (heavy branches).

La mise en lieu sûr

Il arrive fréquemment qu'en plein milieu de son travail, il faille changer de branche (pour travailler sur un autre aspect du projet) ou bien soumettre une partie des changements sur un dépôt distant. Le problème est que cela implique pour pouvoir revenir dessus plus tard, soit de committer un travail à moitié fini, soit diverses solutions de contournement (voire perdre les changements en cours pour certains !).

C'est là qu'intervient le stashing ou mise en lieu sûr. La mise en lieu sûr consiste à sauvegarder l'état du dépôt à un instant donné pour pouvoir le restaurer plus tard si besoin est sans que cela impacte l'historique du dépôt. La fonctionnalité de mise en lieu sûr permet également de conserver une pile de sauvegardes ou stash, par exemple, lorsqu'on doit travailler sur plusieurs branches simultanément.

Sauvegarder l'état du dépôt (retour à l'état initial après le dernier commit) :

$ git stash

Afficher la pile courante :

$ git stash list

Appliquer le dernier stash :

$ git stash apply

La commande précédente rétablit les changements sans rétablir l'index :

$ git stash apply --index

Appliquer le stash numéro 1 :

$ git stash apply stash@{1}

Supprimer le stash numéro 3 :

$ git stash drop stash@{3}

Git permet également de créer une nouvelle branche (par exemple test-stash) à partir d'un stash :

$ git stash branch test-stash

Importer un dépôt subversion

Si votre projet est déjà hébergé dans un référentiel Subversion, migrer vers un autre VCS peut s'avérer problématique si vous perdez l'historique associé. Une extension standard de Git permet d'importer un projet Subversion et l'historique associé. Pour installer git-svn :

# yum install git-svn
$ git svn clone mon_depot_subversion mon_depot.git -s # l'option -s suppose que le dépôt subversion utilise l'organisation (layout) standard

Vous pourrez vérifier que l'importation de l'historique s'est bien faite avec la commande log

$ git log

Il est également possible de récupérer une partie des révisions du référentiel:

$ git svn clone -r31:58  mon_depot_subversion mon_depot.git

Mieux encore, git-svn permet même de se synchroniser avec un dépôt svn ! Il faudra prendre en compte que contrairement à Git, subversion a une gestion linéaire de l'historique. Si le dépôt subversion reste la référence, il faudra rebaser votre branche avant tout commit. Si vous êtes plusieurs à utiliser git-svn, il est recommandé de créer un dépôt git maitre intermédiaire afin d'éviter la duplications des commits. Même si on perd une partie de la souplesse qui a rendu Git célèbre, on gagne par rapport à subversion : le travail hors-ligne, des utilitaires plus rapides et plus puissants, ce qui paradoxalement fait de Git, l'un des meilleurs clients svn qui soit !

On récupère les modifications sur le dépôt maître svn. L'option -s permet de signaler à git-svn que le dépôt utilise le layout (organisation) standard de svn.

$ git svn -s fetch

Pour rebaser notre branche sur le dépôt maître svn :

$ git svn rebase

On commit nos modifications :

$ git svn dcommit

Créer une branche subversion :

$ git svn branch ma branche

N'hésitez pas à utiliser l'option --dry-run (commandes fetch, rebase, dcommit, branch, tag) pour visualiser les changements avant de les soumettre.

Cela permet de bénéficier des nombreux avantages de Git sans pour autant brusquer les autres contributeurs.

Publier un dépôt

Il existe plusieurs manières pour publier un dépôt git, nous nous limiterons à deux méthodes :

  • <app>git-daemon</app> : le plus efficace car utilisant le protocole git. La différence qui saute aux yeux est l'URL qui commence par git://.
  • <app>CGI</app> : plus pratique mais beaucoup moins efficace, le support de HTTP dans Git n'étant pas optimal.

Configurer Git-daemon

# yum install git-daemon

Avec un compte user, on exporte notre dépôt

cd /tmp
git clone --bare file:///home/didier/vcs/scripts scripts.git

Le paquet git-daemon offre une configuration initiale satisfaisante utilisant le service xinetd.

On vérifie la présence de la ligne suivante dans le fichier /etc/services :

$ grep 9418 /etc/services
git             9418/tcp                # Git Version Control System

Par défaut, la configuration exporte les dépôts git présents dans les répertoires utilisateurs <path>~/vcs</path> (paramètre user-path) et <path>/var/lib/git</path> (paramètre base-path).

On supprimera le switch --export-all pour limiter l'export aux seuls dépôts possédant le fichier <path>git-daemon-export-ok</path>.

 $ cat /etc/xinetd.d/git
 # default: off
 # description: The git dæmon allows git repositories to be exported using \
 #	the git:// protocol.
 service git
 {
 	 disable	= no
         socket_type     = stream
         wait            = no
         user            = git
         group           = git
         server          = /usr/libexec/git-core/git-daemon
         server_args     = --base-path=/var/lib/git --user-path=~/vcs --syslog --inetd --verbose --enable=receive-pack
         log_on_failure  += USERID
         # xinetd doesn't do this by default. bug #195265
         flags		= IPv6
 }

Ajout de l'utilisateur et du groupe git

useradd -r -d /var/lib/git -s /bin/false -c 'Git user for git-daemon'
groupadd git # s'l n'existe pas encore

Création du répertoire de travail de git

mkdir -p /var/lib/git

Déplacement du dépôt précédemment exporté et on change l'utilisateur et le groupe

mv /tmp/*.git /var/lib/git/
chown -R git:git *.git

On autorise l'export de notre projet par le service git

# touch /var/lib/git/scripts.git/git-daemon-export-ok

Bien évidemment, il faudra redémarrer le service xinetd pour que celui-ci prenne en compte les modifications apportées.

systemctl restart xinetd.service

Pour permettre le push, il faudra configurer un accès ssh pour chaque développeur. Attribuer le dépôt git à un groupe unix puis rattacher les développeurs à celui-ci est une bonne pratique. Git offre un shell de connexion minimaliste git-shell ne permettant que les opérations push et pull.
Ici, on crée un compte pour l'utilisateur joe avec git-shell pour shell de connexion et l'ajouter au groupe depot1 :

# useradd joe -s /usr/bin/git-shell -G depot1

Configuration du CGI

Il existe différents scripts CGI pour publier des dépôts Git comme l'excellent <app>cgit</app> (cgit chez Freedesktop.org) ou bien <app>gitweb</app> intégré dans la distribution officielle de Git.
Dans ce tutoriel, nous nous intéresserons à la mise en place de <app>gitweb</app>. On commence bien évidemment par l'installer :

# yum install gitweb

Vous pouvez tester gitweb rapidement à l'aide de la commande <cmd>instaweb</cmd>. Celle-ci permet démarrer un serveur web (par défaut lighttpd, Apache2 et webrick sont également supportés). Pour le démarrer :

$ cd mon_depot
$ git instaweb

le dépôt devrait être visible dans votre navigateur web à l'adresse http://127.0.0.1:1234 . Pour l'arrêter :

$ git instaweb --stop

Nous nous fixons pour objectif de mettre à disposition une collection de dépôts Git à l'adresse git.domaine.com à l'aide de gitweb.

La première étape consiste à configurer le CGI pour lui indiquer notamment où sont situés nos dépôts. Le CGI est installé dans le répertoire <path>/var/www/git</path>, on crée le fichier de configuration <path>gitweb_config.perl</path> avec le contenu suivant :

 # emplacement de nos dépôts
 $projectroot = "/srv/git";
 # Nom donné aux projets dans l'interface.
 $home_link_str = "Mes projets";
 # Les fichiers nécessaires pour personnaliser l'affichage de votre site
 @stylesheets = ("gitweb.css");
 $logo = "git-logo.png";
 $favicon = "git-favicon.png";
 # fichier html contenant le bandeau du site
 $site_header = "";
 # fichier html à inclure dans la page d'accueil
 $home_text = "indextext.html";
 # fichier html contenant le pied de page du site
 our $site_footer = "";
 # Nom du site
 $site_name = "Mes dépôts Git";

On crée un dépôt vide destiné à accueillir notre projet :

# mkdir /srv/git/machin.git
# cd /srv/git/machin.git
# git --bare init  # l'option bare
# cp hooks/post-update.sample hooks/post-update
# sed -i 's/git-post/git post/' hooks/post-update # pour que les clones

On prépare notre dépôt, on édite le fichier <path>.git/description</path> avec quelques lignes décrivant le projet, puis on rajoute dans le fichier <path>.git/config</path> :

[gitweb]
  owner = "Johnny"
Avec Apache

On installe nos dépôts dans le répertoire /srv/git et si on utilise SELinux, on leur attribue le bon contexte.

# semanage fcontext -a -t httpd_sys_content_t '/srv/git(/.*)?'

Fedora fournit déjà une configuration fonctionnelle du CGI avec Apache, si vous ouvrez votre navigateur à la page http:/127.0.0.1/git, vos dépôts sont déjà accessibles. Pour la configuration du sous-domaine git, voici un exemple d'hôte virtuel fonctionnel :

<VirtualHost 127.0.0.1>
    ServerName git.zangetsu.com
    DocumentRoot /var/www/git/
    <Directory /var/www/git/>
        DirectoryIndex gitweb.cgi
        AddHandler cgi-script .cgi
        Options ExecCGI FollowSymLinks
        Order allow,deny
        Allow from all
        AuthUserFile /etc/srv/passwd
        AuthName "git"
        AuthType Digest
        <Limit POST PUT>
            Require valid-user
        </Limit>
	RewriteEngine on
        RewriteBase /
        RewriteRule ^$ gitweb.cgi [L]
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule (.*) gitweb.cgi/$1 [QSA,L]
    </Directory>
</VirtualHost>
Avec lighttpd

La première chose à faire est d'attribuer à l'utilisateur lighttpd le répertoire <path>/srv/git</path> :

# chown lighttpd:lighttpd /srv/git

Créer le fichier de configuration git.conf dans le répertoire <path>/etc/lighttpd/conf.d</path> avec le contenu suivant :

# pensez à activer les mod_fastcgi et mod_rewrite
# si vous utilisez le cgi, remplacez mod_fastcgi par mod_cgi
# server.modules += ( "mod_fastcgi" )
# server.modules += ( "mod_rewrite" )
# server.modules += ( "mod_auth" )
# server.modules += ( "mod_setenv" )
# server.modules += ( "mod_redirect" )

url.rewrite-once = ( "^/([a-zA-Z]+.git)(.*)$" => "/gitweb.cgi/$1$2" )

# accès par le sous domaine

$HTTP["host"] =~ "(^|\.)git" {
	server.document-root = "/var/www/git"
	server.errorlog = "/var/log/lighttpd/git-error.log"
	accesslog.filename = "/var/log/lighttpd/git-access.log"
	index-file.names	= ( "gitweb.cgi" )	
	cgi.assign		= ( "gitweb.cgi" => "" )
	#url.rewrite-once = ( "^/([a-zA-Z]+.git)(.*)$" => "/gitweb.cgi/$1$2" )
}

# accès par le sous-répertoire
url.rewrite += (
	"^/git([/?].*)?$" => "/gitweb.cgi$1"
)

$HTTP["url"] =~ "^/gitweb.cgi([/?].*)?$" {
	server.document-root = "/var/www/git"
        cgi.assign = ( ".cgi" => "" )
}

# quick hack to fix broken display
alias.url += (
  "/gitweb.css" => "/var/www/git/gitweb.css",
  "/git-logo.png" => "/var/www/git/git-logo.png",
  "/git-favicon.png" => "/var/www/git/git-favicon.png",
)

les Interfaces utilisateurs

Voici quelques interfaces graphiques à Git

  • <app>gitk</app> : une simple interface tk à Git.
  • <app>giggle</app> : une interface Gtk+ à Git.
  • <app>gitg</app> : une autre interface Gtk+ assez complète.
  • <app>git-cola</app> : une interface PyQt4 caféiné.
  • <app>QGit</app> : une interface Qt4 qui se distingue en étant compatible avec l'extension StGit.
  • <app>TeamGit</app> : une autre interface Qt4 à git

Environnement de développement et éditeurs de textes

  • <app>Anjuta</app> : support de Git inclut par défaut.
  • <app>QtCreator</app> : support de Git inclut par défaut.
  • <app>Emacs</app> : via l'extension emacs-magit.
  • <app>Geany</app> : par l'intermédiaire du plugin geanyvc (paquet <paquet>geany-plugins-geanyvc</paquet>)

Quelques liens utiles

User.png
Auteur initial Haikel Guemar