El comando git fetch descarga commits, archivos y referencias de un repositorio remoto a tu repositorio local. Esta acción la llevas a cabo cuando quieres ver en qué han estado trabajando los demás. Es similar al comando svn update porque te permite ver cómo ha progresado el historial central, pero no te obliga a fusionar los cambios en tu repositorio. Git aísla el contenido recuperado del contenido local existente sin tener ningún tipo de repercusión sobre el desarrollo local de tu trabajo. El contenido recuperado debe extraerse específicamente con el comando git checkout. Esto permite que la recuperación constituya una forma segura de revisar commits antes de integrarlos en tu repositorio local.

Para descargar contenido de un repositorio remoto, los comandos git pull y git fetch están disponibles para realizar esta tarea. Puedes considerar git fetch como la versión segura de los dos comandos. Este comando descarga el contenido remoto, pero no actualiza el estado de trabajo del repositorio local, por lo que tu trabajo actual no se verá afectado. git pull constituye una alternativa más agresiva, ya que descarga el contenido remoto a la rama local activa e inmediatamente ejecuta git merge para crear un commit fusionado con el nuevo contenido remoto. Si tienes cambios pendientes en curso, esta acción provocará conflictos e iniciará el flujo de resolución de conflictos de fusión.

Funcionamiento de git fetch con las ramas remotas

Para entender mejor como funciona git fetch, hablaremos de cómo organiza y almacena Git los commits. Entre bastidores, en el directorio ./.git/objects del repositorio, Git almacena todos los commits locales y remotos. Git mantiene los commits de ramas locales y remotas separados de forma diferenciada mediante las referencias de las ramas. Las referencias de las ramas locales se almacenan en el directorio ./.git/refs/heads/. La ejecución del git branch genera una lista de referencia de las ramas locales. A continuación encontramos un ejemplo del resultado del comando git branch con algunos nombres de ramas de demostración.

git branch
master
feature1
debug2

Al examinar el contenido del directorio /.git/refs/heads/ se obtiene un resultado similar.

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

Las ramas remotas son como las ramas locales, excepto por el hecho de están asociadas a commits de repositorios ajenos. Las ramas remotas tienen como prefijo el repositorio remoto al que pertenecen para que no las confundas con ramas locales. Al igual que para las ramas locales, Git también cuenta con referencias para las ramas remotas. Las referencias de las ramas remotas viven en el directorio ./.git/refs/remotes/. El siguiente ejemplo de fragmento de código muestra las ramas que puedes ver después de recuperar un repositorio remoto, que se llama remote-repo:

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

Este resultado muestra las ramas locales que hemos examinado anteriormente, solo que ahora las muestra con el prefijo origin/. Además, también vemos las ramas remotas con el prefijo remote-repo. Puedes extraer una rama remota como una local, pero hará que tu estado pase a ser HEAD desasociado (al igual que si estuvieras extrayendo un commit antiguo). Puedes considerarlas ramas de solo lectura. Para ver tus ramas remotas, solo tienes que colocar la marca -r en el comando git branch.

Puedes analizar ramas remotas con los comandos habituales git checkout y git log. Si apruebas los cambios que contiene una rama remota, puedes fusionarla con la rama local mediante un comando git merge normal. Al contrario que SVN, la sincronización de tu repositorio local con un repositorio remoto es en realidad un proceso de dos pasos: recuperar y, después, fusionar. El comando git pull es un atajo cómodo para realizar este proceso.

Opciones y comandos git fetch

git fetch <remote>

Recupera todas las ramas del repositorio. También descarga todos los commits y archivos requeridos del otro repositorio.

git fetch <remote> <branch>

Realiza la misma acción que el comando anterior, pero solo recupera la rama especificada.

git fetch --all

Una función potente que recupera todos los repositorios remotos registrados y sus ramas:

git fetch --dry-run

La opción --dry-run ejecutará una demo del comando. Genera ejemplos de acciones que realizará durante la recuperación, pero no los aplica.

Ejemplos de git fetch

Aplicar git fetch a una rama remota

El siguiente ejemplo es una demostración de cómo recuperar una rama remota y actualizar tu estado en curso actual con los contenidos remotos. En este ejemplo, asumiremos que hay un repositorio central de origen a partir del que se ha clonado el repositorio local mediante el comando git clone. También asumiremos que hay un repositorio remoto adicional llamado coworkers_repo que contiene una rama feature_branch que configuraremos y recuperaremos. Una vez explicado esto, continuemos con el ejemplo.

En primer lugar, tenemos que configurar el repositorio remoto mediante el comando git remote.

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

Hemos creado una referencia para el repositorio coworkers_repo mediante la URL del repositorio. Ahora pasaremos el nombre remoto por git fetch para descargar el contenido.

git fetch coworkers feature_branch
fetching coworkers/feature_branch

Ahora tenemos el contenido de la rama coworkers/feature_branch descargados localmente y tenemos que integrarlo en nuestra copia local en funcionamiento. Empezaremos este proceso usando el comando git checkout to para extraer la rama remota que acabamos de descargar.

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>

El resultado de esta operación de extracción indica que nos encontramos en estado de HEAD desasociado. Es algo que ya esperábamos y quiere decir que nuestra referencia HEAD apunta a una referencia que no forma parte de la secuencia de nuestro historial local. Dado que la referencia HEAD apunta a la referencia de la rama coworkers/feature_branch, podemos crear una nueva rama local desde dicha referencia. El resultado de la referencia "HEAD desasociado" muestra cómo realizar esta acción mediante el comando git checkout:

git checkout -b local_feature_branch

Aquí hemos creado una nueva rama local denominada local_feature_branch que actualiza la referencia HEAD para que apunte al contenido remoto más reciente y podamos continuar con el desarrollo a partir de este punto.

Sincronización del origen con git fetch

En el siguiente ejemplo se describe el flujo de trabajo habitual de sincronización del repositorio local con la rama maestra del repositorio central.

git fetch origin

Así se muestran las ramas que se han descargado:

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

The commits from these new remote branches are shown as squares instead of circles in the diagram below. As you can see, git fetch gives you access to the entire branch structure of another repository.

Para ver qué commits se han añadido a la rama maestra de nivel superior, puedes ejecutar un comando git log con el filtro origin/master:

git log --oneline master..origin/master

Para aprobar los cambios y fusionarlos con tu rama maestra local, usa estos comandos:

git checkout master
git log origin/master

A continuación podemos usar el comando git merge origin/master:

git merge origin/master

Las ramas origin/master y master ahora apuntan al mismo commit y están sincronizadas con los desarrollos de nivel superior.

Resumen de git fetch

En resumen, git fetch es un comando principal que se usa para descargar contenidos desde un repositorio remoto. git fetch se usa en combinación con git remote, git branch, git checkout y git reset para actualizar un repositorio local al estado de un remoto. El comando git fetch es una pieza fundamental de los flujos de trabajo colaborativos de git. git fetch presenta un comportamiento similar a git pull, aunque git fetch se puede considerar una versión más segura y menos destructiva.