Ceci est une ancienne révision du document !
Git : fonctionnalités avancées
Pour pouvoir utiliser pleinement Git, il peut être utile de s'approprier la notion de branches. Une branche est une fonctionnalité ou une option que l'on souhaite ajouter et tester sans qu'elle vienne pour l'instant impacter le coeur du projet.
1. Création de branches
On crée une nouvelle branche au projet, à partir de la branche master
git branch nouvellebranche
On passe sur la branche nouvellebranche
git checkout nouvellebranche
ou plus directement :
git checkout -b nouvellebranche
On peut faire des commits (git add & git commit) sur cette branche. On peut aussi repasser sur la branche principale et en faire d'autres.
git checkout master
Il est aussi possible de venir se placer sur un commit, une branche ou un tag précédent :
git checkout nomcommit git checkout vieillebranche git checkout nomtag
(Voir git checkout -h)
2. Fusion de branche (merge)
On repasse sur la branche master
git checkout master
Et on fusionne la branche souhaitée vers la branche en cours (master)
git merge nouvellebranche
Puis on peut supprimer la branche en cours :
git branch -d nouvellebranche # Si status est à jour ou git branch -D nouvellebranche # si pas fusionnée
Gestion de conflits
En cas de merge conflictuel, il faut résoudre le confilt en éditant les fichiers fusionnés qui contiennent les diff.
Il faut éditer les fichiers en conflit et finir avec un :
git add fichiers_en_conflit git commit
Il est possible d'utiliser des outils comme :
git mergetool fichier_en_conflit
Il est possible de merger sans créer de nouveau commit :
git merge --no-commit nouvellebranche
Puis modifier/corriger les fichiers et enfin d'ajouter et de commiter les changements manuellement
Il est alors aussi possible d'annuler un merge avec un :
git merge --abort
Travail collaboratif
Récupérer un dépot distant avec :
git clone url_distant
Dans ce cas, l'origine du dépot distant est mémorisé dans “origin”.
git fetch permet de récupérer les branches distantes. Attention, git pull <⇒ git fetch
git pull # récupère les sources et merge les différences git fetch # récupère les sources sans fusionner
git pull = git fetch + git merge FETCH_HEAD
Pour voir les différences avec le dépot distant :
git remote -v git branch -r # pour voir les branches distantes connues localement git branch -vv # si la branche loclae est trackée
Ajout d'un dépot supplémentaire distant
git remote add nomchoisi urldepot.git git fetch nomchoisi
Et pour mettre à jour le dépot local vers ce dépot distant :
git push -u nomchoisi master
Attention, il faudra mettre à jour les 2 dépots de manière manuelle. Par exemple :
git push heroku master git push -u nomchoisi master
Gestion d'un dépot avec authentification par clef SSH
1) Ajouter sa clef SSH publique dans son profil du dépot distant (github, framagit…)
2) Définir par défaut l'utilisation de sa clef pour ce type de dépot dans ~/.ssh/config
:
Host github.com IdentityFile ~/.ssh/id_rsa
3) définir pour le dépot git local que l'accès se fait en ssh dans dossiergit/.git/config
et changer l'adresse du dépot distant :
[remote "origin"] url = ssh://git@github.com/depotperso/monprojet.git
Et c'est tout. Au prochain git push
, la passphrase de la clef sera demandée (sauf si elle est mémorisée dans le ssh-agent).
Gestion d'un fork d'un projet distant
Cas fréquent : on veut contribuer à un projet existant :
- On forke le projet existant depuis la plateforme
- On clone ce projet localement sur son PC (git clone)
- On crée une nouvelle branche locale de développement (git branch nouvbranche && git checkout nouvbranche)
- on ajoute cette branche distante
- On modifie le code, on commite (git commit -m “blabla”) et on push à distance (git push)
- On retourne sur la plateforme et on crée une PR Pull Request
Problème : que faire si le projet a évolué après, puisque localement on a un clone du fork, mais pas du projet original ?
Il faut définir un dépot upstream du dépot existant :
git remote add upstream git@github.com:nomdepot/nomprojet.git git fetch upstream # on se calle sur upstream et on affiche les branches disponibles git checkout master # pour se mettre localement sur la branche master git reset --hard upstream/master # pour faire un reset local de la branche master
On n'oublie pas de recréer une nouvelle branche pour faire une nouvelle PR :
git checkout -b nouvellebranche
La fois suivante, pour remettre à jour :
git checkout master # pour se mettre localement sur la branche master git reset --hard upstream/master # pour faire un reset local de la branche master git fetch upstream
Pour récupérer des commits d'autres branches dans une branche en cours
Se placer dans la branche qui contient les anciens commits :
git checkout anciennebranche git log # pour afficher les commits du plus récent au plus ancien idcommit3, idcommit2, idcommit1 git checkout master # pour repasser dans la branche master git checkout -b nouvellebranche # pour créer et se placer dans la nouvelle branche git cherry-pick idcommit1 idcommit2 idcommit3 git log # pour afficher les commits récupérés git branch --track master origin/master # pour se reconnecter à une branche existante (passer de dev à master)
Stocker ses accès (sur un serveur sécurisé)
Editer le .git/config
et ajouter son username (avec %40 au lieu de @) et password dans l'URL :
[remote "origin"] url = https://USERNAME:PASSWORD@code.cemea.org/francois.audirac/raspitv.git
Ceci peut être définié au moment du clone :
git clone https://<USERNAME>:<PASSWORD>@github.com/path/to/repo.git
On peut aussi stocker ces infos dans les credentials (.git-credentials
)
git config credential.helper store # pour les activer globalement ou git config --global credential.helper store # pour les activer localement dans chaque dépot
Et au pull ou push suivant, les infos de connexions sont mémorisées !
Déboguer du code bugué depuis un commit inconnu
git bisect permet de faire ça : Trouver par recherche binaire la modification qui a introduit un bogue. (cf doc git-bisect)
Technique par dichotomie entre 2 commits : l'un avec le bug (bad), l'autre sans le bug (good).
Exemple :
git bisect start # démarrage de git bisect git bisect bad # La version actuelle est mauvaise git bisect good v2.6.13-rc2 # la version v2.6.13-rc2
Et se laisser guider.
git bisect reset # pour revenir au HEAD d'origine.
Marche aussi avec un script de test qui doit renvoyer 0 pour être valide :
git bisect run mon_script arguments