Git
Chapters ▾ 2nd Edition

3.5 Ramificaciones en Git - Ramas Remotas

Ramas Remotas

Las ramas remotas son referencias al estado de las ramas en tus repositorios remotos. Son ramas locales que no puedes mover; se mueven automáticamente cuando estableces comunicaciones en la red. Las ramas remotas funcionan como marcadores, para recordarte en qué estado se encontraban tus repositorios remotos la última vez que conectaste con ellos.

Suelen referenciarse como (remoto)/(rama). Por ejemplo, si quieres saber cómo estaba la rama master en el remoto origin, puedes revisar la rama origin/master. O si estás trabajando en un problema con un compañero y este envía (push) una rama iss53, tú tendrás tu propia rama de trabajo local iss53; pero la rama en el servidor apuntará a la última confirmación (commit) en la rama origin/iss53.

Esto puede ser un tanto confuso, pero intentemos aclararlo con un ejemplo. Supongamos que tienes un servidor Git en tu red, en git.ourcompany.com. Si haces un clon desde ahí, Git automáticamente lo denominará origin, traerá (pull) sus datos, creará un apuntador hacia donde esté en ese momento su rama master y denominará la copia local origin/master. Git te proporcionará también tu propia rama master, apuntando al mismo lugar que la rama master de origin; de manera que tengas donde trabajar.

Note
“origin” no es especial

Así como la rama “master” no tiene ningún significado especial en Git, tampoco lo tiene “origin”. “master” es un nombre muy usado solo porque es el nombre por defecto que Git le da a la rama inicial cuando ejecutas git init. De la misma manera, “origin” es el nombre por defecto que Git le da a un remoto cuando ejecutas git clone. Si en cambio ejecutases git clone -o booyah, tendrías una rama booyah/master como rama remota por defecto.

Servidor y repositorio local luego de ser clonado.
Figure 30. Servidor y repositorio local luego de ser clonado

Si haces algún trabajo en tu rama master local, y al mismo tiempo, alguien más lleva (push) su trabajo al servidor git.ourcompany.com, actualizando la rama master de allí, te encontrarás con que ambos registros avanzan de forma diferente. Además, mientras no tengas contacto con el servidor, tu apuntador a tu rama origin/master no se moverá.

El trabajo remoto y el local pueden diverger.
Figure 31. El trabajo remoto y el local pueden diverger

Para sincronizarte, puedes utilizar el comando git fetch origin. Este comando localiza en qué servidor está el origen (en este caso git.ourcompany.com), recupera cualquier dato presente allí que tú no tengas, y actualiza tu base de datos local, moviendo tu rama origin/master para que apunte a la posición más reciente.

`git fetch` actualiza las referencias de tu remoto.
Figure 32. git fetch actualiza las referencias de tu remoto

Para ilustrar mejor el caso de tener múltiples servidores y cómo van las ramas remotas para esos proyectos remotos, supongamos que tienes otro servidor Git; utilizado por uno de tus equipos sprint, solamente para desarrollo. Este servidor se encuentra en git.team1.ourcompany.com. Puedes incluirlo como una nueva referencia remota a tu proyecto actual, mediante el comando git remote add, tal y como vimos en Fundamentos de Git. Puedes denominar teamone a este remoto al asignarle este nombre a la URL.

Añadiendo otro servidor como remoto.
Figure 33. Añadiendo otro servidor como remoto

Ahora, puedes usar el comando git fetch teamone para recuperar todo el contenido del remoto teamone que tú no tenias. Debido a que dicho servidor es un subconjunto de los datos del servidor origin que tienes actualmente, Git no recupera (fetch) ningún dato; simplemente prepara una rama remota llamada teamone/master para apuntar a la confirmación (commit) que teamone tiene en su rama master.

Seguimiento de la rama remota a través de `teamone/master`.
Figure 34. Seguimiento de la rama remota a través de teamone/master

Publicar

Cuando quieres compartir una rama con el resto del mundo, debes llevarla (push) a un remoto donde tengas permisos de escritura. Tus ramas locales no se sincronizan automáticamente con los remotos en los que escribes, sino que tienes que enviar (push) expresamente las ramas que desees compartir. De esta forma, puedes usar ramas privadas para el trabajo que no deseas compartir, llevando a un remoto tan solo aquellas partes que deseas aportar a los demás.

Si tienes una rama llamada serverfix, con la que vas a trabajar en colaboración; puedes llevarla al remoto de la misma forma que llevaste tu primera rama. Con el comando git push (remoto) (rama):

$ git push origin serverfix
Counting objects: 24, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (24/24), 1.91 KiB | 0 bytes/s, done.
Total 24 (delta 2), reused 0 (delta 0)
To https://github.com/schacon/simplegit
 * [new branch]      serverfix -> serverfix

Esto es un atajo. Git expande automáticamente el nombre de rama serverfix a refs/heads/serverfix:refs/heads/serverfix, que significa: “coge mi rama local serverfix y actualiza con ella la rama serverfix del remoto”. Volveremos más tarde sobre el tema de refs/heads/, viéndolo en detalle en Los entresijos internos de Git; por ahora, puedes ignorarlo. También puedes hacer git push origin serverfix:serverfix, que hace lo mismo; es decir: “coge mi serverfix y hazlo el serverfix remoto”. Puedes utilizar este último formato para llevar una rama local a una rama remota con un nombre distinto. Si no quieres que se llame serverfix en el remoto, puedes lanzar, por ejemplo, git push origin serverfix:awesomebranch; para llevar tu rama serverfix local a la rama awesomebranch en el proyecto remoto.

Note
No escribas tu contraseña todo el tiempo

Si utilizas una dirección URL con HTTPS para enviar datos, el servidor Git te preguntará tu usuario y contraseña para autenticarte. Por defecto, te pedirá esta información a través del terminal, para determinar si estás autorizado a enviar datos.

Si no quieres escribir tu contraseña cada vez que haces un envío, puedes establecer un “cache de credenciales”. La manera más sencilla de hacerlo es estableciéndolo en memoria por unos minutos, lo que puedes lograr fácilmente al ejecutar git config --global credential.helper cache

Para más información sobre las distintas opciones de cache de credenciales, véase Almacenamiento de credenciales.

La próxima vez que tus colaboradores recuperen desde el servidor, obtendrán bajo la rama remota origin/serverfix una referencia a donde esté la versión de serverfix en el servidor:

$ git fetch origin
remote: Counting objects: 7, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://github.com/schacon/simplegit
 * [new branch]      serverfix    -> origin/serverfix

Es importante destacar que cuando recuperas (fetch) nuevas ramas remotas, no obtienes automáticamente una copia local editable de las mismas. En otras palabras, en este caso, no tienes una nueva rama serverfix. Sino que únicamente tienes un puntero no editable a origin/serverfix.

Para integrar (merge) esto en tu rama de trabajo actual, puedes usar el comando git merge origin/serverfix. Y si quieres tener tu propia rama serverfix para trabajar, puedes crearla directamente basandote en la rama remota:

$ git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

Esto sí te da una rama local donde puedes trabajar, que comienza donde origin/serverfix estaba en ese momento.

Hacer Seguimiento a las Ramas

Al activar (checkout) una rama local a partir de una rama remota, se crea automáticamente lo que podríamos denominar una “rama de seguimiento” (tracking branch). Las ramas de seguimiento son ramas locales que tienen una relación directa con alguna rama remota. Si estás en una rama de seguimiento y tecleas el comando git pull, Git sabe de cuál servidor recuperar (fetch) y fusionar (merge) datos.

Cuando clonas un repositorio, este suele crear automáticamente una rama master que hace seguimiento de origin/master. Sin embargo, puedes preparar otras ramas de seguimiento si deseas tener unas que sigan ramas de otros remotos o no seguir la rama master. El ejemplo más simple es el que acabas de ver al lanzar el comando git checkout -b [rama] [nombreremoto]/[rama]. Esta operación es tan común que git ofrece el parámetro --track:

$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

Para preparar una rama local con un nombre distinto a la del remoto, puedes utilizar la primera versión con un nombre de rama local diferente:

$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch serverfix from origin.
Switched to a new branch 'sf'

Así, tu rama local sf traerá (pull) información automáticamente desde origin/serverfix.

Si ya tienes una rama local y quieres asignarla a una rama remota que acabas de traerte, o quieres cambiar la rama a la que le haces seguimiento, puedes usar en cualquier momento las opciones -u o --set-upstream-to del comando git branch.

$ git branch -u origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Note
Atajo al upstream

Cuando tienes asignada una rama de seguimiento, puedes hacer referencia a ella mediante @{upstream} o mediante el atajo @{u}. De esta manera, si estás en la rama master y esta sigue a la rama origin/master, puedes hacer algo como git merge @{u} en vez de git merge origin/master.

Si quieres ver las ramas de seguimiento que tienes asignado, puedes usar la opción -vv con git branch. Esto listará tus ramas locales con más información, incluyendo a qué sigue cada rama y si tu rama local está por delante, por detrás o ambas.

$ git branch -vv
  iss53     7e424c3 [origin/iss53: ahead 2] forgot the brackets
  master    1ae2a45 [origin/master] deploying index fix
* serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] this should do it
  testing   5ea463a trying something new

Aquí podemos ver que nuestra rama iss53 sigue origin/iss53 y está “ahead” (delante) por dos, es decir, que tenemos dos confirmaciones locales que no han sido enviadas al servidor. También podemos ver que nuestra rama master sigue a origin/master y está actualizada. Luego podemos ver que nuestra rama serverfix sigue la rama server-fix-good de nuestro servidor teamone y que está tres cambios por delante (ahead) y uno por detrás (behind), lo que significa que existe una confirmación en el servidor que no hemos fusionado y que tenemos tres confirmaciones locales que no hemos enviado. Por último, podemos ver que nuestra rama testing no sigue a ninguna rama remota.

Es importante destacar que estos números se refieren a la última vez que trajiste (fetch) datos de cada servidor. Este comando no se comunica con los servidores, solo te indica lo que sabe de ellos localmente. Si quieres tener los cambios por delante y por detrás actualizados, debes traértelos (fetch) de cada servidor antes de ejecutar el comando. Puedes hacerlo de esta manera: $ git fetch --all; git branch -vv

Traer y Fusionar

A pesar de que el comando git fetch trae todos los cambios del servidor que no tienes, este no modifica tu directorio de trabajo. Simplemente obtendrá los datos y dejará que tú mismo los fusiones. Sin embargo, existe un comando llamado git pull, el cuál básicamente hace git fetch seguido por git merge en la mayoría de los casos. Si tienes una rama de seguimiento configurada como vimos en la última sección, bien sea asignándola explícitamente o creándola mediante los comandos clone o checkout, git pull identificará a qué servidor y rama remota sigue tu rama actual, traerá los datos de dicho servidor e intentará fusionar dicha rama remota.

Normalmente es mejor usar los comandos fetch y merge de manera explícita pues la magia de git pull puede resultar confusa.

Eliminar Ramas Remotas

Imagina que ya has terminado con una rama remota, es decir, tanto tú como tus colaboradores habéis completado una determinada funcionalidad y la habéis incorporado (merge) a la rama master en el remoto (o donde quiera que tengáis la rama de código estable). Puedes borrar la rama remota utilizando la opción --delete de git push. Por ejemplo, si quieres borrar la rama serverfix del servidor, puedes utilizar:

$ git push origin --delete serverfix
To https://github.com/schacon/simplegit
 - [deleted]         serverfix

Básicamente lo que hace es eliminar el apuntador del servidor. El servidor Git suele mantener los datos por un tiempo hasta que el recolector de basura se ejecute, de manera que si la has borrado accidentalmente, suele ser fácil recuperarla.