La commande git fetch télécharge des commits, des fichiers et des refs d'un dépôt distant vers votre dépôt local. Le fetch est l'opération à réaliser lorsque vous souhaitez voir ce sur quoi tout le monde travaille. Il fonctionne de manière similaire à la commande svn update dans la mesure où il vous permet de suivre l'évolution de l'historique centralisé, mais il ne vous oblige pas à faire réellement un merge des changements dans votre dépôt. Git isole le contenu « fetché » du contenu local existant. Cela n'a absolument aucun effet sur vos tâches de développement en local. Vous devez explicitement faire un checkout du contenu « fetché » à l'aide de la commande git checkout. Le fetch est donc un moyen sûr de réviser des commits avant de les intégrer à votre dépôt local.

Lorsque vous téléchargez du contenu depuis un dépôt distant, vous pouvez utiliser les commandes git pull et git fetch pour accomplir cette tâche. Vous pouvez considérer git fetch comme la variante la plus sûre des deux. Celle-ci va télécharger le contenu distant, mais pas mettre à jour l'état courant de votre dépôt local. Ainsi, votre travail en cours ne sera pas altéré. git pull constitue l'alternative la plus agressive, puisque cette commande télécharge le contenu distant pour la branche locale active et exécute immédiatement git merge afin de créer un commit de merge pour le nouveau contenu distant. Si vous avez des changements en attente, cette opération va entraîner des conflits et déclencher le flux de résolution des conflits de merge.

Fonctionnement de git fetch avec des branches distantes

Pour mieux comprendre comment fonctionne git fetch, voyons comment Git organise et stocke les commits. En coulisse, dans le répertoire ./.git/objects du dépôt, Git stocke tous les commits, locaux comme distants. Il conserve les commits des branches locales et distantes bien séparés à l'aide de refs de branche. Les refs des branches locales sont stockées dans le répertoire ./.git/refs/heads/. Si vous exécutez la commande git branch, la liste des refs de branche locale sera générée. Voici un exemple de sortie git branch avec quelques noms de branches de démo.

git branch
master
feature1
debug2

Si vous examinez le contenu du répertoire /.git/refs/heads/, vous obtiendrez un résultat similaire.

ls ./.git/refs/heads/
master
feature1
debug2

Les branches distantes sont exactement comme les branches locales, si ce n'est qu'elles sont mappées aux commits du dépôt de quelqu'un d'autre. Les branches distantes sont préfixées par le dépôt distant auquel elles appartiennent afin de ne pas les mélanger avec les branches locales. À l'instar des branches locales, Git dispose également de refs pour les branches distantes. Les refs de branche distante résident dans le répertoire ./.git/refs/remotes/. L'exemple de snippet de code ci-dessous présente les branches que vous pourriez voir après avoir fait un fetch dans un dépôt distant portant le nom pratique de remote-repo :

git branch -r
# origin/master
# origin/feature1
# origin/debug2
# remote-repo/master
# remote-repo/other-feature

Cette sortie affiche les branches locales que nous avions examinées précédemment. Elles apparaissent cependant avec le préfixe origin/. Par ailleurs, nous voyons maintenant les branches distantes avec le préfixe remote-repo. Vous pouvez faire un checkout d'une branche distante comme vous le feriez pour une branche locale, mais vous passez alors à l'état HEAD détaché (comme pour le checkout d'un ancien commit). Vous pouvez alors considérer vos branches distantes comme des branches en lecture seule. Pour les afficher, transmettez simplement le flag -r à la commande git branch.

Vous pouvez vérifier ces branches avec les commandes git checkout et git log que vous connaissez bien. Si vous approuvez les changements dans une branche distante, vous pouvez les merger dans une branche locale avec la commande git merge normale. Ainsi, contrairement à SVN, la synchronisation de votre dépôt local avec un dépôt distant est un processus en deux étapes : premièrement le fetch, puis le merge. La commande git pull est un raccourci pratique pour appliquer ce processus.

Commandes et options git fetch

git fetch <remote>

Fetche toutes les branches du dépôt. Télécharge également tous les commits et fichiers nécessaires depuis l'autre dépôt.

git fetch <remote> <branch>

Comme la commande ci-dessus, mais fetche uniquement la branche spécifiée.

git fetch --all

Une commande puissante qui fait un fetch de tous les dépôts distants enregistrés et de leurs branches :

git fetch --dry-run

L'option --dry-run exécute la commande en mode Démo. Elle va générer des exemples d'actions qui seront entreprises durant le fetch sans les appliquer.

Exemples de commandes git fetch

Faire un git fetch d'une branche distante

L'exemple suivant va vous démontrer comment faire un fetch d'une branche distante et mettre à jour votre copie de travail locale avec les contenus distants. Supposons qu'il existe un dépôt origin centralisé à partir duquel le dépôt local a été cloné à l'aide de la commande git clone. Supposons également l'existence d'un autre dépôt distant appelé « coworkers_repo » qui contient une branche « feature_branch » que nous allons configurer et dont nous allons faire un fetch. En gardant ces hypothèses à l'esprit, poursuivons avec notre exemple.

Tout d'abord, nous devons configurer le dépôt distant à l'aide de la commande git remote.

git remote add coworkers_repo git@bitbucket.org:coworker/coworkers_repo.git

Dans cet exemple, nous avons créé une référence au dépôt des coéquipiers à l'aide de l'URL de dépôt. Nous allons maintenant transmettre le nom de ce dépôt à git fetch pour télécharger son contenu.

git fetch coworkers feature_branch
fetching coworkers/feature_branch

Nous possédons maintenant en local le contenu de la branche « coworkers/feature_branch ». Nous allons devoir l'intégrer à notre copie de travail locale. Démarrons ce processus en utilisant la commande git checkout pour faire un checkout de la branche distante que nous venons de télécharger.

git checkout coworkers/feature_branch
Note: checking out coworkers/feature_branch'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

git checkout -b <new-branch-name>

La sortie de cette opération de checkout indique que nous sommes à un état HEAD détaché. C'était prévisible. Cela signifie que notre ref HEAD pointe vers une ref qui n'est pas à la suite de notre historique local. Puisque HEAD pointe vers la ref de la branche « coworkers/feature_branch », nous pouvons créer une branche locale à partir de cette ref. La sortie « HEAD détaché » nous montre comment procéder à l'aide de la commande git checkout :

git checkout -b local_feature_branch

Dans cet exemple, nous avons créé une branche locale appelée « local_feature_branch ».HEAD est mis à jour de sorte à pointer vers le contenu distant le plus récent. Nous pouvons alors poursuivre le développement à partir de ce point.

Synchroniser la branche origin avec git fetch

Cet exemple illustre le workflow typique pour la synchronisation de votre dépôt local avec la branche master du dépôt centralisé.

git fetch origin

La commande suivante affiche les branches téléchargées :

a1e8fb5..45e66a4 master -> origin/master
a1e8fb5..9e8ab1c develop -> origin/develop
* [new branch] some-feature -> origin/some-feature

Les commits de ces nouvelles branches locales sont représentés sous forme de carrés au lieu de cercles dans le schéma ci-dessous. Comme vous pouvez le constater, git fetch vous permet d'accéder à la structure de branche complète d'un autre dépôt.

Pour savoir quels sont les commits qui ont été ajoutés à la branche master amont, vous pouvez exécuter une commande git log en utilisant origin/master en tant que filtre :  

git log --oneline master..origin/master

Pour approuver les changements et les merger dans votre branche master locale avec les commandes suivantes :

git checkout master
git log origin/master

Ensuite, nous pouvons utiliser git merge origin/master :

git merge origin/master

Les branches origin/master et master pointent maintenant vers le même commit, et vous êtes synchronisé avec les développements en amont.

Récapitulatif sur la commande git fetch

En résumé, git fetch est une commande primaire qui permet de télécharger du contenu depuis un dépôt distant. git fetch est utilisée en association avec git remote, git branch, git checkout et git reset pour mettre à jour un dépôt local de sorte qu'il corresponde à l'état du dépôt distant. La commande git fetch est un élément essentiel des workflows Git collaboratifs. git fetch affiche un comportement similaire à git pull. Cependant, git fetch peut être considérée comme une variante plus sûre et non destructrice.