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

De TartareFR
Aller à la navigation Aller à la recherche
Aucun résumé des modifications
Ligne 1 : Ligne 1 :
[[Fichier:LogoGit.svg|thumb|97px]]
==Two ways git merge/git pull 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.
There are 2 ways in which git merge (or a git pull, which is a git fetch and then a git merge) can fail:
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é.
===Git can fail to start the merge===
Quelques avantages de Git sur d'autres (D)VCS :
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:
* 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 ==
error: Entry '<fileName>' not uptodate. Cannot merge. (Changes in working directory)


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


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


=== Configuration de l'environnement ===
===Git can fail during the merge===  
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:


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.
  CONFLICT (content): Merge conflict in <fileName>
  $ git config --global user.name "John Doe"
  Automatic merge failed; fix conflicts and then commit the result.
$ 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 :
==Common questions for when git fails during the merge==
$ git config --global color.ui auto


Vous avez également la possibilité configurer plus finement la coloration :
===How do I know which files have conflicts in them?===
$ git config --global color.diff auto  # coloration des patch
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.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.
Example:


Fichier <path>~/.gitconfig</path>
  # Changes to be committed:
<syntaxhighlight lang="ini">
  #  (use "git reset HEAD <file>..." to unstage)
[user]
  #
        name = didier
  #    modified:  <Some file>
        email = dfabert@b2pweb.com
  #
[color]
  # Changed but not updated:
        diff = auto
  #  (use "git add <file>..." to update what will be committed)
        status = auto
  #  (use "git checkout -- <file>..." to discard changes in working directory)
        branch = auto
  #
[alias]
  #    unmerged:  <file>
        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>


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


Git est fourni avec un script d’auto-complétion que vous allez activer :
"Changed but not updated ... unmerged": All files that have conflicts that must be resolved before repository will be back to working order.
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.
===How do I find conflicts within the file itself?===


Editez ensuite le fichier <path>~/.profile</path> (en le créant si nécessaire) et ajoutez y (à la fin) les lignes :
Conflicts are marked in a file with clear line breaks:
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
  <<<<<<< HEAD:mergetest
  This is my third line
  =======
  This is a fourth line I am adding
  >>>>>>> 4e2b407f501b68f8588aa645acafffa0224b9b78:mergetest


Lorsque vous avez fait ceci, fermez votre terminal et relancez le pour bénéficier de votre personnalisation.
'''<<<<<<<''': 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'''.


Ces petits réglages vont vous rendre bien des services :
'''=======''': 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.


* 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.
'''>>>>>>>''': Indicates the end of the lines that had a merge conflict.
* 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 :


== Guide de survie avec Git ==
===How do I resolve a merge conflict in a 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.}}
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.


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


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


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


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''' :
===General tools===
$ git --bare init .


Ensuite, pour ajouter les fichiers contenus dans mon nouveau dépôt :
====git diff====
$ 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) :
[[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.
$ git clone ''<nowiki>http://git.example.com/projet.git <depot></nowiki>''


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


Ceci est une (trop) brève introduction à Git, présentant les commandes de base.<br/>
diff --git a/mergetest b/mergetest
N'hésitez pas à utiliser la documentation interactive :
index 9be56b9..0aeffac 100644
  $ git help # aide générale
--- a/mergetest
  $ git help ''ma_commande''
+++ b/mergetest
@@ -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


Notez que les révisions Git sont identifiées par une somme SHA1 (pour simplifier, on parlera de révision ''X'', ''Y'', etc ...) :
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.


Afficher le statut des fichiers dans le dépôt :
'''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.
$ git status


Ajouter un fichier au contrôle de versions (placement dans la staging area) :
====git status====
$ git add ''<fichier>''
[[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.


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


Alias pour ajouter/supprimer les fichiers modifiés :
    # Changes to be committed:
$ git addremove
    #  (use "git reset HEAD <file>..." to unstage)
    #
    #  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>
    #


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


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


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


Afficher les modifications effectuées par rapport à une révision précédente :
====git stash====
$ git diff ''<rev>''
'''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.'''


Afficher l'historique :
[[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.
$ git log


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


Revenir sur un commit particulier (crée un commit inverse) :
'''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.
$ git revert ''<rev>''


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


Annuler tout les commit depuis une révision précédente et remettre à jour la copie de travail :
[[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'''.
$ git reset --hard ''<rev>''


Supprimer une modification de la staging area :
====git reset --mixed====
$ 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 !'''.}}


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


Générer une tarball à partir du head :
===Tools specifically for when git conflicts arise during a merge===
$ 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 reset====
$ git count-objects  # pour visualiser le nombre d'objets "temporaires" de Git
$ git gc && git prune


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


Avant d'exporter vos modifications, il faut nettoyer son dépôt :  
'''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.'''
$ 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 :
==Scenarios==
$ git remote add ''<alias>''  ssh://user@git.example.com/projet
===Git refuses to start a merge/pull===


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


Exporter ses modifications sur un dépôt distant :  
error: Entry '<fileName>' would be overwritten by merge. Cannot merge. (Changes staged, but not commited)
$ 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.}}


Importer les modifications à partir d'un dépôt distant :
Steps toward Resolution:
$ git fetch ''<alias>'' ''<branche>''
# 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 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)


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


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


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


=== Collaborer ===
Steps toward Resolution:
 
# git status (Shows all files that are in conflict as unmerged changed in working directory.)
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.
# [[ResolvingMerge#Common_questions_for_when_git_fails_during_the_merge|Resolve merge conflicts]]
Le plus simple, reste d'utiliser la commande diff :
# git add <files>
$ git diff -p ''<rev>'' > ''<patch>''
# git commit -m "<Informative commit message>"
 
[[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}}

Version du 20 septembre 2013 à 12:41

Two ways git merge/git pull can fail

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 can fail to start the merge

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:

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

or

error: Entry '<fileName>' would be overwritten by merge. Cannot merge. (Changes in staging area)

Git can fail during the merge

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>
Automatic merge failed; fix conflicts and then commit the result.

Common questions for when git fails during the merge

How do I know which files have conflicts in them?

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'.

Example:

  # Changes to be committed:
  #   (use "git reset HEAD <file>..." to unstage)
  #
  #    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 committed changes to files that are not affected by the conflict are staged.

"Changed but not updated ... unmerged": All files that have conflicts that must be resolved before repository will be back to working order.

How do I find conflicts within the file itself?

Conflicts are marked in a file with clear line breaks:

 <<<<<<< HEAD:mergetest
 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.

=======: 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.

>>>>>>>: Indicates the end of the lines that had a merge conflict.

How do I resolve a merge conflict in a file?

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.

What do I do after I've resolved conflicts in all affected files?

git add the file(s), git commit and git push (Push only for branches tracked.)

(Note added by Chin - need to commit everything, not just the resolved conflict file.)

Tools to help you resolve both types of merge conflicts

The following git tools below can help you resolve both simple and more complicated git merges.

General tools

git diff

git diff: a command that helps find differences between states of a repository/files. Useful in predicting and preventing merge conflicts.

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

diff --git a/mergetest b/mergetest
index 9be56b9..0aeffac 100644
--- a/mergetest
+++ b/mergetest
@@ -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.

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.

git status

git status: a command provides an overview of all files that have been modified and are in conflict at the time of the merge.

Example:

   # Changes to be committed:
   #   (use "git reset HEAD <file>..." to unstage)
   #
   #   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.
  • "Changed but not updated ... unmerged": All files that have conflicts that must be resolved before repository will be back to working order.

Tools specifically for when git refuses to start merge

git stash

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 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.

git stash save "<Save Message>": Save changes to files in working directory and staging area that git is aware of

 git stash save "Saved changes for stash example"
 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.

git checkout

git checkout <fileName>: Can be used to trash changes in the working directory so as to allow a git pull.

git reset --mixed

git reset --mixed: Can be used to unstage files so as to allow a git pull.

Tools specifically for when git conflicts arise during a merge

git reset

here for more information).

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.

Scenarios

Git refuses to start a merge/pull

Error Messages:

error: Entry '<fileName>' not uptodate. Cannot merge. (Changes in working directory)
error: Entry '<fileName>' would be overwritten by merge. Cannot merge. (Changes staged, but not commited)

Steps toward Resolution:

  1. 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)
  2. git status (Verify all changes are staged)
  3. git pull or git merge (Bring in changes from central repository or another branch)
  4. 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

Error Message:

CONFLICT (content): Merge conflict in <fileName>
Automatic merge failed; fix conflicts and then commit the result.

Steps toward Resolution:

  1. git status (Shows all files that are in conflict as unmerged changed in working directory.)
  2. Resolve merge conflicts
  3. git add <files>
  4. git commit -m "<Informative commit message>"