« Git » : différence entre les versions
(Ajustement de git fetch et reset) |
|||
(54 versions intermédiaires par 12 utilisateurs non affichées) | |||
Ligne 1 : | Ligne 1 : | ||
{{Menu tutoriels}} | |||
Git est un [[VCS|système de contrôle de version]] est notamment utilisé pour travailler à plusieurs sur un projet informatique. Il permet notamment d'organiser les modifications effectuées par chacun de manière rigoureuse et sécurisée. | |||
Si tu découvre git, ou que tu n'est pas encore très à l'aise avec, consulte [http://www.vogella.com/articles/Git/article.html ce tutoriel très bien expliqué et très complet]. Pour un aide mémoire, va voir [https://education.github.com/git-cheat-sheet-education.pdf ce Handbook des différentes commandes de git] ou [http://ndpsoftware.com/git-cheatsheet.html ce site qui liste les commandes dans leur contexte]. | |||
''' La grande majorité des commandes ''manuelles'' expliquées sur cette page peuvent être utilisées plus facilement à travers l'interface graphique de certains IDE comme Visual Studio, VSCode, Pycharm, etc!''' Préférez maîtriser l'interface de votre éditeur plutôt que connaître par coeur les commandes à taper. | |||
Obsolète : voir [[SVN]] | |||
== Accéder à l'aide == | |||
Avant toute chose, il est essentiel de savoir où trouver de l'aide, d'autant plus que l'aide de Git est très bien faite. | |||
* Sur internet, il y a le wikiBR, les pages de manuel ([http://linux.die.net/man/1/git sur Linux Die] par exemple) et le [http://book.git-scm.com/ Git Book] | |||
* En terminal, ''git help'' pour une liste des commandes, ''git help cmd'' ou ''git cmd --help'' pour l'aide complète de la commande ''cmd'', ou encore simplement ''git cmd -h'' pour une aide courte sur la commande ''cmd'' | |||
== Installation == | |||
=== Windows === | |||
Téléchargez git sur le [https://git-scm.com/downloads site officiel] | |||
=== Linux & MacOS === | |||
Git est généralement déjà installé sur ces systèmes. Sinon, installez le via un gestionnaire de paquets (homebrew, apt, pacman...) ou sur le [https://git-scm.com/downloads site officiel]. | |||
Testez votre installation en exécutant la commande <code>git</code> dans un terminal. Un texte d'aide devrait apparaître : | |||
usage : git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>] | |||
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path] | |||
[-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare] | |||
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>] | |||
[--config-env=<name>=<envvar>] <command> [<args>] | |||
== Dépôts == | == Dépôts == | ||
Git est complètement décentralisé. Cela signifie que chaque contributeur a sa propre copie locale de tout l'historique d'un projet, et effectue des modifications en local sur sa machine, avant de synchroniser ses changements avec le dépôt distant (hébergé sur [https://gitlab.binets.fr/ gitlab.binets.fr], par exemple). | |||
Un dépôt désigne ce qui stocke les données et l'historique d'un projet. Un '''dépôt distant''' (''remote repository'') désigne le dépôt hébergé sur le cloud (comme sur [http://gitlab.binets.fr/ gitlab.binets.fr]), tandis qu'un '''dépôt local''' (''local repository'') désigne un dépôt que vous avez téléchargé dans un dossier sur votre machine. Les données d'un dépôt local sont contenues dans un dossier caché <code>.git</code> situé à la racine du projet. | |||
Sur cette page, tous les examples sont tirés du Git de [[Sigma]], mais voici d'autres dépôts bien utiles : | |||
* [http://www.github.com/ GitHub] | * [http://www.github.com/ GitHub] | ||
* [http:// | * [http://gitlab.binets.fr/ GitLab], hébergé par le BR | ||
* [http://git.polytechnique.org/ Polytechnique.org] | * [http://git.polytechnique.org/ Polytechnique.org] | ||
Obsolète : [[CVS]] et [[SVN]] sont des systèmes de versionnement centralisés (i.e un serveur contient le dépôt, et chaque utilisateur effectue un ''checkout'' depuis ce dépôt). | |||
== Récupérer le code d'un projet existant == | == Récupérer le code d'un projet existant == | ||
Il existe plusieurs possibilités pour télécharger un projet existant depuis des ''remote repositories'' (depuis [https://gitlab.binets.fr gitlab.binets.fr] ou [https://github.com/ Github.com], par exemple). | |||
Cela crée un '''clone''' du dépôt d'origine (i.e une copie conforme), qui peut d'ailleurs servir de backup si le dépôt d'origine était perdu. Notre clone contient tout l'historique du dépôt depuis sa création, toutes les branches, etc. Cette première opération est très souple. On peut cloner des dépôt via SSH, HTTP, GIT, ou même en local le dépôt d'un autre utilisateur... | On utilise dans tous les cas la commande <code>git clone</code>, qui permet de cloner (télécharger) un projet. Cette commande télécharge le projet dans un nouveau dossier créé dans le dossier où a été exécutée la commande. Cela crée un '''clone''' du dépôt d'origine (i.e une copie conforme), qui peut d'ailleurs servir de backup si le dépôt d'origine était perdu. Notre clone contient tout l'historique du dépôt depuis sa création, toutes les branches, etc. Cette première opération est très souple. On peut cloner des dépôt via SSH, HTTP, GIT, ou même en local le dépôt d'un autre utilisateur... L'adresse http ou ssh exacte d'un dépôt est généralement accessible depuis l'interface de Gitlab ou Github via un bouton '''clone'''. | ||
Par exemple la commande suivante clone dans le dossier ''platal'' la branche ''core/master'' d'une version de Plat/al potientiellement modifiée par le vice-prez 2010 : | Par exemple la commande suivante clone dans le dossier ''platal'' la branche ''core/master'' d'une version de Plat/al potientiellement modifiée par le vice-prez 2010 : | ||
git clone /home/2010/fishilico/dev/platal/.git platal -b core/master | git clone /home/2010/fishilico/dev/platal/.git platal -b core/master | ||
== | ==== Sans authentification ==== | ||
Certains projets publics ne demandent pas d'authentification pour être clonés. Dans ce cas, vous n'avez pas besoin d'un compte avec les droits d'accès développeur. Vous pouvez simplement télécharger le projet avec le protocole http, mais vous ne pourrez pas ajouter vos modifications au dépôt distant. | |||
* En | <code>git clone http://gitlab.binets.fr/br/td-formation-git.git</code> | ||
==== Avec un compte développeur (sans clé ssh) ==== | |||
Si vous disposez d'un compte avec les droits de développeur sur un projet donné, vous pouvez le cloner et lui ajouter vos modifications. L'authentification sans clé ssh n'est pas disponible sur [https://github.com/ Github.com], mais elle l'est sur les instances Gitlab (comme [https://gitlab.binets.fr gitlab.binets.fr]). | |||
Pour exécuter les commandes <code>git clone</code> (télécharger un projet) et <code>git push</code> (ajouter les modifications locales au dépôt distant), git vous demandera vos identifiants et mot de passe. | |||
On utilisera aussi le protocole http : | |||
<code>git clone http://gitlab.binets.fr/br/td-formation-git.git</code> | |||
==== Avec un compte développeur et une clé SSH ==== | |||
Vous pouvez utiliser une clé [[SSH]] pour ne pas avoir besoin de mettre un mot de passe à chaque fois. | |||
Avec un compte muni d'une clé SSH simple, vous pouvez cloner les dépôts auxquels vous avez accès sans avoir à entrer vos identifiants avec la commande suivante : | |||
<code>git clone git@gitlab.binets.fr/br/td-formation-git.git</code> | |||
== Créer un dépôt == | |||
=== Créer un dépôt localement === | |||
Contrairement à [[SVN]] où il faut installer un serveur subversion, créer un dépôt Git local est très rapide : '''dans le dossier que l'on souhaite versionner''', il suffit de taper : | |||
git init | |||
Ou bien, dans le dossier parent où on souhaite créer un nouveau dépôt vide : | |||
git init nom-du-dépot-à-créer | |||
Et voilà, le dossier est versionné : on peut donc commencer à faire des modifications, des commits, etc. (bien entendu, on ne peut pas ''pusher'' ses commits, puisqu'il n'y a pas de serveur distant). | |||
Cette particularité rend Git très efficace pour versionner un petit projet, un exercice de TD, etc. | |||
Il est ensuite possible de partager ce dépôt en le publiant vers un dépôt distant. Voir [https://docs.github.com/en/migrations/importing-source-code/using-the-command-line-to-import-source-code/adding-locally-hosted-code-to-github ce guide] pour Github. | |||
=== Créer un dépôt distant pour le cloner ensuite === | |||
Si vous souhaitez créer un nouveau projet commun, il est plus facile de créer un dépôt distant vide depuis les interfaces de Gitlab ou Github pour ensuite le cloner localement avec la commande <code>git clone</code>. | |||
Voir [https://docs.gitlab.com/ee/user/project/#create-a-blank-project ce guide] pour Gitlab. | |||
== Du bon usage de gitignore == | |||
Dans un projet, il est inutile de '''versionner''' (ie stocker et garder une trace des modifications successives dans le dépôt) les fichiers temporaires et les fichiers compilés (<code>.exe</code> et <code>.o</code>, <code>.pyc</code> et <code>.class</code> pour le c++, python et java par exemple) typiquement générés à partir d'un Makefile avec la commande <code>make</code>. | |||
Pour éviter de les versionner, il suffit d'utiliser un fichier '''''.gitignore''''' bien placé. Généralement, chaque projet a un tel fichier dans son dossier principal. Un fichier .gitignore placé à la racine du projet sera appliqué à l'ensemble du projet (c'est en général suffisant). Il est possible de placer des fichiers .gitignore dans des sous dossiers afin d'avoir un contrôle plus fin des fichiers versionnés. | |||
Voici un exemple de fichier .gitignore d'un projet d'INF443 c++ : | |||
# Ignore the build directory | |||
build/ | |||
# Ignore ALL c++ compiled .o files and shader .d files | |||
*.o | |||
*.d | |||
# Ignore ALL executables and debugger files | |||
*.exe | |||
*.pdb | |||
# Ignore visual studio cache directory | |||
.vs/ | |||
# Ignore imgui settings | |||
imgui.ini | |||
== Effectuer un commit == | |||
Un '''commit''' est une sauvegarde d'un ensemble de fichiers modifiés. Cela permet de suivre chronologiquement les modifications effectuées sur un projet. Par exemple, si l'ajout d'une fonctionnalité sur Sigma modifie les fichiers ''blah'', ''blih'' et ''bloh'', le ''commit'' associé regroupe les modifications de ces trois fichiers, et associe à cette modification une '''date''', un '''auteur''', et le '''message''' écrit par l'auteur pour décrire ce commit. | |||
En général, les IDE comme '''Visual Studio''', '''VSCode''', '''Pycharm''', etc proposent un moyen d'effectuer des commits directement depuis une interface graphique. Si vous souhaitez utiliser git ''à la main'', utilisez les commandes suivantes. | |||
==== Effectuer un commit manuellement ==== | |||
Voir la section [[Git#Quel_est_l'état_de_ma_copie_de_travail_? | Quel est l'état de ma copie de travail]]. | |||
Pour effectuer un commit, il faut : | |||
* Vérifier l'état de la copie de travail, pour ne commiter que ce qui est nécessaire | |||
git status | |||
git diff | |||
* Indiquer à Git quels fichiers feront partie du commit ; ceci permet de ne committer que les modifications de quelques fichiers | |||
git add path/to/blih path/to/blah path/to/bloh | |||
* Vérifier que l'on a ajouté les fichiers que l'on voulait : | |||
git status | |||
* Faire le commit (le ''-s'' ajoute une ligne ''Signed of by'' dans le message, pour pouvoir retrouver plus efficacement l'auteur réel du commit) | |||
git commit -s | |||
* Cette commande ouvre un éditeur (vi, nano ou emacs selon la configuration de la variable EDITOR). Il faut alors entrer un bref descriptif du commit. '''Pour certains projets (dont Frankiz), les conventions de codage obligent les développeurs à écrire les descriptions en anglais.''' Il est un bon usage de s'adapter en conséquence, car un commit peut être refusé en production s'il est mal fait. | |||
* Mettre à jour la copie locale avec le dépôt distant (cela décale le nouveau commit à la fin). '''IL NE FAUT SURTOUT PAS FAIRE DE git pull OU DE git merge ICI''' | |||
git fetch | |||
git rebase origin/master | |||
* Transmettre les commits au dépôt d'origine | |||
git push | |||
La dernière commande provient du fait que git n'est pas centralisé : il n'envoie pas les modifications locales au dépôt parent spontanément. | |||
Ceci permet de faire quelques modifications locales puis de n'envoyer cela au reste des développeurs que lorsque les modifications sont stables et complètes, par exemple. | |||
== Structure interne == | |||
Git stocke les commits de manière très particulière : un commit correspond à peu près à une sauvegarde de l'état des fichiers, à un message, et à une référence vers le commit parent. | |||
Contrairemant à [[SVN]], il n'y a donc pas de notion de numéro de révision : chaque commit est identifié par une chaîne hexadécimale de 40 caractères (par exemple : ''04fd02e59b1bdc430c7a7dcc1ca9f4cbc2b04037'' ) | |||
Un ''tag'' est en fait un nom «lisible» donné à un ''commit'' ; une ''branche'' indique également le ''commit'' principal d'une branche. | |||
== Gérer les branches == | |||
=== Utilisation des branches === | |||
Une branche git est une ligne de versionning indépendante dans un dépôt. L'utilisation de branches permet à plusieurs personnes de travailler sur un même projet tout en gardant leur code temporairement séparé. | |||
Chaque projet contient par défaut une branche principale appelée '''main''' (anciennement ''master'') sur laquelle il est déconseillé de commit directement dans le cas d'un projet à plusieurs. | |||
Cas typique d'utilisation des branches : | |||
#Un contributeur au projet souhaite implémenter une fonctionnalité de son côté : il '''crée une branche''' à cet effet. | |||
#Pendant son travail, il '''commit ses changement exclusivement sur cette branche'''. | |||
#(Optionnel mais conseillé) Régulièrement pendant son travail, il '''[[Git#Mettre_à_jour_la_copie_de_travail | rebase sa branche]]''' lorsque des modifications sont ajoutées sur la branche principale, de manière à diminuer le nombre de conflits à régler lorsqu'il voudra enfin fusionner sa branche. | |||
#Une fois que son travail sur cette fonctionnalité est terminée, il '''merge''' (fusionne) sa branche avec la branche principale main pour ajouter sa contribution au projet, puis supprime sa branche de travail. | |||
=== Lister les branches === | |||
On peut voir la liste des branches accessibles avec : | |||
git branch -a | |||
* La ligne avec une étoile est la branche courante | |||
* Les lignes blanches sont les branches ''locales'' (elles suivent généralement une branche distante) | |||
* Les lignes rouges (si les couleurs sont activées) sont les branches distantes. | |||
=== Travailler sur une autre branche existante === | |||
Pour récupérer une autre branche, il faut d'abord l'ajouter localement : | |||
git checkout -b NomLocal origin/NomDistant | |||
Cela aura également pour effet de basculer sur la branche NomLocal. | |||
Les modifications que l'on avait effectuées sont bien entendu conservées. | |||
Une fois la branche ajoutée, on peut basculer de branche en branche à l'aide de : | |||
git checkout NomLocal | |||
=== Créer une nouvelle branche === | |||
Pour créer une nouvelle branche, utilisez : | |||
git checkout -b nom-de-la-nouvelle-branche | |||
ou | |||
git checkout -b nom-de-la-nouvelle-branche nom-de-la-branche-source | |||
=== Merge et supprimer une branche === | |||
On détaille ici les opérations pour merge une branche feature avec la branche principale main. Bien sûr, il est en théorie possible de merge n'importe quelles branches entre elles. | |||
git checkout main # Aller sur la branche principale | |||
git merge new-feature # Y ajouter les modification de la branche feature | |||
Il faut ensuite résoudre les conflits s'il y en a. Une fois que la fusion est achevée avec succès, on peut supprimer la branche de travail, qui n'est plus d'aucune utilité. Ci joint un [https://www.freecodecamp.org/news/how-to-fix-merge-conflicts-in-git/ une explication plus détaillée sur les merge conflict] et un [https://code.visualstudio.com/docs/sourcecontrol/overview#_merge-conflicts guide pour résoudre les conflits avec l'éditeur de VSCode] | |||
git branch -d new-feature # Supprimer la branche feature | |||
== Quel est l'état de ma copie de travail ? == | == Quel est l'état de ma copie de travail ? == | ||
Ligne 72 : | Ligne 246 : | ||
== Mettre à jour la copie de travail == | == Mettre à jour la copie de travail == | ||
=== git fetch && git rebase origin/master === | === git fetch && git rebase origin/master === | ||
Dans le cas général, vous travaillez sur la branche ''master'' et vous synchronisez votre projet sur un seul serveur. Si votre cas est plus compliqué, vous devez être suffisamment compétent pour vous débrouillez par vous-même. On disait donc... dans le cas simple, Git stocke en interne deux branches : ''master'' et ''origin/master''. Sur | Dans le cas général, vous travaillez sur la branche ''master'' (ou pour les projets créés récemment, la branche principale s'appelle ''main'' au lieu de ''master'') et vous synchronisez votre projet sur un seul serveur. Si votre cas est plus compliqué, vous devez être suffisamment compétent pour vous débrouillez par vous-même. On disait donc... dans le cas simple, Git stocke en interne deux branches : ''master'' et ''origin/master''. Sur Sigma, c'est un peu plus compliqué car il y a une branche de production, mais les développeurs n'utilisent que master. | ||
git branch -a | git branch -a | ||
* master | * master | ||
Ligne 93 : | Ligne 267 : | ||
# Indiquer à git de continuer : ''git rebase --continue'' | # Indiquer à git de continuer : ''git rebase --continue'' | ||
Ceci permet de transformer l'état suivant (les ''O'' sont les commits, ''A'' le moment où les deux versions ont commencé à diverger, ''B'' la version du dépôt, ''E'' la version locale, ''C'' et ''D'' des commits locaux | Remarque : git pull --rebase est un raccourci pour l'ensemble git fetch && git rebase. Attention cependant lors du travail sur plusieurs branches. | ||
Ceci permet de transformer l'état suivant (les ''O'' sont les commits, ''A'' le moment où les deux versions ont commencé à diverger, ''B'' la version du dépôt, ''E'' la version locale, ''C'' et ''D'' des commits locaux | |||
-C--D--E | -C--D--E | ||
Ligne 130 : | Ligne 306 : | ||
Une fois les modifications effectuées, on peut restorer la copie locale à l'état sauvegardé avec : | Une fois les modifications effectuées, on peut restorer la copie locale à l'état sauvegardé avec : | ||
git stash pop | git stash pop | ||
== Configuration globale == | == Configuration globale == | ||
Ligne 214 : | Ligne 326 : | ||
En enlevant ''--global'' dans toutes les commandes précédentes, on configure la copie locale. | En enlevant ''--global'' dans toutes les commandes précédentes, on configure la copie locale. | ||
== Utiliser le proxy de l'X avec Git == | === Exemple de configuration === | ||
Voici un exemple de fichier ~/.gitconfig (qui stocke la configuration ''--global'', le même format peut être utilisé dans les fichier ''$REPO/.git/config'' de chaque dépot) : | |||
[gc] | |||
auto = 1 | |||
[color] | |||
ui = true | |||
[color "diff"] | |||
whitespace = red reverse | |||
[core] | |||
whitespace=fix,-indent-with-non-tab,trailing-space,cr-at-eol | |||
[alias] | |||
st = status | |||
ci = commit | |||
br = branch | |||
co = checkout | |||
df = diff | |||
dc = diff --cached | |||
lg = log -p | |||
lo = log --graph --decorate --pretty=oneline --abbrev-commit -n 10 | |||
lol = log --graph --decorate --pretty=oneline --abbrev-commit | |||
lola = log --graph --decorate --pretty=oneline --abbrev-commit --all | |||
ls = ls-files | |||
# Show files ignored by git: | |||
ign = ls-files -o -i --exclude-standard | |||
amend = commit --amend -C HEAD | |||
[branch] | |||
autosetuprebase = always | |||
== Utiliser le proxy de l'X avec Git (Obsolète) == | |||
Si vous hébergez un projet sur [http://www.github.com GitHub], vous avez envie de dire à Git de se connecter à GitHub en SSH en passant par le proxy de l'X (qui est [http://kuzh.polytechnique.fr:8080 kuzh:8080]). Pour cela, il suffit de configurer le client SSH pour utiliser le proxy à chaque connexion vers github.com. Cela s'effecute par le fichier de configuration suivant dans /home/user/.ssh/config (adaptez avec votre dossier personnel) | Si vous hébergez un projet sur [http://www.github.com GitHub], vous avez envie de dire à Git de se connecter à GitHub en SSH en passant par le proxy de l'X (qui est [http://kuzh.polytechnique.fr:8080 kuzh:8080]). Pour cela, il suffit de configurer le client SSH pour utiliser le proxy à chaque connexion vers github.com. Cela s'effecute par le fichier de configuration suivant dans /home/user/.ssh/config (adaptez avec votre dossier personnel) | ||
Host github.com | Host github.com | ||
ProxyCommand socat - PROXY:kuzh.polytechnique.fr:%h:%p,proxyport=8080 | ProxyCommand socat - PROXY:kuzh.polytechnique.fr:%h:%p,proxyport=8080 | ||
Si vous souhaitez utiliser le protocole git://, il faut utiliser socat, et créer un exécutable avec dedans : | |||
#!/bin/sh | |||
exec socat STDIO PROXY:129.104.247.2:$1:$2 | |||
Puis mettre cet executable dans la variable core.gitproxy : | |||
git config --global core.gitproxy NOM_DU_FICHIER | |||
N'oubliez pas d'enlever cette variable pour utiliser git en-dehors de l'X. | |||
'''Si vous souhaitez uniquement cloner un dépôt GitHub''' dont vous n'êtes pas contributeur, il suffit d'utiliser le lien HTTPS en ligne de commande, en précisant le proxy. | |||
export https_proxy=http://kuzh.polytechnique.fr:8080 | |||
git clone https://github.com/BinetReseau/frankiz.git | |||
Finalement, si vous ne voulez pas vous connecter par ssh, mais vous souhaitez travailler normalement avec un depôt à l'extérieur de l'X, configurez git par le biais de ces commandes: | |||
git config --global http.proxy http://kuzh.polytechnique.fr:8080 | |||
git config --global https.proxy http://kuzh.polytechnique.fr:8080 | |||
Cela va effectuer les modifications correspondantes sur le fichier ~/.gitconfig. '''N'oubliez pas de les enlever dès que vous n'êtes plus connectés au réseau de l'école, avec''': | |||
git config --global --unset http.proxy http://kuzh.polytechnique.fr:8080 | |||
git config --global --unset https.proxy http://kuzh.polytechnique.fr:8080 | |||
Suivant si vous utilisez que http ou le https, vous pouvez modifier seulement la configuration pour le protocole correspondant. |
Version actuelle datée du 4 avril 2023 à 18:04
- Trucs et astuces du BR
- Diagnostiquer une panne réseau
- Configurer un routeur dans son casert
- Création d'un compte Sigma
- Comment récupérer mes données que j'ai effacées sur mon disque dur ?
- Comment utiliser Git ? (Pour les projets en équipe)
- Comment utiliser SSH ?
- Mettre en place SSH pour Gitlab
- Comprendre les différents identifiants à l'X
- Comment imprimer à l'X ?
Git est un système de contrôle de version est notamment utilisé pour travailler à plusieurs sur un projet informatique. Il permet notamment d'organiser les modifications effectuées par chacun de manière rigoureuse et sécurisée.
Si tu découvre git, ou que tu n'est pas encore très à l'aise avec, consulte ce tutoriel très bien expliqué et très complet. Pour un aide mémoire, va voir ce Handbook des différentes commandes de git ou ce site qui liste les commandes dans leur contexte.
La grande majorité des commandes manuelles expliquées sur cette page peuvent être utilisées plus facilement à travers l'interface graphique de certains IDE comme Visual Studio, VSCode, Pycharm, etc! Préférez maîtriser l'interface de votre éditeur plutôt que connaître par coeur les commandes à taper.
Obsolète : voir SVN
Accéder à l'aide
Avant toute chose, il est essentiel de savoir où trouver de l'aide, d'autant plus que l'aide de Git est très bien faite.
- Sur internet, il y a le wikiBR, les pages de manuel (sur Linux Die par exemple) et le Git Book
- En terminal, git help pour une liste des commandes, git help cmd ou git cmd --help pour l'aide complète de la commande cmd, ou encore simplement git cmd -h pour une aide courte sur la commande cmd
Installation
Windows
Téléchargez git sur le site officiel
Linux & MacOS
Git est généralement déjà installé sur ces systèmes. Sinon, installez le via un gestionnaire de paquets (homebrew, apt, pacman...) ou sur le site officiel.
Testez votre installation en exécutant la commande git
dans un terminal. Un texte d'aide devrait apparaître :
usage : git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>] [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path] [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare] [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>] [--config-env=<name>=<envvar>] <command> [<args>]
Dépôts
Git est complètement décentralisé. Cela signifie que chaque contributeur a sa propre copie locale de tout l'historique d'un projet, et effectue des modifications en local sur sa machine, avant de synchroniser ses changements avec le dépôt distant (hébergé sur gitlab.binets.fr, par exemple).
Un dépôt désigne ce qui stocke les données et l'historique d'un projet. Un dépôt distant (remote repository) désigne le dépôt hébergé sur le cloud (comme sur gitlab.binets.fr), tandis qu'un dépôt local (local repository) désigne un dépôt que vous avez téléchargé dans un dossier sur votre machine. Les données d'un dépôt local sont contenues dans un dossier caché .git
situé à la racine du projet.
Sur cette page, tous les examples sont tirés du Git de Sigma, mais voici d'autres dépôts bien utiles :
- GitHub
- GitLab, hébergé par le BR
- Polytechnique.org
Obsolète : CVS et SVN sont des systèmes de versionnement centralisés (i.e un serveur contient le dépôt, et chaque utilisateur effectue un checkout depuis ce dépôt).
Récupérer le code d'un projet existant
Il existe plusieurs possibilités pour télécharger un projet existant depuis des remote repositories (depuis gitlab.binets.fr ou Github.com, par exemple).
On utilise dans tous les cas la commande git clone
, qui permet de cloner (télécharger) un projet. Cette commande télécharge le projet dans un nouveau dossier créé dans le dossier où a été exécutée la commande. Cela crée un clone du dépôt d'origine (i.e une copie conforme), qui peut d'ailleurs servir de backup si le dépôt d'origine était perdu. Notre clone contient tout l'historique du dépôt depuis sa création, toutes les branches, etc. Cette première opération est très souple. On peut cloner des dépôt via SSH, HTTP, GIT, ou même en local le dépôt d'un autre utilisateur... L'adresse http ou ssh exacte d'un dépôt est généralement accessible depuis l'interface de Gitlab ou Github via un bouton clone.
Par exemple la commande suivante clone dans le dossier platal la branche core/master d'une version de Plat/al potientiellement modifiée par le vice-prez 2010 :
git clone /home/2010/fishilico/dev/platal/.git platal -b core/master
Sans authentification
Certains projets publics ne demandent pas d'authentification pour être clonés. Dans ce cas, vous n'avez pas besoin d'un compte avec les droits d'accès développeur. Vous pouvez simplement télécharger le projet avec le protocole http, mais vous ne pourrez pas ajouter vos modifications au dépôt distant.
git clone http://gitlab.binets.fr/br/td-formation-git.git
Avec un compte développeur (sans clé ssh)
Si vous disposez d'un compte avec les droits de développeur sur un projet donné, vous pouvez le cloner et lui ajouter vos modifications. L'authentification sans clé ssh n'est pas disponible sur Github.com, mais elle l'est sur les instances Gitlab (comme gitlab.binets.fr).
Pour exécuter les commandes git clone
(télécharger un projet) et git push
(ajouter les modifications locales au dépôt distant), git vous demandera vos identifiants et mot de passe.
On utilisera aussi le protocole http :
git clone http://gitlab.binets.fr/br/td-formation-git.git
Avec un compte développeur et une clé SSH
Vous pouvez utiliser une clé SSH pour ne pas avoir besoin de mettre un mot de passe à chaque fois.
Avec un compte muni d'une clé SSH simple, vous pouvez cloner les dépôts auxquels vous avez accès sans avoir à entrer vos identifiants avec la commande suivante :
git clone git@gitlab.binets.fr/br/td-formation-git.git
Créer un dépôt
Créer un dépôt localement
Contrairement à SVN où il faut installer un serveur subversion, créer un dépôt Git local est très rapide : dans le dossier que l'on souhaite versionner, il suffit de taper :
git init
Ou bien, dans le dossier parent où on souhaite créer un nouveau dépôt vide :
git init nom-du-dépot-à-créer
Et voilà, le dossier est versionné : on peut donc commencer à faire des modifications, des commits, etc. (bien entendu, on ne peut pas pusher ses commits, puisqu'il n'y a pas de serveur distant).
Cette particularité rend Git très efficace pour versionner un petit projet, un exercice de TD, etc. Il est ensuite possible de partager ce dépôt en le publiant vers un dépôt distant. Voir ce guide pour Github.
Créer un dépôt distant pour le cloner ensuite
Si vous souhaitez créer un nouveau projet commun, il est plus facile de créer un dépôt distant vide depuis les interfaces de Gitlab ou Github pour ensuite le cloner localement avec la commande git clone
.
Voir ce guide pour Gitlab.
Du bon usage de gitignore
Dans un projet, il est inutile de versionner (ie stocker et garder une trace des modifications successives dans le dépôt) les fichiers temporaires et les fichiers compilés (.exe
et .o
, .pyc
et .class
pour le c++, python et java par exemple) typiquement générés à partir d'un Makefile avec la commande make
.
Pour éviter de les versionner, il suffit d'utiliser un fichier .gitignore bien placé. Généralement, chaque projet a un tel fichier dans son dossier principal. Un fichier .gitignore placé à la racine du projet sera appliqué à l'ensemble du projet (c'est en général suffisant). Il est possible de placer des fichiers .gitignore dans des sous dossiers afin d'avoir un contrôle plus fin des fichiers versionnés.
Voici un exemple de fichier .gitignore d'un projet d'INF443 c++ :
# Ignore the build directory build/ # Ignore ALL c++ compiled .o files and shader .d files *.o *.d # Ignore ALL executables and debugger files *.exe *.pdb # Ignore visual studio cache directory .vs/ # Ignore imgui settings imgui.ini
Effectuer un commit
Un commit est une sauvegarde d'un ensemble de fichiers modifiés. Cela permet de suivre chronologiquement les modifications effectuées sur un projet. Par exemple, si l'ajout d'une fonctionnalité sur Sigma modifie les fichiers blah, blih et bloh, le commit associé regroupe les modifications de ces trois fichiers, et associe à cette modification une date, un auteur, et le message écrit par l'auteur pour décrire ce commit.
En général, les IDE comme Visual Studio, VSCode, Pycharm, etc proposent un moyen d'effectuer des commits directement depuis une interface graphique. Si vous souhaitez utiliser git à la main, utilisez les commandes suivantes.
Effectuer un commit manuellement
Voir la section Quel est l'état de ma copie de travail.
Pour effectuer un commit, il faut :
- Vérifier l'état de la copie de travail, pour ne commiter que ce qui est nécessaire
git status git diff
- Indiquer à Git quels fichiers feront partie du commit ; ceci permet de ne committer que les modifications de quelques fichiers
git add path/to/blih path/to/blah path/to/bloh
- Vérifier que l'on a ajouté les fichiers que l'on voulait :
git status
- Faire le commit (le -s ajoute une ligne Signed of by dans le message, pour pouvoir retrouver plus efficacement l'auteur réel du commit)
git commit -s
- Cette commande ouvre un éditeur (vi, nano ou emacs selon la configuration de la variable EDITOR). Il faut alors entrer un bref descriptif du commit. Pour certains projets (dont Frankiz), les conventions de codage obligent les développeurs à écrire les descriptions en anglais. Il est un bon usage de s'adapter en conséquence, car un commit peut être refusé en production s'il est mal fait.
- Mettre à jour la copie locale avec le dépôt distant (cela décale le nouveau commit à la fin). IL NE FAUT SURTOUT PAS FAIRE DE git pull OU DE git merge ICI
git fetch git rebase origin/master
- Transmettre les commits au dépôt d'origine
git push
La dernière commande provient du fait que git n'est pas centralisé : il n'envoie pas les modifications locales au dépôt parent spontanément.
Ceci permet de faire quelques modifications locales puis de n'envoyer cela au reste des développeurs que lorsque les modifications sont stables et complètes, par exemple.
Structure interne
Git stocke les commits de manière très particulière : un commit correspond à peu près à une sauvegarde de l'état des fichiers, à un message, et à une référence vers le commit parent. Contrairemant à SVN, il n'y a donc pas de notion de numéro de révision : chaque commit est identifié par une chaîne hexadécimale de 40 caractères (par exemple : 04fd02e59b1bdc430c7a7dcc1ca9f4cbc2b04037 )
Un tag est en fait un nom «lisible» donné à un commit ; une branche indique également le commit principal d'une branche.
Gérer les branches
Utilisation des branches
Une branche git est une ligne de versionning indépendante dans un dépôt. L'utilisation de branches permet à plusieurs personnes de travailler sur un même projet tout en gardant leur code temporairement séparé.
Chaque projet contient par défaut une branche principale appelée main (anciennement master) sur laquelle il est déconseillé de commit directement dans le cas d'un projet à plusieurs.
Cas typique d'utilisation des branches :
- Un contributeur au projet souhaite implémenter une fonctionnalité de son côté : il crée une branche à cet effet.
- Pendant son travail, il commit ses changement exclusivement sur cette branche.
- (Optionnel mais conseillé) Régulièrement pendant son travail, il rebase sa branche lorsque des modifications sont ajoutées sur la branche principale, de manière à diminuer le nombre de conflits à régler lorsqu'il voudra enfin fusionner sa branche.
- Une fois que son travail sur cette fonctionnalité est terminée, il merge (fusionne) sa branche avec la branche principale main pour ajouter sa contribution au projet, puis supprime sa branche de travail.
Lister les branches
On peut voir la liste des branches accessibles avec :
git branch -a
- La ligne avec une étoile est la branche courante
- Les lignes blanches sont les branches locales (elles suivent généralement une branche distante)
- Les lignes rouges (si les couleurs sont activées) sont les branches distantes.
Travailler sur une autre branche existante
Pour récupérer une autre branche, il faut d'abord l'ajouter localement :
git checkout -b NomLocal origin/NomDistant
Cela aura également pour effet de basculer sur la branche NomLocal. Les modifications que l'on avait effectuées sont bien entendu conservées.
Une fois la branche ajoutée, on peut basculer de branche en branche à l'aide de :
git checkout NomLocal
Créer une nouvelle branche
Pour créer une nouvelle branche, utilisez :
git checkout -b nom-de-la-nouvelle-branche
ou
git checkout -b nom-de-la-nouvelle-branche nom-de-la-branche-source
Merge et supprimer une branche
On détaille ici les opérations pour merge une branche feature avec la branche principale main. Bien sûr, il est en théorie possible de merge n'importe quelles branches entre elles.
git checkout main # Aller sur la branche principale git merge new-feature # Y ajouter les modification de la branche feature
Il faut ensuite résoudre les conflits s'il y en a. Une fois que la fusion est achevée avec succès, on peut supprimer la branche de travail, qui n'est plus d'aucune utilité. Ci joint un une explication plus détaillée sur les merge conflict et un guide pour résoudre les conflits avec l'éditeur de VSCode
git branch -d new-feature # Supprimer la branche feature
Quel est l'état de ma copie de travail ?
Ceci est la question que vous devez vous posez avant de reprendre après une pause votre travail sur un projet versionné. Il peut y avoir eu des changements sur le projet entre temps, des patchs mal faits en production, ... Pour cela, il y a trois commandes essentielles :
- Pour vérifier que le dépôt est correct, git status doit dire cela :
git status # On branch master nothing to commit (working directory clean)
- En cours de travail, la réponse ressemble plus à :
git status # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: un-fichier-random.blah # # Untracked files: # (use "git add <file>..." to include in what will be committed) # # un-fichier-chombier-ajouté.42 no changes added to commit (use "git add" and/or "git commit -a")
- Lire l'historique est bien pour savoir quel est le dernier commit
git log commit 2a424aae1e746fb5f33de3b3bc3e8a31ee25c684 Author: Nicolas Iooss <fishilico@eleves.polytechnique.fr> Date: Fri Mar 9 00:27:35 2012 +0100
- Voir les différences entre la version sur le dépôt distant et celle de travail
git diff
De plus, après avoir téléchargé les derniers commits avec git fetch, il est possible d'obtenir le message suivant :
git status # On branch master # Your branch is behind 'origin/master' by 42 commits, and can be fast-forwarded.
Cela signifie que la copie locale a 42 commits de retard sur le dépôt distant, mais qu'un git rebase origin/master suffit pour mettre à jour la copie locale.
Réinitialiser le dépôt
Pour restaurer un fichier, il suffit de le checkout à partir de l'index. En français, cela signifie que lorsque vous faites une modification sur un fichier, vous pouvez effacer les modifications et revenir la dernière version enregistrée dans l'index Git avec la commande :
git checkout -- chemin/vers/mon/fichier.blih
Pour réinitialiser l'index dans l'état indiqué par une branche (comme master par exemple) sans modifier les fichier, il suffit d'écrire :
git reset master
Si cela ne marche pas car des fichiers seront modifiés ou effacés, on peut forcer la main à Git, mais alors il faut être prêt à subir les conséqences que cela implique (perte des modifications non commitées)
git reset --hard master
Mettre à jour la copie de travail
git fetch && git rebase origin/master
Dans le cas général, vous travaillez sur la branche master (ou pour les projets créés récemment, la branche principale s'appelle main au lieu de master) et vous synchronisez votre projet sur un seul serveur. Si votre cas est plus compliqué, vous devez être suffisamment compétent pour vous débrouillez par vous-même. On disait donc... dans le cas simple, Git stocke en interne deux branches : master et origin/master. Sur Sigma, c'est un peu plus compliqué car il y a une branche de production, mais les développeurs n'utilisent que master.
git branch -a * master remotes/origin/HEAD -> origin/master remotes/origin/f579e1971a66623b2948bf0e20c2e23481022b41 remotes/origin/fkz2 remotes/origin/kangz-h4ck3s remotes/origin/master remotes/origin/prod
Pour mettre à jour sa copie de travail, il faut donc commencer par mettre à jour les branches distantes, avec au choix l'une des commandes suivantes
git fetch git fetch origin
Ensuite, il faut appliquer les éventuelles modifications locales à la suite de celles effectuées sur le dépôt, c'est le rebase.
git rebase origin/master
Git essaiera alors d'appliquer les commits locaux successivement, en indiquant chaque fois qu'il y a un problème (conflit ou fichier supprimé). En cas de problème, il faut
- Résoudre le problème (les fichiers avec des conflits apparaîssent comme Changed but not updated dans git status)
- Ajouter les fichiers (git add)
- Indiquer à git de continuer : git rebase --continue
Remarque : git pull --rebase est un raccourci pour l'ensemble git fetch && git rebase. Attention cependant lors du travail sur plusieurs branches.
Ceci permet de transformer l'état suivant (les O sont les commits, A le moment où les deux versions ont commencé à diverger, B la version du dépôt, E la version locale, C et D des commits locaux
-C--D--E / -O--A--O--B
En l'état plus propre :
-O--A--O--B--C'--D'--E'
Avec C, D et E convertis en C', D' et E' : ils ont été modifiés pour être des modifications relatives à B au lieu de A.
Pourquoi il ne faut JAMAIS utiliser git pull
Certains développeurs utilisent la commande git pull pour mettre à jour leur dépôt. Cette pratique est justifiée lorsque la copie de travail était propre (sans commit en attente de push entre autres), mais sinon, cela peut avoir des conséquences très graves et sales. En effet, git pull' est assimilé à la succession de commandes suivantes :
git fetch origin && git merge origin/master
Le problème est le merge. En reprenant les schémas précédents, cela transforme l'état suivant :
-C--D--E / -O--A--O--B
en :
-C--D--E / \ -O--A--O--B----M
où M est le commit de fusion de branches. Cela est très moche et à éviter absolument. Si vous vous retrouvez dans cette suituation (pour vérifier : git log), vous pouvez toujours tenter un git rebase origin/master qui peut fonctionner si le merge était trivial (sans conflit). Sinon, un git reset --hard origin/master s'impose pour assurer votre salut.
Sauvegarder des modifications locales (git stash)
Avant de faire un merge particulièrement délicat, ou si l'on doit résoudre un bug alors que l'on a pas mal de modifications non commitées en cours, il est parfois utile de sauvegarder l'état courant de la copie de travail.
Pour cela, il faut utiliser avant un changement (avec git rebase par exemple) :
git stash
Une fois les modifications effectuées, on peut restorer la copie locale à l'état sauvegardé avec :
git stash pop
Configuration globale
Si vous avez déjà commitez, vous aurez certainement remarqué qu'il faut utiliser git config pour configurer vos informations personnelles. Ainsi, les deux premières commandes que tout utilisateur doit taper avant de faire un commit sont :
git config --global user.name "Prénom Nom de famille" git config --global user.email "prenom.nom.promo@polytechnique.org"
Ensuite, si vous aimez les couleurs, vous avez envie de taper cette commande :
git config --global color.ui auto
Enfin, si vous en avez assez des projets qui ne mettent pas les fichiers temporaires dans le gitignore, vous pouvez configurer un fichier gitignore global. Si votre /home/user/.gitignore_global ressemble à
*~ *.swp *.tmp
il suffit de taper :
git config --global core.excludesfile /home/user/.gitignore_global
Tout cela permet de gérer la configuration globale, visible par
git config --global -l
En enlevant --global dans toutes les commandes précédentes, on configure la copie locale.
Exemple de configuration
Voici un exemple de fichier ~/.gitconfig (qui stocke la configuration --global, le même format peut être utilisé dans les fichier $REPO/.git/config de chaque dépot) :
[gc] auto = 1 [color] ui = true [color "diff"] whitespace = red reverse [core] whitespace=fix,-indent-with-non-tab,trailing-space,cr-at-eol [alias] st = status ci = commit br = branch co = checkout df = diff dc = diff --cached lg = log -p lo = log --graph --decorate --pretty=oneline --abbrev-commit -n 10 lol = log --graph --decorate --pretty=oneline --abbrev-commit lola = log --graph --decorate --pretty=oneline --abbrev-commit --all ls = ls-files # Show files ignored by git: ign = ls-files -o -i --exclude-standard amend = commit --amend -C HEAD [branch] autosetuprebase = always
Utiliser le proxy de l'X avec Git (Obsolète)
Si vous hébergez un projet sur GitHub, vous avez envie de dire à Git de se connecter à GitHub en SSH en passant par le proxy de l'X (qui est kuzh:8080). Pour cela, il suffit de configurer le client SSH pour utiliser le proxy à chaque connexion vers github.com. Cela s'effecute par le fichier de configuration suivant dans /home/user/.ssh/config (adaptez avec votre dossier personnel)
Host github.com ProxyCommand socat - PROXY:kuzh.polytechnique.fr:%h:%p,proxyport=8080
Si vous souhaitez utiliser le protocole git://, il faut utiliser socat, et créer un exécutable avec dedans :
#!/bin/sh exec socat STDIO PROXY:129.104.247.2:$1:$2
Puis mettre cet executable dans la variable core.gitproxy :
git config --global core.gitproxy NOM_DU_FICHIER
N'oubliez pas d'enlever cette variable pour utiliser git en-dehors de l'X.
Si vous souhaitez uniquement cloner un dépôt GitHub dont vous n'êtes pas contributeur, il suffit d'utiliser le lien HTTPS en ligne de commande, en précisant le proxy.
export https_proxy=http://kuzh.polytechnique.fr:8080 git clone https://github.com/BinetReseau/frankiz.git
Finalement, si vous ne voulez pas vous connecter par ssh, mais vous souhaitez travailler normalement avec un depôt à l'extérieur de l'X, configurez git par le biais de ces commandes:
git config --global http.proxy http://kuzh.polytechnique.fr:8080 git config --global https.proxy http://kuzh.polytechnique.fr:8080
Cela va effectuer les modifications correspondantes sur le fichier ~/.gitconfig. N'oubliez pas de les enlever dès que vous n'êtes plus connectés au réseau de l'école, avec:
git config --global --unset http.proxy http://kuzh.polytechnique.fr:8080 git config --global --unset https.proxy http://kuzh.polytechnique.fr:8080
Suivant si vous utilisez que http ou le https, vous pouvez modifier seulement la configuration pour le protocole correspondant.