Git: how to salir de esta, repositorios remotos

narkha

Claudio Sánchez

Posted on September 26, 2021

Git: how to salir de esta, repositorios remotos

How to

Introducción

Un repositorio de código, dentro del contexto de los sistema de control de versiones, es un sistema para almacenar código y metadatos, como pueden ser el histórico de los archivos.

Git es un sistema de control de versiones distribuido, en el que cada repositorio guarda una copia completa del código y los metadatos, pudiendo funcionar de manera independiente; en contraposición están los sistemas centralizados, en los que existe un único repositorio de código y los clientes se comunican con él para obtener o subir código, pero en ningún caso tienen una copia de los metadatos.

Se denomina "flujo de trabajo" al cómo colaboran entre sí los repositorios de un sistema de control de versiones distribuido. El más común de ellos es el "flujo de trabajo centralizado", en el que hay un repositorio central o de referencia, por ejemplo un repositorio en Bitbucket o GitHub; los desarrolladores se clonan ese repositorio en su local, obteniendo así un repositorio privado sobre el que pueden trabajar; hacen cambios en su repositorio local, como por ejemplo desarrollador una nueva feature, y envian esos cambios al repositorio central; y actualizan el repositorio privado con los cambios que otros desarrolladores han enviado al repositorio central.

flujo trabajo centralizado

El tener un "sistema de control de versiones distribuido" y acabar usando un "flujo de trabajo centralizado" puede sonar contradictorio o exagerado ¿Por qué complicarse? ¿Por qué no usar simplemente un sistema de control de versiones centralizado como SVN?
En un sistema de control de versiones centralizado cualquier operación, desde hacer un nuevo commit a consultar el log, implica comunicaciones con el servidor donde está alojado el repositorio, lo cual es mucho más lento que consultando una copia local como en Git; además de la lentitud, una perdida de conexión con el servidor central implica no poder ejecutar ningún comando; y la gestión de conflictos es más complicada, ya que habrá que resolverlos sobre cambios que todavía no se han podido commitear.
Personalmente he trabajado con SVN y Git y me quedo sin ninguna duda con Git, pero como todo la elección dependerá de gustos y necesidades.

Adicionalmente, un sistema de control de versiones distribuido permite evolucionar el flujo de trabajo dependiendo de como evolucione o crezca el proyecto; por poner un ejemplo, en el kernel de Linux usan el "flujo de trabajo dictador y tenientes".

Tras hacer git clone <url repositorio> en el repositorio recién clonado habrá dos conjuntos de ramas: ramas locales y ramas remotas,

En un GUI En consola
ramas remota en IDE ramas remotas en consola

Las ramas remotas son referencias a ramas que existen en el repositorio remoto que se ha clonado, al que por defecto se le da el nombre de origin, y que se actualizan con git fetch si ha habido cambios en el repositorio remoto, o cuando este acepta los cambios que se le proponen al hacer git push.
Un ejemplo de rama remota sería origin/master, y haría referencia a la rama master en el repositorio remoto con nombre origin.
Una rama remota puede ser el "upstream" de una rama local, pudiéndose entender "lo que hay rio arriba" como que la rama local mira o sigue a la rama remota: cuando se hace git pull se intenta actualizar la rama local con lo que haya en su upstream; cuando se hace git push se intenta actualizar el upstream con los contenidos de la rama local. Y en ambos casos digo intentar porqué si la rama local ha divergido respecto del upstream, sera necesarias algunas acciones que se irán viendo a lo largo del post.

A la hora de visualizarlo, se puede hacer igual que con las ramas locales, solo que ahora habrá unas cuantas ramas más.
Con un GUI

Arbol ramas en IDE

O por consola

$ git log --graph --format='%C(auto)%h %s%n%C(auto)%d%n' --all
Enter fullscreen mode Exit fullscreen mode

Arbol ramas en consola

Las ramas de los repositorios remotos añaden un nuevo nivel de complejidad a la gestión de las ramas: hay ramas como pippin-merry que han adelantado a su upstream origin/pippin-merry; ramas como aragorn-legolas-gimli que se han quedado atrás respecto a su upstream origin/pippin-merry; y ramas como master que han divergido respecto a su upstream origin/master; también habrá ramas remotas que no serán seguidas por ninguna rama local o ramas locales que todavía no se han subido al repositorio remoto y que no tengan su equivalente en origin.

Y para terminar la introducción, algo muy importante:


🚨 No hay que editar nada que ya este en el repositorio remoto y que este siendo usado por otros desarrolladores, ya que se puede liar parda.


Imagina que:

  1. Mortadelo hace git push a master con un commit que tiene un bug.
  2. Filemón se actualiza su rama con master, obteniendo así el commit con el bug.
  3. Mortadelo se da cuenta de su error, y sin avisar a nadie: borra el commit con el bug de master; intenta hacer git push a master, pero no puede por no se que error extraño; así que hace git push -f.
  4. Filemón integra su rama en master, intenta subirla, y o bien vuelve a añadir a master el commit que Mortadelo había borrado, o bien se encuentra con conflictos y tiene que perder un buen rato en resolverlos.

El tener que usar git push -f (o borrar la rama remota y volver a crearla con commits diferentes) es algo que debe hacer saltar todas las alarmas, y hacer pensar muy mucho si realmente es necesario o hay otras opciones.

Dicho esto, si la rama es tuya, y estas seguro de que nadie más la ha usado ni ha usado ninguno de sus commits, es licito modificar los commits que hagan falta y usar git push -f, porque a todos nos ha pasado que queramos cambiar algo que hemos subido por error.

git push -f es una herramienta más de Git, y si sigue hay después de tantos años por algo será, pero hay que usarla con mucho cuidado.

Trastear con repositorios remotos

Personalmente, como más aprendo sobre las cosas es trasteando con ellas, y cómo más aprendí sobre los repositorios remotos de Git fue creándome un repositorio en local y clonándolo.
En un minuto es posibles tener un área de pruebas donde ver como afectan los comando git push y git pull al repositorio remoto, crear situaciones para probar las cosas, probar cosas antes de aplicarlas al repositorio remoto de verdad, etc.
También se puede crear un repositorio privado en GitHub o similares, pero me parece mucho más rápido y ágil probar en local.

El proceso sería más o menos así

# Creo una carpeta donde poner los repositorios para las pruebas.
~$ mkdir -p sandbox/remotes 
~$ cd sandbox/remotes/

# Creo una carpeta donde creare el repositorio remoto.
~/sandbox/remotes$ mkdir origin
~/sandbox/remotes$ cd origin/
# Inicio el repositorio.
~/sandbox/remotes/origin$ git init
        Inicializado repositorio Git vacío en ~/sandbox/remotes/origin/.git/

# Le añado algún commit.
~/sandbox/remotes/origin$ echo "hola git" > README.md
~/sandbox/remotes/origin$ git add .
~/sandbox/remotes/origin$ git commit -am "creado archivo index.html"
        [master (commit-raíz) 246ceaf] creado archivo README.md
         1 file changed, 1 insertion(+)
         create mode 100644 README.md
# Me voy a otra rama para evitar los problemas del tipo
# "remote: error: Por defecto, actualizar la rama actual 
# en un repositorio no vacío".
# https://stackoverflow.com/a/2933656/1587302
~/sandbox/remotes/origin$ git checkout -b no-editar

# Voy atras.
~/sandbox/remotes/origin$ cd ..

# Clono el repositorio origin en la carpeta local.
~/sandbox/remotes$ git clone origin local 
        Clonando en 'local'...
        hecho.

# Entro en él y veo que tengo un clone de "origin".
~/sandbox/remotes$ cd local/
~/sandbox/remotes$ git checkout master
        Rama 'master' configurada para hacer seguimiento a la rama remota 'master' de 'origin'.
        Cambiado a nueva rama 'master'
~/sandbox/remotes/local$ git status
        En la rama master
        Tu rama está actualizada con 'origin/master'.

        nada para hacer commit, el árbol de trabajo está limpio

~/sandbox/remotes/local$ cat README.md 
        hola git
Enter fullscreen mode Exit fullscreen mode

Problemas al subir una rama

Hago push pero lo cambios no se suben; al intentar hacer push sale un error; hago push pero no pasa nada; etc

Hay varios motivos por los que git push puede dar error:

  • No se tienen permisos para escribir es un repositorio. Por poner un ejemplo, es posible clonarse cualquier repositorio público de GitHub, pero al hacer git push se obtendrá un error como este remote: Permission to 30-seconds/30-seconds-of-code.git denied to Pepito.
  • No se tienen permisos para escribir en una rama. Es posible restringir los permisos de escritura a ramas sensibles como master, de tal forma que sólo ciertos usuarios puedan escribir sobre ellas o solo se pueda escribir sobre ellas al darle a Merge en las "Pull request" o "Merge request".
  • Todavía no existe la rama remota.
  • La rama local está detrás o no está al día con la rama remota
  • La rama local ha divergido respecto a la rama remota y no es posible actualizarla.

Para los dos primeros casos habrá que consultar al administrador del repositorio.

En el tercer caso, git push da error porque se le pide actualizar algo que no existe, y la solución es tan simple como crearla siguiendo las instrucciones que da Git en el mensaje de error.
La siguientes veces que se ejecute git push ya no se obtendrá el error, porque ya sabrá que debe actualizar.
Aunque esto es algo que solo suelen experimentar los usuarios de consola, porque muchos muchos GUI por debajo controlan este caso y crean la rama remata si no existe.

# Intento hacer push de una rama que no existe y obtengo un error.
$ git push 
        fatal: La rama actual nueva-feature no tiene una rama upstream.
        Para realizar un push de la rama actual y configurar el remoto como upstream, use

            git push --set-upstream origin nueva-feature

# Así que la creo.
$ git push --set-upstream origin HEAD
        Total 0 (delta 0), reusado 0 (delta 0)
        To ~/sandbox/remotes/origin
         * [new branch]      HEAD -> nueva-feature
        Rama 'nueva-feature' configurada para hacer seguimiento a la rama remota 'nueva-feature' de 'origin'.

$ git status
        En la rama nueva-feature
        Tu rama está actualizada con 'origin/nueva-feature'.

        nada para hacer commit, el árbol de trabajo está limpio
Enter fullscreen mode Exit fullscreen mode

En el ejemplo se utiliza git push --set-upstream origin HEAD para crear la rama en lugar del comando sugerido por Git git push --set-upstream origin nueva-feature.
Es un pequeño atajo no tener que pensar en el nombre de la rama a la hora de crearla.

Respecto a los dos últimos casos, si git push da error, es importante hacer git fetch para actualizar las ramas remotas, porque puede pasar que todo parezca estar en orden al ejecutar git status, pero que no lo este porque otro desarrollador haya hecho cambios en el repositorio remoto desde la última vez se actualizo el repositorio local, y las referencias a las ramas remotas no estén actualizadas.

Si la rama local está detrás de la rama remota no hay cambios que subir, y aunque el mensaje puede ser un poco agresivo es normal que no pase nada.
Si se actualiza la rama seguirá sin pasar nada, pero el mensaje no será tan agresivo.

# Hago push y obtengo un mensaje un poco agresivo
$ git push 
        To ~/sandbox/remotes/origin
         ! [rejected]        master -> master (non-fast-forward)
        error: falló el push de algunas referencias a '~/sandbox/remotes/origin'
        ayuda: Actualizaciones fueron rechazadas porque la punta de tu rama actual está
        ayuda: detrás de su contraparte remota. Integra los cambios remotos (es decir
        ayuda: 'git pull ...') antes de hacer push de nuevo.
        ayuda: Mira 'Note about fast-forwards' en 'git push --help' para más detalles.

# Compruebo el estado y veo que mi rama se ha quedado detras
$ git status
        En la rama master
        Tu rama está detrás de 'origin/master' por 1 commit, y puede ser avanzada rápido.
          (usa "git pull" para actualizar tu rama local)

        nada para hacer commit, el árbol de trabajo está limpio

# Actualizo la rama
$ git pull
        Actualizando 246ceaf..47be068
        Fast-forward
         index.html | 1 +
         1 file changed, 1 insertion(+)

# Y el git push segirá sin hacer nada, aunque el mensaje 
# no es tan agresivo
$ git push 
        Everything up-to-date
Enter fullscreen mode Exit fullscreen mode

Y si la rama remota y la rama local han evolucionado de manera distinta, es que han divergido.

# Compruebo el estado de la rama y veo que está por delante 
# de la rama remota, así que debería poder hacer push.
$ git status
        En la rama master
        Tu rama está adelantada a 'origin/master' por 1 commit.
          (usa "git push" para publicar tus commits locales)

        nada para hacer commit, el árbol de trabajo está limpio

# Pero falla.
$ git push 
        To sandbox/remotes/origin
         ! [rejected]        master -> master (fetch first)
        error: falló el push de algunas referencias a 'sandbox/remotes/origin'
        ayuda: Actualizaciones fueron rechazadas porque el remoto contiene trabajo que
        ayuda: no existe localmente. Esto es causado usualmente por otro repositorio 
        ayuda: realizando push a la misma ref. Quizás quiera integrar primero los cambios
        ayuda: remotos (ej. 'git pull ...') antes de volver a hacer push.
        ayuda: Vea 'Notes about fast-forwards0 en git push --help' para detalles.

# Actualizo las ramas remotas y veo que la rama remota 
# se ha actualizado.
$ git fetch 
        remote: Enumerando objetos: 5, listo.
        remote: Contando objetos: 100% (5/5), listo.
        remote: Total 3 (delta 0), reusado 0 (delta 0)
        Desempaquetando objetos: 100% (3/3), 277 bytes | 277.00 KiB/s, listo.
        Desde sandbox/remotes/origin
           246ceaf..792a7bf  master     -> origin/master

# Intento obtener información más concreta y veo que 
# las ramas han divergido.
$ git status
        En la rama master
        Tu rama y 'origin/master' han divergido,
        y tienen 1 y 1 commits diferentes cada una respectivamente.
          (usa "git pull" para fusionar la rama remota en la tuya)

        nada para hacer commit, el árbol de trabajo está limpio
Enter fullscreen mode Exit fullscreen mode

rama divergente

En el ejemplo se puede ver que la rama local master y la rama remota origin/master partieron de commit creado archivo index.html y que en ambas se han hecho commits.

git push solo funciona cuando los commits que se suben salen del último commit de la rama remota, es decir, se produce un fast forward, en caso contrario falla y habrá que actualizar la rama local con el upstream.

La forma de salir del paso depende de como se integren las ramas en el proyecto:

  • Si se usan rebases, el comando sería git rebase <upstream>, por ejemplo git rebase origin/master si por ejemplo mi el upstream es origin/master.
  • Si se usan merges git pull .

Una vez integrada, y si no se da la casualidad de que justo se ha vuelto a actualizar la rama remota entre medias, se podrá hacer git push.

Modificar algo en el repositorio remoto

He visto después de hacer push que el mensaje de un commit tiene una errata; he mergeado la rama que no era y he hecho push; he subido algo por error; me acabo de dar cuenta de que he subido un bug; etc.

Como se vio en la introducción


🚨 No hay que editar nada que ya este en el repositorio remoto y que este siendo usado por otros desarrolladores, ya que se puede liar parda.


Pero ¿quién no la ha cometido errores alguna vez?

Como también se dijo en la introducción, si la rama es tuya, y estas seguro de que nadie más la ha usado ni ha usado ninguno de sus commits, es licito modificar los commits que hagan falta y usar git push -f

$ git commit -am "Hañado titúlo"
        [mi-rama 13c9acf] Hañado titúlo
         1 file changed, 1 insertion(+)

$ git push 
        Enumerando objetos: 5, listo.
        Contando objetos: 100% (5/5), listo.
        Compresión delta usando hasta 12 hilos
        Comprimiendo objetos: 100% (2/2), listo.
        Escribiendo objetos: 100% (3/3), 314 bytes | 314.00 KiB/s, listo.
        Total 3 (delta 0), reusado 0 (delta 0)
        To sandbox/remotes/origin
           207ba5a..13c9acf  mi-rama -> mi-rama

# Me doy cuenta de que he metido algunos errores en el mensaje 
# y los corrijo.
$ git amend -m "Añado título"
        [mi-rama ec27a36] Añado título
         Date: Sat May 8 21:05:27 2021 +0200
         1 file changed, 1 insertion(+)

# Pero el push falla porque he modificado un commit que 
# ya estaba en el repositorio remoto.
$ git push 
        To sandbox/remotes/origin
         ! [rejected]        mi-rama -> mi-rama (non-fast-forward)
        error: falló el push de algunas referencias a 'sandbox/remotes/origin'
        ayuda: Actualizaciones fueron rechazadas porque la punta de tu rama actual está
        ayuda: detrás de su contraparte remota. Integra los cambios remotos (es decir
        ayuda: 'git pull ...') antes de hacer push de nuevo.
        ayuda: Mira 'Note about fast-forwards' en 'git push --help' para más detalles.

# Compruebo el estado.
$ git status
        En la rama mi-rama
        Tu rama y 'origin/mi-rama' han divergido,
        y tienen 1 y 1 commits diferentes cada una respectivamente.
          (usa "git pull" para fusionar la rama remota en la tuya)

        nada para hacer commit, el árbol de trabajo está limpio

# Estando muy muy seguro de que no va a afectar a otras personas.
$ git push -f
        Enumerando objetos: 5, listo.
        Contando objetos: 100% (5/5), listo.
        Compresión delta usando hasta 12 hilos
        Comprimiendo objetos: 100% (2/2), listo.
        Escribiendo objetos: 100% (3/3), 318 bytes | 318.00 KiB/s, listo.
        Total 3 (delta 0), reusado 0 (delta 0)
        To ~/sandbox/remotes/origin
         + 13c9acf...ec27a36 mi-rama -> mi-rama (forced update)

$ git status
        En la rama mi-rama
        Tu rama está actualizada con 'origin/mi-rama'.

        nada para hacer commit, el árbol de trabajo está limpio
Enter fullscreen mode Exit fullscreen mode

Si el git push se hizo a una rama compartida, las acciones a tomar dependen de la situación:

  • Si los commits son para corregir una errata en un mensaje, lo mejor es dejarlo correr, porque arreglarlo no merece la pena.
  • Si es algo que hay que deshacer, lo más correcto sería usar git revert para revertir un commit individual o un merge commit, probar bien los cambios, y después hacer git push.
  • Si es algo como un bug, siempre se pueden hacer commits para corregirlo.

Aunque lo más correcto no siempre es lo más cómodo, para que mentir.
Si se ha hecho git push a una rama compartida con otros desarrolladores y ninguno ha usado ninguno de los commits que se han subido (no han hecho git pull en la rama comprometida, ni git pull origin <rama>, ni git cherry-pick de ninguno de los commits) se puede:

  1. Avisar al resto de desarrolladores de que se ha subido algo por error y que hasta nuevo aviso no hagan ni git pull en la rama, git pull origin <rama> ni git cherry-pick de los commits recién subidos.
  2. Hacer lo cambios que se tengan que hacer y hacer git push -f.
  3. Pedir al resto de desarrolladores que se actualicen las ramas remotas con git fetch y decir que ya se puede trabajar con normalidad.

¿Y si algún otro desarrollador ya ha hecho uso de alguno de los commits subidos?
Siempre es posible seguir los pasos de arriba y que el resto de desarrolladores rehagan parte del trabajo, pero igual es demasiado trastorno y no merece la pena.

¿Y si se ha modificado algún commit en local y se decide que lo mejor es dar marcha atrás porque no se puede hacer git push -f?

Se puede volver a lo que había antes de modificar el commit siguiendo los mismos pasos que para recuperar una rama borrada por error.

Git pull, ese comando problemático

"git pull" cada vez hace una cosa distinta; después de hacer "git pull" la aplicación ya no funciona.

git pull sirve para actualizar una rama local con una rama del repositorio remoto.
Por debajo primero hace git fetch , actualizando todas las ramas del repositorio remoto, y después a git merge <rama-remota> .
Ciertamente es muy cómodo, pero hay que tener todas las consideraciones que al mergear una rama (pueden surgir conflictos, hay revisar que todo sigue funcionando después de un merge commit, etc) y alguna más.

La forma más verbosa de invocar a git pull sería git pull origin <rama>, que por debajo vendría a hacer:

  • git fetch origin , que actualizaría todas las ramas remotas (las ramas origin/<rama> que se mencionaban en la introducción).
  • git merge origin/<rama> para mergear la rama remota origin/<rama> en la rama local.

Es una forma muy útil para por ejemplo actualizar la rama local en la que se está desarrollando una nueva feature con la última versión de master en el repositorio remoto.

$ git status
        En la rama mi-feature
        nada para hacer commit, el árbol de trabajo está limpio

# Actualizo mi-feature con la rama master del repositorio remoto.
$ git pull origin master 

        # Internamente hace git fetch.
        remote: Enumerando objetos: 5, listo.
        remote: Contando objetos: 100% (5/5), listo.
        remote: Comprimiendo objetos: 100% (2/2), listo.
        remote: Total 3 (delta 0), reusado 0 (delta 0)
        Desempaquetando objetos: 100% (3/3), 291 bytes | 291.00 KiB/s, listo.

        # La rama master ha cambiado en el repositorio remoto
        # así que actualiza origin/master.
        Desde ~/sandbox/remotes/origin
         * branch            master     -> FETCH_HEAD
           792a7bf..1a16ce3  master     -> origin/master

        # Hace el merge.
        Merge made by the 'recursive' strategy.
         index.html | 2 ++
         1 file changed, 2 insertions(+)

# Reviso la el úlitmo commit para ver que ha sido un merge.
$ git log -1
        commit 73365ef70d893c3b3b9680e0676bda0c78c36505 (HEAD -> mi-feature)
        Merge: 504b167 1a16ce3

            Merge branch 'master' of ~/sandbox/remotes/origin into mi-feature
Enter fullscreen mode Exit fullscreen mode

Otra forma es git pull a secas, bastante útil para actualizar la rama local con el upstream.
Por debajo vendría a hacer:

  • git fetch <remoto>, donde <remoto> sería el repositorio remoto del upstream (si el upstream fuese origin/master haría git fetch origin).
  • git merge <upstream>, para mergear el upstream en la rama local (si el upstream fuese origin/master haría git merge master). Si la rama no tuviese upstream indicaría como añadirlo.
# Hago git status y veo que no estoy siguiendo 
# a ninguna rama remota.
$ git status
        En la rama mi-feature
        nada para hacer commit, el árbol de trabajo está limpio

# git pull hace internamente el git fetch, y luego falla, 
# porque la rama actual no sigue a ninguna rama remota
$ git pull
        remote: Enumerando objetos: 5, listo.
        remote: Contando objetos: 100% (5/5), listo.
        remote: Comprimiendo objetos: 100% (2/2), listo.
        remote: Total 3 (delta 0), reusado 0 (delta 0)
        Desempaquetando objetos: 100% (3/3), 290 bytes | 290.00 KiB/s, listo.
        Desde ~/sandbox/remotes/origin
           792a7bf..01d5c54  master     -> origin/master
        No hay información de rastreo para la rama actual.
        Por favor especifica a qué rama quieres fusionar.
        Ver git-pull(1) para detalles.

            git pull <remoto> <rama>

        Si deseas configurar el rastreo de información para esta rama, puedes hacerlo con:

            git branch --set-upstream-to=origin/<rama> mi-feature

# Cambio a otra rama que si sigue a una rama remota.
$ git checkout master 
        Cambiado a rama 'master'
        Tu rama está detrás de 'origin/master' por 1 commit, y puede ser avanzada rápido.
          (usa "git pull" para actualizar tu rama local)

# Hago git pull.
# Internamente hace el git fecth, pero como no hay cambios
# en el repositorio remoto no imprime nada.
$ git pull
        Actualizando 792a7bf..01d5c54
        Fast-forward
         index.html | 1 +
         1 file changed, 1 insertion(+)

Enter fullscreen mode Exit fullscreen mode

Todas las opciones que se pueden aplicar a git merge se pueden aplicar también a git pull.

Si por ejemplo se está en la rama master y se quiere actualizar con el repositorio remoto puede ser útil ejecutar git pull --ff-only ; haciéndolo así git pull fallaría si las ramas han divergido, evitando así que la rama master se diferente a la de otros desarrolladores.

Se puede ejecutar git pull --no-ff --no-commit origin hotfix para que si el merge resultase en un merge commit tener la posibilidad de revisar los cambios antes de completar el commit, por si hubiese alguna incompatibilidad entre las dos ramas.

Renombrar una rama

Corregir un texto incorrecto, se copio la clave del issute tracker que no era, etc.

Las acciones para renombrar ramas solo renombran ramas locales, no actúan sobre los upstream; como tal no existe la opción de renombrar una rama en un repositorio remoto, aunque si se puede borrar la rama con el nombre antiguo y crear una rama con el nombre nuevo. Adicionalmente habría que actualizar el upstream de la rama, porque no se actualiza solo.

# Hago un git status y veo que estoy en la rama dovolop 
# y que estoy siguiendo a la rama remota origin/dovolop.
$ git status
        En la rama dovolop
        Tu rama está actualizada con 'origin/dovolop'.

        nada para hacer commit, el árbol de trabajo está limpio

# Otra opción para ver esto es mirarlo es 
$ git branch -vv -a
        * dovolop                d63cc7b [origin/dovolop] crear hoja de estilos home.css
          master                 d63cc7b [origin/master] crear hoja de estilos home.css
          remotes/origin/dovolop d63cc7b crear hoja de estilos home.css
          remotes/origin/master  d63cc7b crear hoja de estilos home.css

# El nombre debería ser develop, así que renombro la rama.
$ git branch -m develop

# Si verifico el estado veo que he renombrado la rama local, 
# pero no la remota, y que mi rama local todavía sigue 
# a origin/dovolop.
$ git branch -a -vv
        * develop                d63cc7b [origin/dovolop] crear hoja de estilos home.css
          master                 d63cc7b [origin/master] crear hoja de estilos home.css
          remotes/origin/dovolop d63cc7b crear hoja de estilos home.css
          remotes/origin/master  d63cc7b crear hoja de estilos home.css

# "Actualizo" la rama remota borrando la vieja y creando la nueva.
$ git push origin :dovolop develop
        Total 0 (delta 0), reusado 0 (delta 0)
        To ~/sandbox/git
         - [deleted]         dovolop
         * [new branch]      develop -> develop

# Si consulto el estado veo que la rama remota se ha renombrado
# y que mi rama local sigue a una rama "desaparecida" o "gone".
$ git branch -a -vv
        * develop                d63cc7b [origin/dovolop: desaparecido] crear hoja de estilos home.css
          master                 d63cc7b [origin/master] crear hoja de estilos home.css
          remotes/origin/develop d63cc7b crear hoja de estilos home.css
          remotes/origin/master  d63cc7b crear hoja de estilos home.css

# Así que tengo que actualizar el upstream para que siga 
# a la rama renombrada.
$ git push --set-upstream origin develop 
        Rama 'develop' configurada para hacer seguimiento a la rama remota 'develop' de 'origin'.
        Everything up-to-date

# Y ya está todo en orden.
$ git branch -a -vv
        * develop                d63cc7b [origin/develop] crear hoja de estilos home.css
          master                 d63cc7b [origin/master] crear hoja de estilos home.css
          remotes/origin/develop d63cc7b crear hoja de estilos home.css
          remotes/origin/master  d63cc7b crear hoja de estilos home.css
Enter fullscreen mode Exit fullscreen mode

🚨 Los comandos anteriores pueden afectar a otros desarrolladores.


Si el Filemón tenía una rama siguiendo a dovolop y Mortadelo la "renombra" en el repositorio remoto, pueden ocurrir varias cosas: que Filemón no sea capaz de actualizarse con los commits que haga Mortadelo, ya que ha perdido la referencia la rama remota; o que Filemón haga nuevos commits y al subirlos al repositorio remoto cree una nueva sin darse cuenta.

# Mortadelo comprueba el estado de las ramas.
$ git branch -vv -a
        * dovolop                d63cc7b [origin/dovolop] crear hoja de estilos home.css
          master                 d63cc7b [origin/master] crear hoja de estilos home.css
          remotes/origin/dovolop d63cc7b crear hoja de estilos home.css
          remotes/origin/master  d63cc7b crear hoja de estilos home.css

# Hace un fetch y no le presta mucha antención, porque 
# no es extraño que se creen o borren ramas.
$ git fetch 
        Desde ~/sandbox/git
         - [eliminado]       (nada)     -> origin/dovolop
         * [nueva rama]      develop    -> origin/develop

# Si Filemón comprobase el estado de la rama vería algo raro, 
# pero supongamos que no lo hace.
$ git branch -vv -a
        * dovolop                d63cc7b [origin/dovolop: desaparecido] crear hoja de estilos home.css
          feature                d63cc7b [origin/feature: desaparecido] crear hoja de estilos home.css
          master                 d63cc7b [origin/master] crear hoja de estilos home.css
          remotes/origin/develop d63cc7b crear hoja de estilos home.css
          remotes/origin/master  d63cc7b crear hoja de estilos home.css

# Hace algunos cambios y los commitea.
$ git commit -am "algunos cambios"
        [dovolop 190e822] algunos cambios
         1 file changed, 1 insertion(+)

# Sube el nuevo commit al repositorio remoto...
# y ve que se ha creado una nueva rama, aunque el esperaba 
# que se hubiese actualizado la rama dovolop
$ git push 
        Enumerando objetos: 5, listo.
        Contando objetos: 100% (5/5), listo.
        Compresión delta usando hasta 12 hilos
        Comprimiendo objetos: 100% (3/3), listo.
        Escribiendo objetos: 100% (3/3), 305 bytes | 305.00 KiB/s, listo.
        Total 3 (delta 1), reusado 0 (delta 0)
        To ~/sandbox/git
         * [new branch]      dovolop -> dovolop

# Y sin darse cuenta ha recreado la rama que mi Mortadelo 
# con tanto esfuerzo renombro.
$ git branch -a -vv
        * dovolop                190e822 [origin/dovolop] algunos cambios
          master                 d63cc7b [origin/master] crear hoja de estilos home.css
          remotes/origin/develop d63cc7b crear hoja de estilos home.css
          remotes/origin/dovolop 190e822 algunos cambios
          remotes/origin/master  d63cc7b crear hoja de estilos home.css
Enter fullscreen mode Exit fullscreen mode

Mantener el entorno limpio: cuando las ramas no dejan ver el bosque

"git branch" y tengo muchas ramas que ya no se usan; "git branch -a " muestra ramas del repositorio remoto que ya fueron borradas; "git status" dice que el upstream ha desaparecido o "is gone".

En repositorios muy activos y con muchos desarrolladores es fácil que git branch y git brach -a devuelvan decenas de resultados, de los cuales la inmensa mayoría serán ramas que no se han usado en meses.
Git nunca borra nada a menos que se le diga explícitamente, lo cual esta bien porque nunca se pierde información, pero tiene la contra de que se puede acabar con información que ya no es relevante y que dificulta encontrar lo que se esta buscando, como cuando se tiene el escritorio tan lleno de archivos, carpetas y enlaces directos que lleva un rato encontrar algo que no uses todos los días.

Ramas del repositorio remoto que ya no existen

Las más fáciles de limpiar son las ramas remotas que ya no existen en el repositorio remoto, es decir aquellas que cuando:

  1. Pin subió la rama feature/tiger al repositorio remeto.
  2. Pon hizo un git fetch, el cual creo la rama origin/feature/tiger. Si ejecutase hiciese git branch -a mostraría, entre otras, origin/feature/tiger
  3. Pin borro feature/tiger.
  4. Pon hizo git fetch, que no cambio nada. Si ejecutase hiciese git branch -a seguiría mostrando origin/feature/tiger.

Se le puede indicar a Git que borre esas ramas llamando a git fetch o a git pull con la opción --prune, para indicar que tiene que podar las ramas que ya no existen.
Si se usa un GUI, puede que ya haga el prune automáticamente, o puede que tenga una opción para configurarlo.

Es posible configurar Git para que por defecto haga prune , ahorrando así tener que usar la opción --prune en cada llamada, para ello, añadir lo siguiente al archivo ~/.gitconfig

[fetch]
        prune = true
Enter fullscreen mode Exit fullscreen mode

Un ejemplo paso a paso

### Pin publica la rama feature/tiger.

# Pon hace un fetch.
$ git fetch 
        remote: Enumerando objetos: 5, listo.
        remote: Contando objetos: 100% (5/5), listo.
        remote: Comprimiendo objetos: 100% (2/2), listo.
        remote: Total 3 (delta 0), reusado 0 (delta 0)
        Desempaquetando objetos: 100% (3/3), 294 bytes | 294.00 KiB/s, listo.
        Desde ~/sandbox/remotes/origin
         * [nueva rama]      feature/tiger -> origin/feature/tiger

$ git branch -a
        * master
          remotes/origin/HEAD -> origin/master
          remotes/origin/feature/tiger
          remotes/origin/master

### Pin borra del repositorio remoto feature/tiger.

# Pon hago un fecth y no pasa nada.
$ git fetch 

# La rama origin/feature/tiger sigue existiendo.
$ git branch -a
        * master
          remotes/origin/HEAD -> origin/master
          remotes/origin/feature/tiger
          remotes/origin/master

# Si hiciese fetch con la opción --prune
# origin/feature/tiger se borraría.
$ git fetch --prune
        Desde ~/sandbox/remotes/origin
         - [eliminado]       (nada)     -> origin/feature/tiger

$ git branch -a
        * master
          remotes/origin/HEAD -> origin/master
          remotes/origin/master
Enter fullscreen mode Exit fullscreen mode

Ramas locales que se han quedado sin rama remota

  1. Pin subió la rama feature/duck
  2. Pon hizo un git fech y git checkout feature/duck, lo cual creo la rama local feature/duck cuyo upstream es origin/feature/duck.
  3. Pin mergeó feature/duck en master y la borro del repositorio remoto para no deja una rama que ya terminado su ciclo de vida.
  4. Pon hizo git fecth con la opción de autoprune, con lo cual Git borro la rama origin/feature/duck , pero no feature/duck, no vaya a ser que por alguna razón se quiera conservar en local, o que la rama local hubiese divergido de la rama remota y se pierdan commits.
  5. Pon ejecuta git status y ve el siguiente mensaje Tu rama está basada en 'origin/feature/duck', pero upstream ha desaparecido.

La manera de limpiar estar ramas es borrarlas a mano: git branch -d feature/duck

Pero con el tiempo se vuelve una tarea repetitiva y pesada, sobre todo cuando hay varias ramas en ese estado.

Una forma de hacerlo menos pesado es definiendo un par de alias en ~/.gitconfig

[alias]
    clear-pruned-branches = "!f() { git branch -vv | grep -E ': (desaparecido|gone)\\]' | grep -v '*' | awk '{print $1}' | xargs -r git branch -d; }; f"
  fetch-and-clear = !sh -c 'git fetch && git clear-pruned-branches'
Enter fullscreen mode Exit fullscreen mode

git clear-pruned-branches borraría las ramas desaparecidas que no estén mergeadas en la rama actual (git branch -d).
Si alguna rama no se puede borrar porque no está mergeada mostrará un mensaje tal que error: La rama 'feature/gorilla' no ha sido fusionada completamente., y tal vez haya que prestarle un poco más de atención para no borrar algún commit que se olvido subir.

git fetch-and-clear serviría como atajo para evitar tener que escribir git fecth && git clear-pruned-branches.
Para mantener el sistema limpio se puede usar git clear-pruned-branches o usar git fetch-and-clear en lugar de git fetch.

Un ejemplo paso a paso

### Pin publica la rama feature/duck.

# Pon hace un fetch y va a la ramara a cotillear.
$ git fetch
        Desde ~/sandbox/remotes/origin
         * [nueva rama]      duck       -> origin/duck
$ git checkout duck 
        Rama 'duck' configurada para hacer seguimiento a la rama remota 'duck' de 'origin'.
        Cambiado a nueva rama 'duck'
$ git status
        En la rama duck
        Tu rama está actualizada con 'origin/duck'.

        nada para hacer commit, el árbol de trabajo está limpio

### Pin borra del repositorio remoto feature/duck.

# Pon hace un fecth y como tiene el autoprune activo 
# borra la rama remota.
$ git fetch
        Desde ~/sandbox/remotes/origin
         - [eliminado]       (nada)     -> origin/duck

# git status dice que el upstream ha desaparecido.
$ git status
        En la rama duck
        Tu rama está basada en 'origin/duck', pero upstream ha desaparecido.
          (usa "git branch --unset-upstream" para arreglar)

        nada para hacer commit, el árbol de trabajo está limpio

# Para borrarla tendría que ir a otra rama y borrarla
$ git checkout master 
        Cambiado a rama 'master'
        Tu rama está actualizada con 'origin/master'.

$ git branch -d duck
        Eliminada la rama duck (era 01d5c54)..
Enter fullscreen mode Exit fullscreen mode

Ramas remotas que han sido mergeadas pero no borradas

  1. Pin subió la rama feature/dolphin.
  2. Mergeó la rama feature/dolphine en master pero no la borro.
  3. La rama sigue ahí 3 meses después.

Muchos sistemas de control de versiones como GitHub o Bitbucket tienen una opción para borrar la rama al mergear si se usan Pull Request o Merge Request, pero no es raro que se olvide marcarla, o que el merge se haga en local y se olvide borrar la rama después.

Una solución es ir al repositorio remoto y borrar una por una, asegurándose de borrar solo las ramas mergeadas para no perder ningún commit
Pero de nuevo es una tarea manual y tediosa, que se puede simplificar con un comando de consola

# Ir a la rama de integración, master en ese caso
git checkout master \
    `# Actualizarla a la última versión` \
    && git pull --ff-only \
    `# Listar todas ramas remotas mergeadas en master` \
    && git branch -r --merged \
  `# Excluir del listado las ramas que no hay que borrar;` \
  `# con expresiones regulares se exluyen las que contienen el texto` \
  `# "master", "production" o "RC"` \
    | grep -vE 'master|production|RC' \
  `# Quitar del texto el nombre del repositorio remoto` \
  | sed 's/origin\///' \
  `# Borrar las ramas del repositorio remoto` \
  | xargs -r -n 1 git push --delete origin
Enter fullscreen mode Exit fullscreen mode

No es un comando precisamente sencillo, y personalmente siempre me da un poco de respecto ejecutarlo.
Por ello, primero listo las ramas que se irían a borrar.

# Ir a la rama de integración, master en ese caso
git checkout master \
    `# Actualizarla a la última versión` \
    && git pull --ff-only \
    `# Listar todas ramas remotas mergeadas en master` \
    && git branch -r --merged \
  `# Excluir del listado las ramas que no hay que borrar` \
  `# con expresiones regulares se exluyen las que contienen el texto` \
  `# "master", "production" o "RC"` \
    | grep -vE 'master|production|RC' \
  `# Quitar del texto el nombre del repositorio remoto` \
  | sed 's/origin\///'
Enter fullscreen mode Exit fullscreen mode

Las reviso, y si todo me cuadra ya lanzo el comando completo.

Y como medida de seguridad adicional, siempre se puede clonar el proyecto original para tener un backup.

git clone <repository-url> <project-name>-bck-"$(date)"
Enter fullscreen mode Exit fullscreen mode
# Hago 'git branch' y veo que hay muchas ramas,
# muchas de las cuales creo que ya no se usan.
$ git branch 
        * contenido-home
          master
          rama-dos
          rama-nueve
          rama-seis
          rama-siete
          rama-tres
          rama-uno
          seccion-contacto

# Intento borrar alguna que ya se haya borrado del repositorio 
# remoto,pero nada.
# (fetch-and-clear es un alias descrito algo más arriba en 
# "Ramas locales que se han quedado sin rama remota")
$ git fetch-and-clear

$ git checkout master 
# Miro cuantas ramas hay mergeadas en master y hay unas cuantas...
$ git branch -r --merged
        origin/HEAD -> origin/master
      origin/master
      origin/production
      origin/rama-cinco
      origin/rama-cuatro
      origin/rama-diez
      origin/rama-dos
      origin/rama-nueve
      origin/rama-ocho
      origin/rama-seis
      origin/rama-siete
      origin/rama-tres
      origin/rama-uno
      origin/seccion-contacto

# Asi que quiero borrarlas todas menos 'production'. 
# Como borrarlas una a una sería demasiado tedioso uso un script.
$ git branch -r --merged \
   `# Excluir del listado las ramas que no hay que borrar;` \
   `# con expresiones regulares se exluyen las que contienen el texto` \
   `# "master", "production" o "RC"` \
   | grep -vE 'master|production|RC' \
   `# Quitar del texto el nombre del repositorio remoto` \
   | sed 's/origin\///' \
   `# Borrar las ramas del repositorio remoto` \
   | xargs -r -n 1 git push --delete origin
                To ~/sandbox/remotes/origin
         - [deleted]         rama-cinco
        To ~/sandbox/remotes/origin
         - [deleted]         rama-cuatro
        To ~/sandbox/remotes/origin
         - [deleted]         rama-diez
        To ~/sandbox/remotes/origin
         - [deleted]         rama-dos
        To ~/sandbox/remotes/origin
         - [deleted]         rama-nueve
        To ~/sandbox/remotes/origin
         - [deleted]         rama-ocho
        To ~/sandbox/remotes/origin
         - [deleted]         rama-seis
        To ~/sandbox/remotes/origin
         - [deleted]         rama-siete
        To ~/sandbox/remotes/origin
         - [deleted]         rama-tres
        To ~/sandbox/remotes/origin
         - [deleted]         rama-uno
        To ~/sandbox/remotes/origin
         - [deleted]         seccion-contacto

# Listo todas las ramas y veo que se han borrado muchas 
# del repositorio remoto, pero todavía quedan muchas en local. 
$ git branch -a
          contenido-home
        * master
          rama-dos
          rama-nueve
          rama-seis
          rama-siete
          rama-tres
          rama-uno
          seccion-contacto
          remotes/origin/HEAD -> origin/master
          remotes/origin/contenido-home
          remotes/origin/master
          remotes/origin/production

# Puede ser que me falte hacer el prune y borrar las ramas locales
# que se han quedado sin rama remota.
$ git fetch-and-clear 
        Eliminada la rama rama-dos (era 211751a)..
        Eliminada la rama rama-nueve (era 211751a)..
        Eliminada la rama rama-seis (era 211751a)..
        Eliminada la rama rama-siete (era 211751a)..
        Eliminada la rama rama-tres (era 211751a)..
        Eliminada la rama rama-uno (era 211751a)..
        Eliminada la rama seccion-contacto (era 2656b99)..

# Reviso por última vez y veo que está más limpio.
$ git branch -a
          contenido-home
        * master
          remotes/origin/HEAD -> origin/master
          remotes/origin/contenido-home
          remotes/origin/master
          remotes/origin/production
Enter fullscreen mode Exit fullscreen mode

Modificar un tag

He creado un tag en el commit que no era; me he equivocado en el nombre del tag; he creado un tag del tipo que no era; etc

Si no se ha subido todavía al repositorio remoto, basta con borrarlo y volver a crearlo.


🚨 Si ya se ha subido al repositorio remoto... se podría reemplazar, pero eso tendría consecuencias para otros desarrolladores.


Los tags no están pensados para ser modificados, así que si alguien modifica un tag en el repositorio remoto, ya sea haciendo git push -f o borrándolo y recreándolo, el resto de desarrolladores seguirían teniendo en sus locales la versión original del tag, ya que git fetch no modifica tags.

Y puede ser un problema si en algún momento hay que revertir alguna rama a ese tag o hay que sacar un fix para esa versión, ya que dependiendo de quien haga la operación los resultados serían distintos.

En la documentación de Git se analiza este caso, y vienen a proponer dos soluciones.

La primera es crear un nuevo tag, añadiéndole por ejemplo un sufijo (si el tag original era 1.0.0 llamar al nuevo 1.0.0-the-good-one).

La segunda opción es modificar el tag en el repositorio remoto y escribir al resto de desarrolladores explicando lo ocurrido y describiendo los pasos que hay que seguir para obtener el tag correcto (borrar el tag en local con git tag --delete TAG, hacer git fetch para obtener la nueva versión, y verificar que tienen el tag correcto con git rev-parse TAG o git show TAG)

Aquí un ejemplo práctico.

# Moratadelo crea un nuevo tag y lo sube al repositorio remoto.
mortadelo@tia$ git commit -am "Implementado algoritmo secreto"
        [master 2da5ad7] Implementado algoritmo secreto
         1 file changed, 1 insertion(+)

mortadelo@tia$ git push 
        Enumerando objetos: 5, listo.
        Contando objetos: 100% (5/5), listo.
        Compresión delta usando hasta 12 hilos
        Comprimiendo objetos: 100% (2/2), listo.
        Escribiendo objetos: 100% (3/3), 285 bytes | 285.00 KiB/s, listo.
        Total 3 (delta 0), reusado 0 (delta 0)
        To ~/sandbox/remotes/origin/
           409db7e..2da5ad7  master -> master

mortadelo@tia$ git tag -a "1.0.0" -m "Implementado algoritmo secreto"

mortadelo@tia$ git push origin 1.0.0
        Enumerando objetos: 1, listo.
        Contando objetos: 100% (1/1), listo.
        Escribiendo objetos: 100% (1/1), 169 bytes | 169.00 KiB/s, listo.
        Total 1 (delta 0), reusado 0 (delta 0)
        To ~/sandbox/remotes/origin/
         * [new tag]         1.0.0 -> 1.0.0

# Se lo comenta a Filemón, que hace git fectch para traerse todas
# las novedades
filemon@tia$ git fetch
        remote: Enumerando objetos: 6, listo.
        remote: Contando objetos: 100% (6/6), listo.
        remote: Comprimiendo objetos: 100% (3/3), listo.
        remote: Total 4 (delta 0), reusado 0 (delta 0)
        Desempaquetando objetos: 100% (4/4), 402 bytes | 402.00 KiB/s, listo.
        Desde ~/sandbox/remotes/origin
           409db7e..2da5ad7  master     -> origin/master
         * [nuevo tag]       1.0.0      -> 1.0.0

# Por algúna razón Mortadelo se da cuenta de que hay un error 
# en código y decide actualizarlo.
mortadelo@tia$ git commit \
                   -am "Implementación sin errores del algoritmo secreto"
        [master e985b90] Implementación sin errores del algoritmo secreto
         1 file changed, 1 insertion(+)

mortadelo@tia$ git push 
        Enumerando objetos: 5, listo.
        Contando objetos: 100% (5/5), listo.
        Compresión delta usando hasta 12 hilos
        Comprimiendo objetos: 100% (2/2), listo.
        Escribiendo objetos: 100% (3/3), 311 bytes | 311.00 KiB/s, listo.
        Total 3 (delta 0), reusado 0 (delta 0)
        To ~/sandbox/remotes/origin/
           2da5ad7..e985b90  master -> master

# Mortadelo no quiere que el primer tag del proyecto tenga 
# ese bug, así que intenta recrearlo, pero Git le da error.
mortadelo@tia$ git tag -a "1.0.0" -m "Implementado algoritmo secreto"
        fatal: el tag '1.0.0' ya existe
# Decidido a cubrir sus huellas opta por borrar el tag 
# y crear el bueno.
mortadelo@tia$ git tag --delete 1.0.0
        Etiqueta '1.0.0' eliminada (era b017cde)

mortadelo@tia$ git tag -a "1.0.0" -m "Implementado algoritmo secreto"

# Intenta pushearlo, pero el repositorio remoto lo rechaza
mortadelo@tia$ git push origin 1.0.0
        To ~/sandbox/remotes/origin/
         ! [rejected]        1.0.0 -> 1.0.0 (already exists)
        error: falló el push de algunas referencias a '~/sandbox/remotes/origin/'
        ayuda: Actualizaciones fueron rechazadas porque el tag ya existe en el remoto.

# Resuelto quema todas las naves con un git push -f
mortadelo@tia$ git push --force origin 1.0.0
        Enumerando objetos: 1, listo.
        Contando objetos: 100% (1/1), listo.
        Escribiendo objetos: 100% (1/1), 171 bytes | 171.00 KiB/s, listo.
        Total 1 (delta 0), reusado 0 (delta 0)
        To ~/sandbox/remotes/origin/
         + b017cde...7a1b39e 1.0.0 -> 1.0.0 (forced update)

# Revisa la información del tag para comprobar que es la esperada.
mortadelo@tia$ git show 1.0.0
        tag 1.0.0
        Tagger: mortadelo <mortadelo@tia.es>
        Date:   Sun Sep 19 17:19:08 2021 +0200

        Implementado algoritmo secreto

        commit e985b904626ff98b77b2478d15abd929d4b6237d (HEAD -> master, tag: 1.0.0, origin/master, origin/HEAD)
        Author: mortadelo <mortadelo@tia.es>
        Date:   Sun Sep 19 17:18:34 2021 +0200

            Implementación sin errores del algoritmo secreto


# Filemón, hace git fetch, pero el tag no se actualiza.
filemon@tia$ git fetch
        remote: Enumerando objetos: 6, listo.
        remote: Contando objetos: 100% (6/6), listo.
        remote: Comprimiendo objetos: 100% (3/3), listo.
        remote: Total 4 (delta 0), reusado 0 (delta 0)
        Desempaquetando objetos: 100% (4/4), 430 bytes | 430.00 KiB/s, listo.
        Desde ~/sandbox/remotes/origin
           2da5ad7..e985b90  master     -> origin/master

# Revisa su tag en local y es distinto al de Mortadelo, 
# ya que apunta a la versión con el bug.
filmemon@tia$ git show 1.0.0
        tag 1.0.0
        Tagger: mortadelo <mortadelo@tia.es>
        Date:   Sun Sep 19 17:14:32 2021 +0200

        Implementado algoritmo secreto

        commit 2da5ad761654cd67bbd8bdfe1a9ac9891f04970f (tag: 1.0.0)
        Author: mortadelo <mortadelo@tia.es>
        Date:   Sun Sep 19 17:11:17 2021 +0200

            Implementado algoritmo secreto

# Para tener el mismo tag que Mortadelo tendría que 
# borrar el tag en local.
filmemon@tia$ git tag --delete 1.0.0
        Etiqueta '1.0.0' eliminada (era b017cde)
# Y hacer git fetch para obtener el nuevo tag
filmemon@tia$ git fetch
        Desde /home/claudio/sandbox/remotes/origin
         * [nuevo tag]       1.0.0      -> 1.0.0

# Revisa la información y ya ve lo mismo que Mortadelo.
filmemon@tia$ git show 1.0.0
        tag 1.0.0
        Tagger: mortadelo <mortadelo@tia.es>
        Date:   Sun Sep 19 17:19:08 2021 +0200

        Implementado algoritmo secreto

        commit e985b904626ff98b77b2478d15abd929d4b6237d (HEAD -> master, tag: 1.0.0, origin/master, origin/HEAD)
        Author: mortadelo <mortadelo@tia.es>
        Date:   Sun Sep 19 17:18:34 2021 +0200

            Implementación sin errores del algoritmo secreto

Enter fullscreen mode Exit fullscreen mode



Si has llegado hasta aquí, gracias 🙂
Este era el último post de la serie; espero que este post, así como los anteriores, te hayan resultado útiles 👋

Créditos

Cover: https://www.pexels.com/photo/photography-of-forest-during-daytime-1068508/
Generación de diagramas: https://excalidraw.com/

💖 💪 🙅 🚩
narkha
Claudio Sánchez

Posted on September 26, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related