alfonso, autor en Aprende GIT https://aprendegit.com/author/alfonso/ Información y experiencias sobre el uso de git Thu, 25 Jul 2024 14:51:44 +0000 es hourly 1 https://wordpress.org/?v=6.6.1 43885904 Cómo deshacer el último commit en git https://aprendegit.com/como-deshacer-el-ultimo-commit-en-git/ https://aprendegit.com/como-deshacer-el-ultimo-commit-en-git/#comments Wed, 11 Sep 2013 15:14:32 +0000 https://aprendegit.com/?p=630 Aquí os dejo una manera sencilla de dar marcha atrás si habéis hecho un commit y os habéis arrepentido de hacerlo. El motivo por el que queréis «borrarlo» puede ser múltiple: porque el trabajo no está terminado y queréis continuar trabajando, habéis introducido un bug sin daos cuenta o sencillamente os habéis equivocado y lo habéis hecho antes de tiempo.

Existen dos maneras de borrar ese commit:

  • Eliminando junto al commit las modificaciones que este contiene
  • Recuperándolas en el área de trabajo para seguir trabajando en ellas

En ambos casos, el comando que utilizaremos será «git reset».

Deshacer el commit perdiendo las modificaciones

Supongamos que tenemos nuestro repositorio en el siguiente estado:

Voila_Capture283y queremos deshacer el último commit. En este primer caso, queremos desechar los cambios introducidos en ese commit que contiene una serie de tests funcionales.

Para ello, ejecutamos el comando:

git reset --hard HEAD~1

Tras ejecutar el comando, el estado del repositorio es el siguiente:

Repositorio tras borrar el commit

Como podéis ver, el commit 600cc08 ha desaparecido que era lo que queríamos. Además, la rama activa se ha desplazado un commit hacia abajo y nuestro área de trabajo ha quedado en el estado del commit 6eb9f2d. Los tests funcionales que estaban en el commit se han perdido y tendríamos que recurrir al reflog para recuperarlos.

La sintaxis HEAD~1 del comando anterior la podríamos traducir como «El commit al que está apuntando la rama activa menos uno». Si hubiésemos ejecutado el comando:

git reset --hard HEAD~3

en lugar de acabar en el commit 6eb9f2d (uno por detrás) habríamos acabado en 63db9fa (tres por detrás).

Deshacer el commit manteniendo las modificaciones

Existe la posibilidad de eliminar el commit pero manteniendo las modificaciones que contiene ese commit en el área de trabajo. ¿Y por qué querríamos hacer esto? Por varios motivos, por ejemplo por que los tests funcionales del commit 600cc08 están incompletos, son incorrectos o he introducido algún bug en él.

Partiendo de nuevo del mismos estado inicial de antes:

Estado inicial del repositorio.ejecutaríamos el siguiente comando:

git reset HEAD~1

Tras lo cual, el estado del repositorio sería:

Voila_Capture285Si miráis el estado veréis los siguiente:

  • Al igual que en el caso anterior, el commit 600cc08 ha desaparecido
  • La rama activa (rest) ha pasado al apuntar al commit 6eb9f2d
  • A diferencia del  caso anterior, el área de trabajo contiene las modificaciones que estaban en el commit que acabamos de borrar.

Así que podemos seguir trabajando, corregir el bug o completar los tests que habíamos dejado incompletos y hacer un nuevo commit con los cambios completos. ¡Así de fácil!

Muy útil pero…

Muy importante tener en cuenta que estas dos operaciones sobreescriben la historia del repositorio ¡estamos borrando un commit!. Si estamos trabajando en local y no hemos hecho push a nuestro remoto no hay ningún problema. Si ha habéis hecho push de este commit tened en cuenta que vuestros compañeros lo seguirán viendo si alguna de sus ramas lo referencia.

Espero que os haya resultado útil.

 

 

]]>
https://aprendegit.com/como-deshacer-el-ultimo-commit-en-git/feed/ 15 630
6 motivos por los que git no es un sistema de backup https://aprendegit.com/6-motivos-por-los-que-git-no-es-un-sistema-de-backup/ https://aprendegit.com/6-motivos-por-los-que-git-no-es-un-sistema-de-backup/#comments Tue, 11 Jun 2013 05:51:35 +0000 https://aprendegit.com/?p=608 Esta es una frase que escucho muy a menudo:

 “Yo tengo backup de mi repositorio git en github”.

Siempre que la escucho acabo teniendo la misma conversación con la persona que la ha dicho. Intento hacerle ver porqué github, bitbucket o cualquier otro servicio de hosting de repositorios no son una copia de seguridad de tu repositorio y cómo en determinadas circunstancias (muy habituales cuando trabajas en equipo) puedes perder información por usarlos para lo que no son.

Esto desde el punto de vista práctico. Si escarbamos un poco, lo normal es que detrás de esta frase se esconda un uso no del todo correcto de git o un desconocimiento de ciertas funcionalidades de la herramienta que espero corregir con este artículo.

En adelante me referiré a tu cuenta de github, bitbucket o cualquier otro sistema de hosting de repositorios git como servidor git.

1- Git es algo más que hacer un commit al final de nuestra jornada

El flujo más básico de uso de git que me he encontrado es el siguiente:

  • Llego a trabajar por la mañana y trabajo
  • Antes de irme hago un commit
  • Después del commit hago un push

Así, tienes en tu servidor git la última versión del código fuente. Si respetas este flujo, efectivamente tienes una copia de la última versión de tu código fuente en tu servidor. Ahora bien, no tienes una copia de tu repositorio, porque el repositorio del servidor al que haces push y el de tu máquina local son diferentes. ¡Por eso haces push!

Este forma de trabajo viola varias de las buenas prácticas de git:

  • No estás haciendo commits atómicos, pequeños y muy a menudo. Lo que significa que no estás pensando en cómo gestionar tu código sino en guardar la última versión en un «cajón de sastre» que es tu servidor
  • No estás trabajando con ramas locales para desarrollar funcionalidad
  • Probablemente, no tienes definido ningún flujo de trabajo que te permita gestionar cambios de contexto a la hora de trabajar

2- No estás guardando una copia de tus ramas locales

Las ramas locales, son eso, ramas locales. Las usas para muchas cosas, entre ellas para hacer pruebas, hacer refactorings del código o desarrollar funcionalidades en paralelo. Al no hacer push, de estas ramas, no tienes copia de los commits en tu servidor git.

Sé lo que estás pensando, basta con hacer push de todas las ramas y ya está. Bien, eso es correcto si estás tu solo con tu repositorio. Ahora bien, si estás trabajando en equipo y todos vosotros compartís el mismo repositorio git, la cosa cambia ¿Te imaginas a 5 personas todas subiendo sus ramas de prueba al servidor git para tener copia de seguridad? El caos está garantizado si no se organiza todo muy, muy, muy bien.

3- No estás guardando una copia del reflog

El reflog es un fichero de log que está en la carpeta .git de tu repositorio local donde se guarda un log de todos los cambios de referencias que ocurren en tu repositorio. Cada vez que cambias de rama, haces un merge, un rebase, un pull o un cherry-pick (entre otros) se guarda en el reflog lo que ha pasado.

Este fichero es el que te permite dar marcha atrás cuando la lías parda. Échale un vistazo a este hangout para un ejemplo sobre cómo se usa.

Tu reflog no está en tu servidor git. El servidor git tiene su propio reflog que no tiene porqué coincidir con el tuyo. De nuevo, si estás tu solo y haces push de todas tus ramas, el reflog del servidor se parecerá mucho al tuyo. Eso sí, en caso de desastre, tendrás que entrar al servidor a verlo o copiartelo a tu máquina local… oh, vaya, espera, que estás trabajando con github / bitbucket y no te dejan entrar a sus servidores a descargarte el reflog, desde luego qué tíos perros ¿no?.

Si estás trabajando en equipo, el reflog del servidor tiene todas las modificaciones de referencias hechas por tí y el resto del equipo. ¡Intentar encontrar algo en ese reflog es garantía de diversión durante horas!

4- No tienes backup de los hooks de tu repositorio git

Dentro de la carpeta .git/hooks de tu repositorio puedes poner hooks. Estos hooks no son más que scripts que se ejecutan antes o después de los comandos git y que te permiten interceptar la ejecución para hacer «cosas». Por ejemplo, el ‘pre-commit’ te permite manipular dinámicamente el mensaje del commit que se genera por defecto.

Cualquier hook que hayas puesto en tu máquina local en la carpeta .git/hooks, no tiene copia de seguridad en tu servidor git.

5- No tienes backup de tu configuración local

Dentro de tu repositorio tienes un fichero con la configuración local de tu repositorio: .git/config. En este fichero puedes guardar varias cosas, entre ellas el nombre y correo electrónico del autor de los commits, alisas de comandos de esos molones que te has bajado de internet y, en general, opciones de configuración específicas de ese repositorio en esa máquina.

Este fichero tampoco se sube a tu servidor git, así que en caso de desastre, lo pierdes y tienes que volver a generar la configuración del repositorio.

6- git permite sobreescribir la historia de tu repositorio

Si trabajas con más gente, en tu repositorio no vas a estar hurgando solo tú. Tendrás código de otras personas, harás merges o pull requests. Hay alguien que puede estar tocando el repositorio detrás de tí así que entre el momento que ocurre el desastre y «recuperas» el repositorio haciendo un clon, muchas cosas pueden haber cambiado.

Ponte en esta situación: te vas de vacaciones mientras tus compañeros trabajan en el repositorio. A la vuelta tu disco duro ha muerto, o durante el viaje te roban el portátil, así que clonas de nuevo el repositorio y te pones a trabajar… Lo que vas a clonar no es lo que tenías antes de irte, el repositorio contendrá todos los cambios que tus compañeros han hecho en tu ausencia.

Me dirás: “tío, no tienes ni idea. Una vez clonado hago un reset al commit de antes de irme de vacaciones y ya está”… Y yo te digo ¿Y no sabes que tus compañeros del alma pueden haberse cargado esos commits con un rebase, por ejemplo?. Recuerda: git, a diferencia de mercurial, permite sobreescribir la historia del repositorio así que ¡¡nada te garantiza que cuando vuelvas de tus vacaciones los commits sigan ahí!!

Conclusión

Según la wikipedia:

a backup, or the process of backing up, refers to the copying and archiving of 
computer data so it may be used to restore the original after a data loss event.

Si pierdes tu disco duro, y recuperas un repositorio haciendo un nuevo clon, no estás recuperando el repositorio como lo tenías antes del desastre así que según esta definición, no es una copia de seguridad. Además ¿Tú crees que Linus Torvalds hizo git para esto? ¿Para hacer backup? ¡eso ya lo tenía con los ficheros tar con los que empezó! Si solo lo usas para hacer copias de respaldo te estás perdiendo muchas cosas.

Git no es un sistema de copia de seguridad de nuestro código. Ahora bien, si se dan estas condiciones:

  1. Estás trabajando tú solo
  2. Haces push de todos los commits al repositorio remoto
  3. Todas las ramas que creas son remotas
  4. Tienes un repositorio que llamas scripts_y_configuracion en el que guardas los hooks, alias, pro-tips y configuraciones personalizadas de tus repositorios.

y eres consciente de lo que estás haciendo, puedes utilizar github como un backup (parcial) de tu código fuente, no de tu repositorio.

De igual manera, si trabajas en equipo y cada integrante tiene su propio repositorio, cada uno de vosotros podría usar git de esta manera. Aunque es un flujo muy básico que sirve para empezar a trabajar, no lo recomiendo en casi ningún caso: en seguida se te queda corto.

En mi caso particular, TimeMachine me ha salvado ya en varias ocasiones de problemas, ahorrándome mucho tiempo y trabajo. Aquí tienes mi consejo: usa una herramienta de backups para hacer backups y una herramienta de gestión de código para gestionar código.

]]>
https://aprendegit.com/6-motivos-por-los-que-git-no-es-un-sistema-de-backup/feed/ 7 608
git-merge 2013: user day https://aprendegit.com/git-merge-2013-user-day/ https://aprendegit.com/git-merge-2013-user-day/#comments Sat, 11 May 2013 10:28:22 +0000 https://aprendegit.com/?p=578  

Estamos en Berlín en pleno Git Merge Hack Day. Ayer fue el user day en git-merge 2013, la conferencia para usuarios de git que Github ha organizado en la capital alemana este fin de semana. 

git-merge 2013

A primera hora registro y café y un ratito de networking hasta que ha dado comienzo la conferencia. El formato ha sido abierto y muy, como no, colaborativo (muy github):

  • Lightning Talks hasta la hora de la comida
  • Tarde libre en formato “open space” en el que se proponían temas para hablar sobre ellos

Para los que no sepáis lo que son las Lightning Talks, podemos resumirlo en lo siguiente: “el que tenga algo que compartir que salga y lo haga”.

Y la verdad es que ha salido bastante gente a compartir herramientas, presentarse, sugerir temas de conversación para la tarde o contar el último proyecto en el que estaba trabajando:

  • El primero ha empezado con fuerza. Un plugin para integrar XCode con Github disponible vía “Alcatraz”. Podéis encontrarlo aquí: https://github.com/larsxschneider/ShowInGitHub. Está todavía en desarrollo aunque la verdad es que promete bastante.
  • Luego nos han presentado una iniciativa para hacer públicas las discusiones de los parlamentarios a medida que las leyes se van elaborando. ¿Os imagináis a nuestros queridos políticos haciendo un merge de la ley antipiratería y luego haciendo un pull request para incluir sus modificaciones y comentarlas con el resto de grupos? No, yo tampoco. Hay sitios en los que esto pasa. Esto es madurez democrática y lo demás son tonterías. Aquí tenéis el repositorio y el listado de leyes: https://github.com/Bundestag y http://bundestag.github.io/gesetze/ (en Alemán).
  • Dos de los desarrolladores de git-submodules han presentado rápidamente las novedades que están implementando (https://github.com/jlehmann/git-submod-enhancements/wiki).
  • Christian Couder nos ha contado lo potente que es git-bisect para localizar bugs (http://es.slideshare.net/ChristianCouder/enjoy-fighting-regressionswithgitbisect). Además, es muy fácil automatizar la búsqueda con un test y, una vez localizado, corregirlo y crear un commit con la solución y el script de testeo. En una encuesta / estudio realizado entre 40 desarrolladores se ha observado un 40% menos de bugs y hasta un 80% de reducción en el tiempo de localización y depuración del bug cuando se utiliza con TDD. Una herramienta para tener en cuenta. En una intervención posterior, una persona de Ericsson ha compartido con nosotros como utilizó git bisect para detectar y corregir un bug en perl.
  • Roberto Tyley nos ha presentado BFG-repo-cleaner, una herramienta escrita en Scala que multiplica por mucho la velocidad de git-filter-branch: http://rtyley.github.io/bfg-repo-cleaner/. En este enlace tenéis un vídeo que compara el rendimiento de un raspberry-pi usando su herramienta vs un MacBook Pro usando git-filter-branch… por supuesto gana la RaspberryPi.
  • Michael Haggerty ha presentado git-imerge, una herramienta para hacer merges incrementales entre ramas de larga duración (http://softwareswirl.blogspot.de/2013/05/git-incremental-merge.html, https://github.com/mhagger/git-imerge). Muchas vences me habréis oído decir “no dejes el merge para el final”, haz merge a menudo para resolver los conflictos poco a poco. Puesta esta herramienta facilita esta tarea. Está todavía en modo experimental, seguiremos su evolución con atención porque es realmente útil.
  • Jack Pearkes ha presentado get una herramienta escrita en Go y pensada para hacer fetch de una cuenta de github y todos sus repositorios. Siguiendo con el ejemplo que ha puesto Jack, antes de salir de casa con el portátil, me hago un fetch de todos los repositorios de mi cuenta y me voy al tren con todos actualizados.
  • Filip Noetzel ha hablado de dos proyectos bumpversion y geocommit. El primero sirve para actualizar todas las cadenas de versión de un programa, crear un commit y etiquetarlo. Está escrito en python y nos puede ahorrar trabajo a la hora de generar una nueva versión de nuestra aplicación. El segundo, geocommit, es un servicio que geolocaliza los commits y nos ayuda a ver de dónde vienen las contribuciones a un proyecto.
  • Una persona nos ha presentado gource. Digo una persona porque no me he quedado con su nombre y no era el que lo ha desarrollado. Es una aplicación que lee el repositorio y hace una animación de cómo evoluciona un repositorio. Muy chulo el resultado para repositorios grandes con muchos participantes. Después de esto las pantallas han estado mostrando la animación del repositorio de git el resto del día.
  • Se hicieron varias presentaciones sobre libgit2. En este momento es la niña bonita de Github ya que como nos contó Vicent Martí en la presentación (http://vimeo.com/64716825) les ha permitido resolver varios problemas de escalabilidad en el backend. Se trata de una implementación de git empaquetada en una librería en C de forma que puede utilizarse en cualquier aplicación. ¿Te imaginas poder hacer un commit desde una aplicación echa por tí en ruby o python? Pues esto es, entre otras cosas, lo que permite hacer libgit2. La librería está bastante madura y tiene bindings para muchos lenguajes (lo siento, parece que Java no es uno de ellos de momento).
  • Relacionado con libgit2, tuvimos dos presentaciones de personal de Microsoft en la que nos mostraron cómo instalar y usar el plugin de git en Visual Studio 2012 y cómo clonar un repositorio alojado en TFS usando git-tf. Parece que dentro de poco Visual Studio ya incluirá el soporte de git nativo y no será necesario instalar ningún plugin.
  • Mislav Marohnić nos presenta hub una herramienta escrita en ruby para trabajar con repositorios github desde la línea de comandos. Github la utiliza en sus cursos intermedios/avanzados.
  • Sergei nos presentó una herramienta para enseñar git bastante curiosa, muy parecida a http://pcottle.github.io/learnGitBranching/. Aunque el código no está en este momento abierto sí se puede usar en este enlace http://io.git-init.ru/git-trainer/
  • Matthew McCullough nos habló sobre los recursos que github ha puesto a disposición de la comunidad para aprender git: teach.github.com, learn.github.com y www.youtube.com/github.
  • Simon nos presentó subgit una herramienta que permite utilizar un repositorio tanto con clientes subversion como con clientes git. Si trabajas con los dos sistemas o te estás planteando una migración, esta puede ser una herramienta muy útil.
  • Jetbrains hos nizo una rápida exposición de algunas de las mejoras en las que están trabajando para el cliente git que incluyen en sus IDE. Me gustó mucho lo que ellos llaman “smart checkout” que básicamente es un stash-checkout-unstash, muy útil cuando has hecho varias modificaciones en el código en la rama que no era. También mostraron una nueva característica: cuando te rechazan un push porque tus referencias no están actualizadas, tienes que volver hacer un pull y luego volver a hacer el push. En las próximas versiones, Jetbrains lo hará por nosotros dándonos la opción la hacer el pull con un merge o con un rebase. Estos chicos siempre pensando en que trabajemos menos…(http://www.jetbrains.com/idea/webhelp/using-git-integration.html)
  • Nos enseñan otro proyecto muy curioso: emscripten. Se trata de un compilador LLVM-to-Javascript, es decir, coge LLVM Bitcode y lo transforma en javascript… ¿qué excusa tenéis ahora para no escribir javascript?
  • Sergio Gil, con el que tuve el placer de estar charlando un buen rato durante la tarde, nos presentó GHContributors (http://ghcontributors.herokuapp.com/) una web que nos muestra todas las contribuciones que un usuario ha hecho a github.
  • http://www.versioneye.com/ un servicio que monitoriza las librerías que utilizas en tu proyecto y te avisa cuando cambian de versión.
  • Para cerrar la sesión, Scott Chacon nos habló del portal git-scm.com/community. Como el mismo dijo, una página para usuarios de git, no para desarrolladores. Nos estuvo hablando del libro (http://www.github.com/progit/progit) y de los planes que tiene para la segunda edición, que quiere escribir contando con la colaboración más activa de usuarios y desarrolladores. También se habló de la traducción del libro, que os recuerdo se realiza a través de la comunidad, y nos habló de que en github se están planteando incluso la contratación de traductores profesionales para mejorar ese aspecto. Por supuesto no dio fechas ni plasmaron un compromiso formal sobre ello, lo plantearon como opción para ayudar a resolver el problema que se plantea con un tema tan complicado como es la traducción. En esta discusión, que continuó más tarde en el grupo de formación en git, contamos con la experiencia de Axel Hecht (Mozilla) y cómo gestionan ellos las traducciones de sus herramientas.
  • Para terminar las ligthning talks, Scott nos recordó, por si se nos había olvidado, que github es el servidor de repositorios subversion más grande del mundo. Basta con que hagáis un checkout de cualquier repositorio de git con vuestro cliente favorito de subversion:
svn checkout https://github.com/progit/progit

IMG_0490

Después de las charlas, se establecieron varios grupos en los que se habló de diferentes temas: formación, migración a git, traducción de material y recursos. Matthew McCullough y Brent Beer estuvieron hablando sobre cómo enseñan git y github en diferentes partes del mundo. Entre las 10 personas que estuvimos charlando e intercambiando experiencias, había dos corrientes: los que mostraban el grafo desde el primer momento y los que preferían esperar un poco antes de mostrar las famosas “pelotas con padres”. La conversación fue muy productiva con ideas y un notas para mejorar los cursos de git.

En paralelo a esta conversación sobre formación en git, tuvo lugar otra muy interesante sobre migración. Como por el momento no he desarrollado la capacidad de estar en dos sitios a la vez, Peter Jönsson (https://github.com/mindjiver) and Andrey Devyatkin (https://github.com/Andrey9kin) tuvieron la gentileza de volver a hablar conmigo sobre cómo hicieron en Ericsson una migración de Clear Case a git que afectó a mil personas. Lo primero que hicieron fue formar un equipo de 8 personas que durante los casi dos años que duró el proceso se dedicaron en exclusiva a ese proyecto. Dado que tenían un alto grado de personalización en la instalación que tenían de Clear Case, tuvieron que realizar varias herramientas a medida para implementar la funcionalidad que necesitaban. De echo, 4 de las personas del equipo eran programadores de backend y frontend dedicados a la aplicación que han desarrollado. Una de las necesidades que tenían era el almacenamiento de metadatos en los repositorios y me estuvieron comentando que de las tres opciones que tenían (mensaje del commit, git-notes y etiquetas) finalmente optaron por almacenarlos en el mensaje del commit y desarrollar un parser con expresiones regulares para extraer y buscar la información. Comentamos opciones como almacenarlos en una base de datos (SQL o NoSQL) aunque no era para ellos una opción por complicar la infraestructura más de lo necesario.

Si algo saco en claro de la experiencia tanto mía como de las conversaciones que tengo con cualquier persona que afronta una migración en git es que no es un proceso sencillo. Requiere planificación y una adecuada ejecución, y aunque lo que se gana es mucho, el proceso es doloroso y requiere compromiso de todo el equipo para poder llevarlo a cabo con éxito.

Como veis un día muy intenso y productivo. Veremos cómo se desarrolla el hack-day.

Más enlaces

git-merge-2013

]]>
https://aprendegit.com/git-merge-2013-user-day/feed/ 1 578
git-flow: Resumen y conclusiones https://aprendegit.com/git-flow-resumen-y-conclusiones/ https://aprendegit.com/git-flow-resumen-y-conclusiones/#comments Mon, 15 Apr 2013 08:00:24 +0000 https://aprendegit.com/?p=527 A lo largo de las últimas semanas hemos escrito una serie de cinco artículos en los que hemos hablado sobre git-flow:

  • En la introducción, vimos por qué surge esta extensión de git, qué hace y qué tipo de flujos de trabajo nos permite implementar.
  • Después instalamos git-flow, creamos un repositorio e inicializamos la extensión en el mismo.
  • Creamos las ramas develop y master y empezamos a desarrollar las historias de usuario del sprint usando feature branches.
  • Cuando terminamos nuestro sprint, utilizamos un release branch para testar y ajustar nuestro código antes de pasarlo a producción.
  • Finalmente vimos cómo corregir bugs urgentes en producción mediante el uso de hotfix branches.

 Qué nos aporta git-flow

  • Un flujo de trabajo básico para organizar el repositorio y nuestro trabajo.
  • Un convenio de nombres para nuestras ramas que permite a todos los miembros del equipo saber qué es cada cosa.
  • Unas reglas comunes a la hora de mover la información de una rama a otra.
  • Un conjunto de comandos que nos ahorra tiempo.
  • ¡Sourcetree tiene soporte en la aplicación! Si has entendido cómo funciona, puedes investigar cómo usarlo en la interfaz gráfica. Tienes el botón en la barra de herramientas.

Botón de git-flow en sourcetree

A lo largo de la serie siempre hemos relacionado los comandos de git-flow con los comandos git que la extensión ejecuta por detrás. Aunque nos facilite el trabajo, el uso de git-flow no nos exime de entender cómo funcionan las ramas, saber utilizar merge y rebase o entender la diferencia entre un pull y un fetch. Es entendiendo estos conceptos como le sacarás rendimiento a esta y a cualquier otra extensión de git.

He utilizado este flujo de trabajo en proyectos en los que he trabajado solo y proyectos con equipos de entre 3 y 5 personas.  Mi experiencia es que esta forma de organizar el repositorio es un buen punto de partida para el desarrollo de procesos más complejos, especialmente si el equipo no tiene mucha experiencia en el uso de git.

Como dijimos en la introducción, estas no son reglas absolutas. Y aunque funcionan en un gran número de equipos, puede que en tu caso necesites adaptarlas a tu forma de trabajar. Confío en que después de haber leído los artículos de esta serie, estés en condiciones de hacerlo.

]]>
https://aprendegit.com/git-flow-resumen-y-conclusiones/feed/ 4 527
git-flow: hotfix branches https://aprendegit.com/git-flow-hotfix-branches/ https://aprendegit.com/git-flow-hotfix-branches/#comments Thu, 11 Apr 2013 08:00:16 +0000 https://aprendegit.com/?p=507 Seguimos hablando de git-flow. En la entrada anterior vimos cómo utilizar un release branch para poner a punto nuestra aplicación antes de llevarla a producción. En esta última entrega de la serie veremos cómo utilizar git-flow para gestionar la resolución de bugs urgentes y, en general, cualquier tipo de modificación que requiera un rápido despliegue en producción.

¿Qué son las hotfix branches de git-flow?

Recordemos cómo había quedado nuestro repositorio tras la puesta en producción:

  • La rama master, que actualmente contiene la versión 1.0, ya ha sido desplegada en producción
  • La rama develop, que ya incorpora todos los cambios y ajustes que hicimos durante la puesta a punto de la versión 1.0, está lista para avanzar en el desarrollo de la versión 1.1

Recordemos cómo dejamos el repositorio en la entrega anterior:

Repositorio tras cerrar release/1.0

Estamos listos para empezar un nuevo sprint. Tenemos una reunión de planificación, ponemos en el backlog las historias de usuario que vamos a desarrollar para la versión 1.1, y empezamos a trabajar.

A los pocos días, recibimos un aviso de nuestros compañeros del departamento de atención al cliente: ¡hay un bug de la aplicación en producción! Git-flow utiliza hotfix branches para implementar un flujo de trabajo que permite:

  • Interrumpir el trabajo que estamos haciendo en la rama develop para la versión 1.1
  • Resolver el bug
  • Incorporar la corrección del bug en la rama master para desplegarlo en producción lo más rápido posible
  • Incorporar la corrección del bug en la rama develop (si procede)
  • Retomar el trabajo que estábamos haciendo en la rama develop

Para los que estáis familiarizados con la administración de sistemas, a mí cada vez que me pasa esto me siento como el kernel de Linux haciendo context switching. Cada vez que tenemos que dejar cambiar de rama tenemos que cambiar de contexto. Eso implica recordar qué estábamos haciendo, qué teníamos en la nueva rama y en qué estado estábamos. Sin una herramienta como git, que permite hacer este cambio de forma rápida y viendo la historia de las dos ramas, el tiempo necesario para hacer el cambio de contexto nos hace menos productivos. Las ramas hotfix nos ayudan a hacer estos cambios de contexto de forma más eficiente y a corregir el problema con el mínimo impacto sobre el resto del trabajo que estamos haciendo.

Creando la rama hotfix/bug-14

Como hemos comentado antes, supongamos que ya llevamos unos cuantos días trabajando en el sprint. Habremos creado una (o varias) feature branches y el estado de nuestro repositorio puede ser algo parecido a esto:

Estado de la rama develop antes del aviso de bug

Estado de la rama develop antes del aviso de bug

Nos encontramos trabajando en la historia de usuario H5 cuando recibimos la llamada de nuestros compañeros avisándonos del bug.

Lo primero que haremos será almacenar el trabajo que estamos haciendo y que vamos a tener que interrumpir porque tenemos que cambiar de contexto. El objetivo es guardar este trabajo a medias y recuperarlo cuando hayamos terminado de corregir el bug. Hay varias formas de hacer esto, nosotros lo guardaremos en el stash ya que prevemos que la corrección del bug no nos llevará mucho tiempo:

$ git stash save 'Antes de empezar a corregir el bug #14'
Saved working directory and index state On feature/h5: Antes de empezar a corregir el bug #14
HEAD is now at f6609a9 Primera implementación de las páginas estáticas

Podemos ver el contenido del stash con el comando git stash list

$ git stash list
stash@{0}: On feature/h5: Antes de empezar a corregir el bug #14

El objetivo de esta entrada no es hablar del stash, así que entraremos en detalle en otra ocasión. Si no sabes lo que es, puedes consultar este enlace. Seguimos.

Una vez tenemos nuestro trabajo almacenado y listo para cambiar de contexto, creamos la rama hotfix/bug14:

$ git flow hotfix start bug14
Switched to a new branch 'hotfix/bug14'

Follow-up actions:
- Bump the version number now!
- Start committing your hot fixes
- When done, run:

git flow hotfix finish 'bug14'
Creando la rama hotfix/bug14

Estado del repositorio tras crear la rama hotfix/bug14

Los comandos que git-flow ha ejecutado por nosotros son en este caso bastante sencillos:

$ git checkout master
$ git checkout -b hotfix/bug14

Con la rama creada, empezamos a trabajar en la corrección del bug. Pasadas unas horas y unos cuantos commits después, tenemos el bug corregido y listo para subir a producción. Este es el estado del repositorio:

bug #14 corregido

Estado del repositorio después de haber localizado y corregido el bug.

Cerrando la rama hotfix/bug14

Nos acercamos al final. Una vez corregido el bug, procedemos a cerrar la rama hotfix:

$ git flow hotfix finish bug14

Cuando ejecutamos este comando, git-flow nos pide que introduzcamos tres mensajes:

  • El primero de ellos es el mensaje del merge commit resultado de incorporar los cambios de hotfix/bug14 en master
Introducir mensaje para el merge commit con la rama master

Se abre el editor predeterminado para introducir el mensaje del merge commit

  • El segundo es el mensaje que git-flow pondrá a la etiqueta que va a crear para identificar esta versión (vbug14)
Introducir mensaje para la etiqueta

Mensaje para la etiqueta de versión

  • El tercero y último será el mensaje que git-flow pondrá en el merge commit resultado de incorporar la rama hotfix/bug14 en develop
Introducir mensaje para el merge commit con la rama develop

Se abre el editor predeterminado para introducir el mensaje del merge commit con la rama develop

Al igual que cuando cerramos la rama release/1.0, al finalizar la ejecución del comando se muestra un resumen de todas las acciones que han tenido lugar:

Salida de git-flow al cerrar un hotfix branch

En rojo hemos indicado las acciones que git-flow ha ido ejecutando y que pueden resumirse en los siguientes comandos:

git checkout master
git merge hotfix/bug14 --no-ff
git tag vbug14
git checkout develop
git merge hotfix/bug14 --no-ff
git branch -d hotfix/bug14

El nombre que git-flow ha puesto a la etiqueta no es precisamente el más adecuado, así que borramos esa etiqueta y creamos una nueva que se llama v1.0.1. El repositorio queda de la siguiente manera:

Repositorio tras cerrar hotfix/bug14

Y ya está, casi hemos terminado… Sólo nos falta volver a cambiar de contexto y recuperar el repositorio como lo teníamos antes de empezar a corregir el bug.

Volviendo a la rama feature/h5

Este paso es el más sencillo, basta ejecutar el comando

$ git checkout feature/h5

Ahora bien: ¿cómo recuperamos ese trabajo a medias que habíamos tenido que interrumpir y que almacenamos en el stash?

$ git stash list
stash@{0}: On feature/h5: Antes de empezar a corregir el bug #14

$ git stash pop stash@{0}
Auto-merging 

(Nota: dado que sólo tenemos una cosa guardada en el stash, podríamos ejecutar sencillamente git stash pop).

Y con esto hemos terminado, ya tenemos todo listo para seguir trabajando en la historia de usuario H5.

Conclusión

En esta entrega hemos visto cómo git-flow nos ayuda a gestionar la corrección de bugs del sistema en producción a través de hotfix branches. Creando una rama específica para corregir el bug, conseguimos que mientras una parte del equipo está trabajando en la rama develop, otra parte pueda corregir el bug. Si es una misma persona la que tiene que hacer este trabajo, la creación de estas ramas auxiliares facilita el cambio de contexto al desarrollador.

Este tipo de ramas no tienen mucho sentido en las ramas develop ya que la detección y corrección de bugs forma parte del proceso de desarrollo de nueva funcionalidad

En la siguiente entrega haremos un pequeño resumen de lo que hemos visto en esta serie de artículos y daremos por terminada la serie.

]]>
https://aprendegit.com/git-flow-hotfix-branches/feed/ 6 507
git-flow: release branches https://aprendegit.com/git-flow-release-branches/ https://aprendegit.com/git-flow-release-branches/#comments Tue, 02 Apr 2013 06:59:20 +0000 https://aprendegit.com/?p=487 En la entrada anterior vimos cómo utilizamos la rama develop y las features branches para desarrollar la primera versión de la aplicación. En este entrega veremos cómo utilizar las release branches  para preparar la puesta en producción de nuestra aplicación.

¿Para qué necesitamos una release branch?

El objetivo de estas ramas es preparar nuestra aplicación para su puesta en producción. En algunos equipos, estas ramas son las que se vuelcan en los servidores de pre-producción para hacer el testing final: se corrigen bugs, se pule la interfaz, se ajusta la maquetación…se hace la puesta a punto final de la aplicación antes de liberar la versión definitiva. Vamos a crear una release branch para la versión 1.0. Utilizando la línea de comandos, ejecutamos

$ git flow release start 1.0

Switched to a new branch 'release/1.0'
Summary of actions:
- A new branch 'release/1.0' was created, based on 'develop'
- You are now on branch 'release/1.0'

Follow-up actions:

- Bump the version number now!
- Start committing last-minute fixes in preparing your release

- When done, run:

git flow release finish '1.0'

Tras ejecutar estos comandos el repositorio queda de la siguiente manera:

Creando la rama release/1.0

Una vez creada la rama, empezamos el proceso de corrección y depuración, que en el ejemplo que nos ocupa da como resultado varios commits a la rama release/1.0. Así queda el repositorio cuando hemos terminado de arreglar todos los bugs y estamos listos para que nuestro proyecto pase a producción:

Repositorio justo antes de subir a producción

Cerrando la rama release con git-flow

En este punto, nuestro código fuente está testado, todos los bugs corregidos (o eso pensamos) y todo está listo para entregar la versión 1.0. Para cerrar la rama, ejecutamos

$ git flow release finish 1.0

Cuando ejecutamos este comando git-flow nos va a pedir que introduzcamos tres mensajes:

  • El primero de ellos es el mensaje del merge commit resultado de incorporar los cambios de release/1.0 en master

Introducir mensaje para el merge commit

  • El segundo mensaje es el mensaje que git-flow pondrá a la etiqueta que va a crear para identificar esta versión

Introducir mensaje para la etiqueta

  • El tercero y último será el mensaje que git-flow pondrá en el merge commit resultado de incorporar la rama release/1.0 en develop

Introducir mensaje para el merge commit con la rama develop

Cuando el comando termina, se nos muestra un resumen de todas las acciones que han tenido lugar:

Salida de git-flow al cerrar un release branchEn rojo hemos indicado las acciones que git-flow ha ido ejecutando y que pueden resumirse en los siguientes comandos:

git checkout master
git merge release/1.0 --no-ff
git tag v1.0
git checkout develop
git merge release/1.0 --no-ff
git branch -d release/1.0

El repositorio queda de la siguiente manera:

Repositorio tras cerrar release/1.0

Despliegue en producción

Dado que en este ejemplo estamos trabajando con una web HTML, el despliegue en producción es muy sencillo:

  • Sincronizamos las rama master con git push
git checkout master
git push
  • En el servidor en producción ejecutamos
git checkout master
git pull

Variaciones de este flujo

Cuando estamos trabajando en la rama release, puede darse el caso de que algunos bugs sean más complicados de resolver de lo esperado. Si eso ocurre, siempre podemos crear una rama dentro de release para corregir ese bug y, una vez terminado, incorporar los cambios a la rama release.

Conclusión

En esta entrega hemos visto cómo git-flow nos ayuda a gestionar la liberación de nuevas versiones de nuestro código fuente. Creando una rama específica para la puesta a punto de la versión, conseguimos que mientras una parte del equipo está trabajando release/1.0, otra parte puede avanzar en nuevas funcionalidades usando feature branches en la rama develop.

Lo que se debe evitar es utilizar la rama release para desarrollar nuevas funcionalidades. Si esto ocurre quiere decir que hemos pasado el código a pre-producción demasiado pronto.

En la siguiente entrega veremos cómo prepara hotfixes para nuestro código en producción.

]]>
https://aprendegit.com/git-flow-release-branches/feed/ 1 487
git-flow: la rama develop y uso de feature branches https://aprendegit.com/git-flow-la-rama-develop-y-uso-de-feature-branches/ https://aprendegit.com/git-flow-la-rama-develop-y-uso-de-feature-branches/#comments Wed, 13 Mar 2013 13:16:43 +0000 https://aprendegit.com/?p=466 Seguimos con la serie de artículos sobre git-flow. Después de ver cómo pueden ayudarnos estas extensiones de git e instalarlas, vamos a empezar el desarrollo de nuestro proyecto utilizando git-flow.

Trabajaremos con una sencilla página HTML como ejemplo. No queremos complicar la explicación ni distraernos con el código fuente; el objetivo es entender el flujo que vamos a implementar con git.

Git-flow y metodologías ágiles

Los próximos artículos vamos a escribirlos en el contexto de las metodologías ágiles. Hablaremos de iteraciones, reuniones de planificación, reuniones diarias del equipo… El objetivo es poner git-flow en contexto y ver cómo nos puede ayudar.

Supongamos que ya hemos pasado por la reunión de planificación y hemos acordado en el equipo qué historias de usuario vamos a implementar en la primera iteración.

Las historias de usuario del primer sprint son las siguientes:

  • H-1: La web dispondrá de una home con un menú de acceso al resto de páginas
  • H-2: La página de inicio dispondrá de un hero con un texto y un botón de enlace al último artículo

Implementaremos la primera de las historias de forma manual y la segunda con git-flow. De esta forma entenderemos bien qué es lo que estas extensiones hacen por debajo.

Antes de empezar: git-flow-init

Dado que se trata de un proyecto nuevo, lo primero que haremos antes de empezar el desarrollo es, como no, crear el repositorio y prepararlo para usar git-flow. Para ello seguimos los siguientes pasos:

$ mkdir nuestro-proyecto
$ cd nuestro-proyecto
$ git init
$ git-flow init

No branches exist yet. Base branches must be created now.
Branch name for production releases: [master]
Branch name for "next release" development: [develop]

How to name your supporting branch prefixes?
Feature branches? [feature/]
Release branches? [release/]
Hotfix branches? [hotfix/]
Support branches? [support/]
Version tag prefix? [] v

Al ejecutar el último comando, entramos en un menú interactivo que nos va preguntando las opciones que aparecen arriba:

  • Al inicializar git-flow, nos pregunta el nombre de la rama de producción y de la rama de desarrollo (master y develop respectivamente). Seleccionamos los nombres por defecto.
  • Después nos preguntará los prefijos que asignará a las ramas de tipo feature, release, hotfix y support. Volvemos a seleccionar los nombres por defecto.
  • Por último, nos pregunta el prefijo que queramos utilizar para etiquetar las versiones.

Si no os gustan los prefijos que usa git-flow por defecto, podéis utilizar otros. En un artículo posterior veremos como cambiar a posteriori estos nombres.

¿Y en qué estado queda nuestro repositorio después de hacer esto? Aquí tenéis una captura de SourceTree:

Estado del repositorio tras ejecutar git-flow

Estado del repositorio tras ejecutar git-flow

Vemos el commit inicial así como las ramas master y develop. Desde la línea de comandos, el repositorio tiene este aspecto:

$git branch -av
* develop 87ee184 Initial commit
  master  87ee184 Initial commit

Desarrollando H-1: gestionando las ramas manualmente

En el proyecto, en una de las reuniones diarias, se decide que vamos a usar bootstrap para maquetar la web, así que en la primera historia descargaremos bootstrap, lo incluiremos en la carpeta vendor y crearemos la página de inicio (nota para los usuarios más avanzados: somos conscientes de que hay mejores maneras de añadir bootstrap al proyecto como por ejemplo usar submódulos. Usamos este enfoque más simple porque no queremos distraernos con detalles ajenos al objetivo de esta serie que es entender git-flow).

Dado que se trata de un desarrollo planificado que formará parte de un futuro release (la versión 0.1) usaremos una feature branch.

Recordamos: las feature branches nacen de la rama develop y se incorporan a esa misma rama. Así que creamos una nueva rama a partir de develop que llamamos feature-H-1:

$ git checkout -b feature-H-1 develop
$ git branch -av
  develop     87ee184 Initial commit
* feature-H-1 87ee184 Initial commit
  master      87ee184 Initial commit

Una vez creada la rama feature-H-1, hacemos la siguiente serie de commits:

  • Añadimos bootstrap al proyecto
  • Creamos la página de inicio
  • Ponemos el menú

Cuando terminamos el desarrollo de la historia H-1, este es el estado de nuestro repositorio:

Terminado el desarrollo de la historia H1

Así queda el repositorio cuando terminamos de hacer el desarrollo de la historia H-1 en la rama feature-H-1

Ya hemos terminado nuestra primera historia, así que ha llegado el momento de incorporar los cambios a la rama develop (recuerda, las feature branches se incorporan a la rama develop):

$ git checkout develop
$ git merge --no-ff feature-H-1

Si no sabes qué es la opción –no-ff y porqué la usamos, lee este artículo. Al ejecutar el comando se nos pide el mensaje para el merge commit:

Merge branch 'feature-H-1' into develop

# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.

Cuando guardamos y cerramos, este es el estado del repositorio:

Repositorio después de incorporar la rama feature-H-1

Estado del repositorio después de incorporar la rama feature-H-1

Como la rama feature-H-1 ha quedado visibles en el repositorio con un merge commit, podemos borrarla:

$ git branch -d feature-H-1
Deleted branch feature-H-1 (was 765ce08).

Pues bien, ya hemos terminado nuestra primera historia, vamos a por la segunda.

Desarrollando H-2: gestionando las ramas con git-flow

Para hacer esta historia, necesitaremos crear una nueva feature branch que llamaremos feature-H-2. Esta vez usaremos git-flow:

$ git-flow feature start H-2
Switched to a new branch 'feature/H-2'

Summary of actions:
- A new branch 'feature/H-2' was created, based on 'develop'
- You are now on branch 'feature/H-2'

Now, start committing on your feature. When done, use:

     git flow feature finish H-2

Notar que no necesitamos poner el prefijo “feature” para crear la rama, git-flow lo hace por nosotros. El propio git-flow se encarga de activar la rama feature/H-2 y de decirnos qué tenemos que hacer cuando terminemos. El estado del repositorio después de ejecutar el comando es el siguiente:

Usando git-flow para crear feature/H-2

Estado del repositorio después de crear la rama feature/H-2 con gitflow

Con la rama creada, nos ponermos a trabajar. Implementamos el hero de la página de inicio y hacemos los commits correspondientes:

rama feature/H-2 antes de cerrarla

Estado de la rama feature/H-2 una vez terminado el desarrollo

Así vemos las ramas desde la línea de comandos:

$ git branch -av
  develop     b7bd517 Merge branch 'feature-H-1' into develop
* feature/H-2 4604003 Introduciendo el texto definitivo
  master      87ee184 Initial commit

Si en un momento dado queréis listar las ramas de tipo feature desde la línea de comandos, basta con ejecutar git flow feature:

$ git flow feature
* H-2

Esto mismo es aplicable para las ramas hotfix, release y support.

Continuamos con el desarrollo. Revisamos y testamos nuestro código y cuando vemos que hemos terminado, utilizamos git-flow para cerrar la rama:

$ git flow feature finish H-2
Switched to branch 'develop'
Merge made by the 'recursive' strategy.
  | 7 +++++++
 1 file changed, 7 insertions(+)
Deleted branch feature/H-2 (was 4604003).

Summary of actions:
- The feature branch 'feature/H-2' was merged into 'develop'
- Feature branch 'feature/H-2' has been removed
- You are now on branch 'develop'

Es decir, hemos vuelto a la rama develop, se ha incorporado la rama feature/H-2 a develop y la feature branch se ha borrado. Después de ejecutar el comando, este es el resultado:

Estado del repositorio tras cerrar la feature branch

Estado del repositorio tras cerrar la feature branch

Si os fijáis, hemos hecho lo mismo ejecutando menos comandos.

En esta captura vemos cómo en este flujo de trabajo queda reflejado en la historia del repositorio de forma bastante limpia y clara, cuándo se empezó y finalizó el desarrollo de cada una de las feature branches.

Ahora toca prepararlo todo para hacer el release a producción, aunque eso lo haremos en la siguiente entrega.

Hemos subido este repositorio a nuestra cuenta de github. Podéis verlo en este enlace: https://github.com/aprendegit/articulo-sobre-gitflow

]]>
https://aprendegit.com/git-flow-la-rama-develop-y-uso-de-feature-branches/feed/ 15 466
Organizando las ramas en carpetas https://aprendegit.com/organizando-las-ramas-en-carpetas/ https://aprendegit.com/organizando-las-ramas-en-carpetas/#comments Mon, 11 Mar 2013 18:49:45 +0000 https://aprendegit.com/?p=458 Si en el momento de crear una rama utilizas como nombre una ruta, como por ejemplo “mi-carpeta-de-ramas/nombre-de-rama”, verás que en la carpeta .git/refs/heads de tu repositorio se creará una subcarpeta “mi-carpeta-de-ramas”. Dentro de la misma verás el fichero “nombre-de-rama” con la referencia. Es decir, git convierte la cadena con formato de ruta que pasamos como argumento en una estructura real de carpetas.

Esta forma de crear ramas soporta subcarpetas, es decir, si creamos una rama que se llame carpeta1/carpeta2/mirama:

$ git checkout -b carpeta1/carpeta2/mirama

git creará el fichero .git/refs/heads/carpeta1/carpeta2/mirama con la referencia.

¿Y cómo muestra SourceTree las ramas creadas de esta manera?

Organizando las ramas en carpetas

Esta forma de clasificar las ramas en carpetas es especialmente útil cuando trabajamos con ramas para hacer hotfixes, corregir bugs o desarrollar funcionalidades organizadas en historias de usuario.

Desde la interfaz de línea de comandos, así es como veríamos las ramas:

$ git branch -av
   carpeta1/carpeta2/mirama 4604003 Introduciendo el texto definitivo
   develop                  b7bd517 Merge branch ‘feature-H-1’ into develop
*  feature/H-2              4604003 Introduciendo el text definitive
   master                   87ee184 Initial commit

Si quisiésemos ver sólo las ramas feature, podemos usar la opción –list:

$ git branch --list feature*
feature/H-2

Para borrar la rama, usamos el comando git-branch con la ruta completa a la rama:

$ git branch -D carpeta1/carpeta2/mirama

Un truco muy sencillo que nos ayuda a organizar las ramas un poco mejor, especialmente útil si estáis usando SourceTree.

]]>
https://aprendegit.com/organizando-las-ramas-en-carpetas/feed/ 4 458
Instalación de git-flow en linux, windows y mac https://aprendegit.com/instalacion-de-git-flow/ https://aprendegit.com/instalacion-de-git-flow/#comments Mon, 04 Mar 2013 08:00:49 +0000 https://aprendegit.com/?p=439 Continuamos con la serie de artículos sobre git-flow. En la entrega anterior conocimos a Vincent Driessen y su flujo de trabajo. Hoy vamos a ver cómo instalar las extensiones en nuestra máquina.

Instalación de git-flow

Mac

Si habéis instalado git a través de homebrew o macports, la instalación se muy sencilla:

$ brew install git-flow
$ port install git-flow

Si tienes problemas con XCode 4.2 y Macports 2.0.4, sigue las instrucciones que se dan en la página de git-flow. También es posible utilizar la instalación a través de wget usando el script de instalación de Rick Osborne:

wget --no-check-certificate -q -O - https://github.com/nvie/gitflow/raw/develop/contrib/gitflow-installer.sh | sudo bash

Linux

git-flow tiene paquetes para distribuciones basadas en debian y Ubuntu. Utiliza el gestor de paquetes de tu distribución, busca el paquete e instálalo. En debian/Ubuntu, el paquete se llama git-flow, en fedora gitflow y en Archlinux gitflow-git.

Si tu distribución no tiene paquete disponible en los repositorios oficiales como ocurre con centos 5, la mejor manera de instalarlo es utilizar el script de instalación:

wget --no-check-certificate -q -O - https://github.com/nvie/gitflow/raw/develop/contrib/gitflow-installer.sh | sudo bash

Windows

Las instalación es un poco más tediosa, aunque no es complicada. Seguiremos las instrucciones que se dan en la página de git-flow aunque con un poco más de detalle:

 util-linux-ng para windows

  • Descomprimimos los dos ficheros descargados: util-linux-ng-[version]-bin.zip y util-linux-ng-[version]-dep.bin
  • Dentro de la carpeta “util-linux-ng-[version]-bin”, copiamos el fichero bin/getopt.exe a la carpeta C:\Program Files\Git\bin
  • Dentro de la carpeta “util-linux-ng-[version]-dep”, copiamos  el fichero bin/libintl3.dll a la carpeta C:\Program Files\Git\bin
  • Nota: en mi caso, tuve que hacer esto desde la línea de comandos lanzando un terminal de git bash como administrador de la máquina

descomprimiendo getopt.exe y libintl2.dll

  • Una vez copiados los ficheros, se clona el repositorio git://github.com/nvie/gitflow.git. Puedes clonarlo utilizando la línea de comandos o tu cliente gráfico favorito.
  • Por último, abrimos una terminal de windows dentro del repositorio que acabamos de clonar y ejecutamos el comando contrib/msysgit-install.cmd “C:\Program Files\Git” (sustituyendo la ruta si en tu máquina la tienes en una carpeta diferente). Nota: este terminar también tuve que lanzarla como usuario administrador, mi usuario de trabajo no tiene permiso en la carpeta C:\Program Files\Git.

msysgit-install.cmd

Listo, para confirmar que lo tenemos instalado, abrimos git bash, creamos una carpeta vacía y dentro inicializamos el repositorio con el siguiente comando:

 

$ git flow init

Si todo ha ido bien, esto es lo que deberíamos observar:

Comprobando la instalación

]]>
https://aprendegit.com/instalacion-de-git-flow/feed/ 10 439
¿Qué es git-flow? https://aprendegit.com/que-es-git-flow/ https://aprendegit.com/que-es-git-flow/#comments Thu, 28 Feb 2013 09:00:41 +0000 https://aprendegit.com/?p=425 Empezamos una serie de artículos sobre git-flow, conjunto de extensiones de git que facilitan la gestión de ramas y flujos de trabajo.

Si quieres seguir esta serie, debes disponer de una máquina con git instalado:

  • Windows: msysgit que puedes descargar de este enlace
  • Mac: a través de homebrew o macports
  • Linux: a través del gestor de paquetes de tu distribución

Flujos de trabajo

Hace unos días participé en el Open Space de Calidad del Software organizado en Madrid este mes de febrero. En la reunión se abordaron varios temas que iban desde responder a preguntas como ¿qué se calidad del software? ¿cuánto cuestan los tests funcionales? o ¿cómo hacer testing de desarrollos para dispositivos móviles? pasando por otros tan exóticos como el Pirata Roberts, llegando incluso a plantearse hasta la eliminación de los responsables de calidad de la faz de la tierra.

En casi todas las conversaciones en las que tuve la oportunidad de participar había un denominador común: las ramas. Se hablaba de ramas para hacer hot-fixes urgentes, ramas para desarrollar nuevas versiones separadas de las ramas maestras donde está la versión en producción. Ramas para probar nuevas versiones, ramas y repositorios para trabajar con proveedores externos, ramas para hacer pruebas en pre-producción, ramas para que los departamentos de calidad hagan sus pruebas antes de liberar nuevas versiones. Con git podemos crear ramas “como churros” y ese fin de semana tuve la oportunidad de compartir con varios colegas de profesión cómo utilizar las ramas para hacer el bien. Sin embargo, esta facilidad para crear ramas también se puede utilizar para hacer el mal y sembrar el terror. Más de una vez he visto ramas creadas sin ningún criterio, sin ningún flujo de información detrás que las sustente. Esta situación suele llevar al repositorio al caos más absoluto.

Para no acabar en el caos, debemos establecer unas “reglas del juego” que todo el equipo debe respetar. Aunque a grandes rasgos casi todos los proyectos pueden utilizar unas reglas de base comunes, las reglas deben ser flexibles para adaptarse a los cambios que puedan surgir en el tablero de juego; al fin y al cabo, las necesidades y particularidades de cada equipo, empresa o proyecto no son las mismas.

¿Y cuáles son estas reglas base comunes? En enero de 2010 Vincent Driessen publicó en su blog un artículo en el que compartía con la comunidad un flujo de trabajo que a él le estaba funcionando: “A successful Git branching model”. Como él mismo cuenta en el artículo (te recomiendo encarecidamente que lo leas) Vincent propone una serie de “reglas” para organizar el trabajo del equipo.

Ramas master y develop

El trabajo se organiza en dos ramas principales:

  • Rama master: cualquier commit que pongamos en esta rama debe estar preparado para subir a producción
  • Rama develop: rama en la que está el código que conformará la siguiente versión planificada del proyecto

Cada vez que se incorpora código a master, tenemos una nueva versión.

Además de estas dos ramas, Se proponen las siguientes ramas auxiliares:

  • Feature
  • Release
  • Hotfix

Cada tipo de rama, tiene sus propias reglas, que resumimos a continuación.

Feature or topic branches

feature branches

fuente: nvie http://nvie.com/posts/a-successful-git-branching-model/

  • Se originan a partir de la rama develop.
  • Se incorporan siempre a la rama develop.
  • Nombre: cualquiera que no sea master, develop, hotfix-* o release-*

Estas ramas se utilizan para desarrollar nuevas características de la aplicación que, una vez terminadas, se incorporan a la rama develop.

Release branches

  • Se originan a partir de la rama develop
  • Se incorporan a master y develop
  • Nombre: release-*

Estas ramas se utilizan para preparar el siguiente código en producción. En estas ramas se hacen los últimos ajustes y se corrigen los últimos bugs antes de pasar el código a producción incorporándolo a la rama master.

Hotfix brancheshotfix branches

  • Se origina a partir de la rama master
    fuente http://nvie.com/posts/a-successful-git-branching-model/
  • Se incorporan a la master y develop
  • Nombre: hotfix-*

Esas ramas se utilizan para corregir errores y bugs en el código en producción. Funcionan de forma parecida a las Releases Branches, siendo la principal diferencia que los hotfixes no se planifican.

¿Qué es git-flow?

Si queremos implementar este flujo de trabajo, cada vez que queramos hacer algo en el código, tendremos que crear la rama que corresponda, trabajar en el código, incorporar el código donde corresponda y cerrar la rama. A lo largo de nuestra jornada de trabajo necesitaremos ejecutar varias veces al día los comandos git, merge, push y pull así como hacer checkouts de diferentes ramas, borrarlas, etc. Git-flow son un conjunto de extensiones que nos ahorran bastante trabajo a la hora de ejecutar todos estos comandos, simplificando la gestión de las ramas de nuestro repositorio.

La flexibilidad de git…y el sentido común

Las «reglas» que Vincent plantea en su blog son un ejemplo de cómo git nos permite implementar un flujo de trabajo para nuestro equipo. Estas no son reglas absolutas, bien es cierto que pueden funcionar en un gran número de proyectos, aunque no siempre será así. Por ejemplo ¿qué pasa si tenemos que mantener dos o tres versiones diferentes de una misma aplicación? digamos que tenemos que mantener la versión 1.X, la 2.X y la 3.X. El tablero de juego es diferente así que necesitaremos ampliar y adaptar estas reglas para poder seguir jugando.

git es una herramienta que nos permite modificar estas reglas y, lo que es más importante, irlas cambiando y adaptando a medida que el proyecto avanza y el equipo madura. Una vez más, una buena dosis de sentido común será nuestra mejor aliada para responder las preguntas que nos surjan durante el camino.

Referencias:

]]>
https://aprendegit.com/que-es-git-flow/feed/ 23 425
Forzando los merge commits https://aprendegit.com/forzando-merge-commits/ https://aprendegit.com/forzando-merge-commits/#comments Mon, 18 Feb 2013 17:27:43 +0000 https://aprendegit.com/?p=409 Una de las preguntas más habituales que se hacen en los cursos de git que imparto regularmente, y que también se me ha planteado en algunas de las reuniones de desarrolladores en las que participo es la siguiente: ¿Cómo evito un fast-forward para dejar constancia en el repositorio de dónde empieza y termina una rama?

Forzar merge commits

Lo más claro, como siempre, es verlo con un ejemplo. Imaginad que llegáis por la mañana al trabajo y empezáis como siempre a picar código como locos en la rama devel. De repente surge la necesidad de atender un bug. Siguiendo las buenas prácticas, lo que haremos será crear una rama HotFix, arreglar el problema haciendo cuantos commits necesitemos a esa rama y finalmente hacer un merge a la rama que corresponda cuando terminemos de corregir el bug.

En la siguiente captura se muestra el estado del repositorio justo después de haber hecho el último commit a la rama hotfix_14523 que arregla el problema en cuestión:

Estado del repositorio al terminar el hotfix 15423

Si en este momento se hace un merge de la rama hotfix_15423 a la rama devel, se hará un fast-forward:

$ git checkout devel
$ git merge hotfix_15423
Updating 2d1d1c4..2b9d126
Fast-forward
Gemfile | 2 ++
app/views/home/.erb | 1 +
2 files changed, 3 insertions(+)

Así queda el grafo después de hacer el merge:Estado del repositorio tras hacer un merge con fast-forward de la rama hotfix_15423

Como vemos, mirando la historia del repositorio, no queda constancia de cuándo se empezó el desarrollo de la rama hotfix_15423 y cuándo se incorporó a la rama devel. Una solución podría ser etiquetar los commits correspondientes, como se muestra en la siguiente captura:Usando etiquetas para indicar el inicio y final de una rama

Esta solución es válida cuando tenemos pocas ramas. Si tenemos muchas ramas de las que queramos saber su inicio y final, podemos acabar con un número de etiquetas difícil de gestionar.

Forzar un merge commit

Volvamos a la situación inicial:

$ git reset --hard 2d1d1c4
HEAD is now at 2d1d1c4 Update README.rdoc

Estado del repositorio al terminar el hotfix 15423

En esta situación, volvemos a ejecutar el merge de la siguiente forma:

$ git merge --no-ff hotfix_15423 -m'Incorporando rama hotfix_15423'
Merge made by the 'recursive' strategy.
 Gemfile | 2 ++
 app/views/home/.erb | 1 +
 2 files changed, 3 insertions(+)

Después de ejecutar el comando, este es el estado del repositorio:

Incoporando hotfix15423 en devel con la opción --no-ff

Haciéndolo de esta forma, en lugar de hacerse un fast-forward, vemos que se crea un merge-commit, lo que resulta en una bifurcación que indica claramente el fin y el inicio de la rama hotfix_15423.

Si sois de los que os gusta ver claramente dónde empiezan y terminan vuestras ramas, este pequeño truco es resultará de utilidad.

]]>
https://aprendegit.com/forzando-merge-commits/feed/ 4 409
¿Qué es un pull request? https://aprendegit.com/que-es-un-pull-request/ https://aprendegit.com/que-es-un-pull-request/#comments Thu, 14 Feb 2013 15:23:57 +0000 https://aprendegit.com/?p=378 En esta entrada, la tercera de una serie de tres, explicamos qué es un pull request y cómo funciona en github.

Recordamos brevemente qué es lo que nuestros usuarios aalbagarcia y aprendegit-user1 hicieron en las dos entradas anteriores:

  • El usuario aalbagarcia crea un repositorio en github: https://github.com/aprendegit/fork
  • El usuario aprendegit-user1 crea un fork (bifurcación) para trabajar en él: https://github.com/aprendegit-user1/fork
  • Los dos usuarios realizan modificaciones cada uno en su repositorio, cada uno de ellos hace un commit y posteriormente un push. Cada uno sube los cambios a su correspondiente repositorio
  • El usuario aprendegit-user1 configura un repositorio remoto adicional (upstream) e incorpora, haciendo un merge, los cambios en el código que hizo aalbagarcia. Después de hacer el merge, aprendegit-user1 hace un push para actualizar su repositorio remoto.

Lo último que nos falta por hacer es que el usuario aalbagarcia, que es el propietario del repositorio inicial (https://github.com/aprendegit/fork), incorpore el trabajo del usuario aprendegit-user1 que se encuentra en el fork https://github.com/aprendegit-user1/fork.

¿Qué es un pull request?

Un pull request es una petición que el propietario de un fork de un repositorio hace al propietario del repositorio original para que este último incorpore los commits que están en el fork. En el caso que nos ocupa, el usuario aprendegit-user1 le enviará la petición a aalbagarcia para que este último incorpore los commits que tiene en su fork.

Lo primero que hará el usuario aprendegit-user1 será crear una rama que apuntará al último commit que ha hecho y que contiene las modificaciones a la página de inicio. El procedimiento es el de siempre:Creando una rama antes de hacer el pull request

  • Se selecciona a la izquierda la rama master y se hace clic sobre el último commit de la rama
  • Se hace click sobre el icono «Branch»
  • Se introduce el nombre de la rama, en este maso mycommits
  • Se hace clic sobre «Create Branch»

Si se usa la línea de comandos, la secuencia sería:

$ git checkout master
Switched to branch 'master'
$ git checkout -b mycommits
Switched to a new branch 'mycommits'

Una vez creada la rama, el usuario aprendegit-user1 hace push de la rama «mycommits» a su fork:

  • Se selecciona la rama mycommits a la izquierda asegurándonos de que esta queda como rama activa haciendo doble clic sobre ella
  • Se selecciona el último commit de la rama
  • Se hace clic sobre el icono Push de la bara de herramientas
  • En el desplegable, se selecciona en la columna «Push?» la rama mycommits y se marca en la columna de la derecha (Track) la rama local como tracking branch.
  • Se hace clic sobre OK.
La secuencia de comandos sería 
$ git checkout mycommits
$ git push -u origin mycommits
Total 0 (delta 0), reused 0 (delta 0)
To git@github-aprendegit-user1:aprendegit-user1/fork
    * [new branch] mycommits -> mycommits
Branch mycommits set up to track remote branch mycommits from origin.

Al terminar, el estado del repositorio es el siguiente:

Solicitando el pull request

En este momento, el usuario aprendegit-user1 accede a su cuenta de github y abre en su navegador la página de su fork https://github.com/aprendegit-user1/fork.

Una vez hemos accedido, cambiamos a la rama mycommits como se indica en la siguiente captura:Acceder a github y cambiar a la rama mycommits

Una vez se ha cambiado a la rama mycommits, aprendegit-user1 hace clic sobre el botón «Pull Request»El botón pull request

Esta es la pantalla que se presenta a aprendegit-user1:Pantalla para enviar el pull request

En la parte superior, aprendegit-user1 selecciona la rama que contiene los commits que aalbagarcia (el destinatario del pull request) debe incorporar en su repositorio. En la parte de abajo se ven tres pestañas en las que se puede:

  • Poner un título y descripción al pull request
  • Ver los commits que aalbagarcia incorporará al repositorio si acepta el pull request (pestaña Commits)
  • Ver un diff que los cambios que se incluyen en los commits (pestaña Files Changed)

Es una buena práctica poner un título y descripción que reflejen el motivo del commit. Estos pull requests los ven todos los colaboradores del proyecto (si el proyecto es público lo ve todo el mundo) Así que aunque aalbagarcia y aprendegit-user1 hayan hablado por teléfono acerca de este pull request, el resto del mundo seguramente no ha escuchado la conversación. Pensando en el resto del equipo, aprendegit-user1 incluye un mensaje descriptivo de qué contiene el pull request. Cuando termina, hace clic sobre el botón «Send Pull Request». Esta es la pantalla a la que aprendegit-user1 llega después de enviarlo:Pantalla del pull request que ve aprendegit-user1

La captura es bastante sencilla de entender. Vemos el título y descripción introducidos por aprendegit-user1, los commits y una interfaz para intercambiar comentarios con el equipo.

Aunque en pequeño, se nos indica qué es lo que tendríamos que hacer para añadir commits a este pull request: enviar más commits a la rama «mycommits» del fork de aprendegit-user1.

¿Porqué podemos necesitar añadir más commits? Imagínate que el equipo revisa el pull request y se determina que todavía queda trabajo pendiente de hacer. ¿Cómo se procede? aprendegit-user1 continúa el trabajo en la rama rama «mycommits» de su fork y cuando termina lo sube a su repositorio remoto. El pull request se actualiza y todo el equipo puede ver el nuevo código. Esto lo veremos en detalle en otro artículo, de momento, seguimos con el proceso.

Aceptando el pull request

Cuando aprendegit-user1 envía el pull request, Github envía al propietario un email avisándole de que tiene un pull request listo para revisar. En este caso, el usuario aalbagarcia recibe el email, accede a su cuenta de Github y va a su repositorio https://github.com/aprendegit/fork:Página del propietario del repositorio después del pull request

En esta pantalla, seleccionamos la pestaña «Pull Requests» y accedemos a una interfaz que nos muestra todos los que tenemos. Dado que este es el primero, en este listado seleccionamos el único que hay:Listado de pull requests del repositorio

Cuando aalbagarcia selecciona «Añadiendo logotipo», accede a una pantalla muy parecida a la que hemos visto con el usuario aprendegit-user1. En la siguiente captura indico cuáles son las diferencias:La página del pull request vista por el propietario

Las diferencias son:

  • Existe un botón «Merge pull request» que el propietario aalbagarcia utilizará para incorporar los commits al repositorio
  • Existe un botón «Close» que el propietario utiliza para cerrar el pull request sin incorporar los cambios

Una vez revisado el código y confirmado que todo está bien, aalbagarcia hace clic sobre el botón «Merge Pull Request». En ese momento Github le pedirá que introduzca un comentario para el merge commit. Una vez introducido, aalbagarcia hace clic sobre el botón «Commit merge» y ya está, Github automáticamente cierra el pull request. También envía un email a los dos interesados (aalbagarcia y aprendegit-user1) avisándoles de que se han incorporado los cambios en el repositorio.

Si volvéis a la página de commits del repositorio en github (https://github.com/aprendegit/fork/commits/master) veréis que tras hacer el pull request, aparece un nuevo commit en el repositorio:Merge commit tras el pull request

¿Cómo quedan los repositorios de aalbagarcia y aprendegit-user1?

En este momento, el repositorio remoto de aalbagarcia ya contiene el merge commit que se ha creado a través del pull request. La pregunta es ¿el de aprendegit-user1 también? ¿verán estos nuevos commits los dos usuarios?

…la respuesta es que, efectivamente, no lo verán hasta que hagan un fetch en sus respetivos repositorios. Tras hacer los dos usuarios un fetch de todos sus repositorios remotos (recuerda que aprendegit-user1 tiene 2 remotos,  origin y upstream) así quedan sus respectivas copias de trabajo:

Copias de trabajo después del pull request y el fetch

Para terminar:

  • aalbagarcia tiene que hacer un merge de la rama origin/master a la rama master
  • aprendegit-user1 tiene que hacer un merge de la rama upstream/master a la rama master y después hacer un push de su rama master

Una vez hecho esto, los repositorios quedan de la siguiente manera:

Copias de trabajo después de macer merge de las ramas remotas

Y como podéis ver, están sincronizados.

¿Quieres hace un pull request?

Si quieres hacer tú mismo el proceso para ver cómo funciona, ve al repositorio https://github.com/aprendegit/fork, haz un fork y envíanos las modificaciones siguiendo los pasos que hemos seguido en esta serie de artículos. Si tienes alguna duda no dudes en preguntarnos.

Seguiremos hablando de pull requests, aunque eso ya será en otros artículos.

]]>
https://aprendegit.com/que-es-un-pull-request/feed/ 43 378
Mantener tu fork al día https://aprendegit.com/mantener-tu-fork-al-dia/ https://aprendegit.com/mantener-tu-fork-al-dia/#comments Thu, 31 Jan 2013 10:01:23 +0000 https://aprendegit.com/?p=359 En la entrada anterior vimos qué significa hacer un fork y cómo hacerlo desde github. Resumo brevemente los pasos que dimos:

  1. El usuario aprendegit-user1 hizo un fork del repositorio https://github.com/aprendegit/fork
  2. El usuario aprendegit-user1 modificó la página de inicio del proyecto (ficticio) que estamos usando e hizo un push de sus modificaciones a su fork (https://github.com/aprendegit-user1/fork)
  3. Vimos cómo las modificaciones que aprendegit-user1 hizo a su fork no se «sincronizan» automáticamente con el repositorio original

A la vez que prendegit-user1 ha avanzado con su tarea, nuestro primer usuario (aalbagarcia) y administrador del repositorio original (https://github.com/aprendegit/fork), ha continuado también trabajando. A la vez que el usuario aprendegit-user1 ha cambiado la página de inicio, aalbagarcia ha añadido un nuevo campo a la clase Post de nuestro blog. Cuando aalbagarcia ha acabado su trabajo, lo sube al repositorio original (https://github.com/aprendegit/fork) haciendo un push.

El estado de ambos repositorios es el siguiente:

Situación de los repositorios de aalbagarcia y aprendegit-user1

En la parte superior de la imagen tenemos una captura del estado del repositorio de aprendegit-user1 (fork) y en la parte inferior una captura del repositorio de aalbagarcia. Vemos que cada uno tiene en su repositorio su trabajo. Ha llegado la hora de sincronizarlos, cosa que haremos en dos pasos:

  • Paso 1: aprendegit-usuario1 traerá a su fork el trabajo de aalbagarcia (en este caso el commit c3e3f5b que podéis ver arriba)
  • Paso 2: aalbagarcia incluirá en el repositorio original el trabajo de aprendegit a través de un pull request.
¡Empezamos por el Paso 1!

Trabajando con múltiples repositorios remotos

Lo primero que aprendgit-user1 tiene que hacer es añadir el repositorio original a su lista de remotes. El usuario aprendegit-user1 abre SourceTree y va a Repository->Repository settings:

Preferencias del repositorio

Dentro de la pantalla de «Repository settings», selecciona la pestaña «Remotes». En esta pantalla está su fork (origin). Se hace clic sobre el botón «Add» para añadir el repositorio original:

Seleccionando nombre y URL de nuevo remote

En la ventana emergente, se introduce «upstream» como nombre del remote (upstream es una sugerencia, podéis poner otro si lo preferís) y se pone la URL del repositorio original (https://github.com/aprendegit/fork). Rellenado el formulario, se hace clic en OK y de nuevo clic en OK en la ventana de preferencias. Una vez cerradas todas las ventanas de diálogo, el repositorio de aprendegit-user1 tendrá este aspecto:

Aspecto del repositorio tras añadir upstream

En la sección «REMOTES» aparece junto a origin el nuevo origen upstream, pero si se despliega el contenido veremos que está vacío. Pulsando sobre «Fetch» descargaremos el contenido del repositorio remoto «upstream»:

Fetch

…y cuando el fetch finaliza, el repositorio queda de la siguiente manera:

Situación del fork después de hacer fetch de upstream

El fork de aprendegit-user1 ya muestra las ramas del repositorio original ¿véis el commit c3e3f5b? ¡ya lo tenemos ahí!. ¿Qué nos falta? Pues tan sólo hacer un merge de la rama upstream/master a la rama master para «sincronizar» el fork con el original. Aprendegit-user1 selecciona el commit correspondiente a nuestra rama master (en la captura anterior ya está seleccionado) y hace clic sobre el icono merge en la barra de herramientas:

Incorporando (merge) del repositorio original al fork

En la pantalla de merge, se selecciona el commit correspondiente a la rama upstream/master y se hace clic sobre OK. Cuando el merge termina, así queda el repositorio de aprendegit-user1:

Estado del fork tras incorporar los cambios de aalbagarcia

¡Ya está! aprendegit-user1 ya tiene su rama sincronizada con el repositorio original. Ahora sólo queda hacer un push; como se puede ver el propio SourceTree nos avisa de que la rama master de aprendegit-user1 está dos commits por delante de la rama remota origin/master. Basta con hacer clic sobre el icono push para que aprendegit-user1 actualice su repositorio remoto.

Cuando aprendegit-user1 termina, así quedan su repositorio (fork) y el de aalbagarcia (original):

Estado del fork y repositorio original tras el merge

¡aalbagarcia todavía no tiene en su repositorio el trabajo de aprendegit-user1! Para eso, aprendegit-user1 hará un pull request… en la siguiente entrada.

¡Happy gitting!

]]>
https://aprendegit.com/mantener-tu-fork-al-dia/feed/ 27 359
Fork de repositorios en Github https://aprendegit.com/fork-de-repositorios-para-que-sirve/ https://aprendegit.com/fork-de-repositorios-para-que-sirve/#comments Tue, 29 Jan 2013 08:39:17 +0000 https://aprendegit.com/?p=337 ¿Qué es un fork?

La palabra fork se traduce al castellano, dentro del contexto que nos ocupa, como bifurcación. Cuando hacemos un fork de un repositorio, se hace una copia exacta en crudo (en inglés «bare») del repositorio original que podemos utilizar como un repositorio git cualquiera. Después de hacer fork tendremos dos repositorios git idénticos pero con distinta URL. Justo después de hacer el fork, estos dos repositorios tienen exactamente la misma historia, son una copia idéntica. Finalizado el proceso, tendremos dos repositorios independientes que pueden cada uno evolucionar de forma totalmente autónoma. De hecho, los cambios que se hacen el repositorio original NO se transmiten automáticamente a la copia (fork). Esto tampoco ocurre a la inversa: las modificaciones que se hagan en la copia (fork) NO se transmiten automáticamente al repositorio original.

¿Y en qué se diferencia un fork de un clon?

Cuando hacemos un clon de un repositorio, te bajas una copia del mismo a tu máquina. Empiezas a trabajar, haces modificaciones y haces un push. Cuando haces el push estás modificando el repositorio que has clonado.

Cuando haces un fork de un repositorio, se crea un nuevo repositorio en tu cuenta de Github o Bitbucket, con una URL diferente (fork). Acto seguido tienes que hacer un clon de esa copia sobre la que empiezas a trabajar de forma que cuando haces push, estás modificando TU COPIA (fork). El repositorio original sigue intacto. Lo vamos a ver en breve con un ejemplo.

¿Para qué sirve?

Tiene varios usos. El más común es el de permitir a los desarrolladores contribuir a un proyecto de forma segura.

¿Porqué decimos de forma segura? Imaginaos un super proyecto como puede ser el código fuente de Apache. ¿Cómo se trabajaba antes de existir git? con Subversion o CVS existía un servidor centralizado que tenía dos tipos de usuarios: lo que podían «escribir» en el repositorio (subir cambios al código fuente) y los que sólo podían «leer» el repositorio. Estos últimos sólo podían bajarse el código a su máquina y podían modificarlo sólo en su copia local. No podían subir ninguna modificación al servidor central.

¿Qué tenías que hacer para contribuir? Tenías que solicitar permiso de escritura y que alguien te lo diese. Una vez te lo concedían, ya podías subir tus modificaciones y, por supuesto, liarla si no sabías lo que estabas haciendo. Otra opción era enviar parches, trabajar con ramas… había varias formas pero todas bastante engorrosas.

Además, este procedimiento de dar acceso de escritura a un repositorio centralizado es un poco arriesgado. Siguiendo con el ejemplo que he puesto de Apache ¿cómo sé yo, responsable del repositorio, que esta persona que está a 10000Km de mí en la otra punta del planeta sabe lo que está haciendo? ¿puedo confiar en él?. Al final, contribuir a un proyecto se convertía en una tarea tediosa tanto para el que pretendía contribuir como para el que lo tenía que gestionar. Y no hablemos de lo divertido que era hacer un merge…

Git, al tratarse de un sistema distribuido, resuelve este tipo de problemas de una forma muy elegante a través de los forks. Digamos que Pepito es una persona quiere contribuir al proyecto. Ha encontrado un bug y sabe cómo corregirlo. Como propietario del repositorio me interesa que Pepito pueda enviarme el parche de forma rápida, que no pierda mucho tiempo. Si es así ¡Pepito estará encantado de colaborar con nosotros! ;-). Además, necesito que el proceso sea ágil, no quiero tener que invertir 5 horas de mi tiempo cada vez que tenga que hacer un merge del trabajo que Pepito me envíe. ¿Cómo resuelve git el problema?

  1. Pepito hace un fork de mi repositorio, para lo que sólo necesito darle permiso de lectura.
  2. Pepito trabaja en SU COPIA (fork) del repositorio. Como es suya, puede hacer lo que quiera, la puede borrar, corromper, dinamitar, reescribir la historia del proyecto… nos da lo mismo, es SU COPIA (fork).
  3. Cuando Pepito termina de programar y testear el parche, me avisa de que ya lo tiene y me dice «En la rama parche_de_pepito de MI COPIA (fork), tienes el parche que corrige el Bug XXXX».
  4. Yo voy a su repositorio, miro lo que ha hecho y si está bien lo incorporo (merge) a mi repositorio, que es el original.

Las ventajas de este proceso son las siguientes:

  1.  Pepito trabaja con SU COPIA. En ningún momento le tengo que dar acceso al repositorio central.
  2. El proceso de incorporación de los cambios de Pepito es muy sencillo. Si no hay conflictos en los ficheros puede que sea tan simple como ejecutar un par de comandos git.
  3. Pepito tiene muy fácil contribuir, no le cuesta esfuerzo.
  4. Yo puedo gestionar muy fácilmente las contribuciones de muchas personas ¡me cuesta muy poco trabajo!
Ahora cierra los ojos e imagina que esto mismo lo pudieses hacer con tus compañeros de trabajo, en tu equipo…

Haciendo Fork de un repositorio en Github

Bueno, vamos a ver esto con un ejemplo práctico. La situación es la siguiente: en nuestra organización, www.aprendegit.com, tenemos un repositorio de un proyecto RubyOnRails y que usaremos a modo de ejemplo. Este repositorio se encuentra en la siguiente URL: https://github.com/aprendegit/fork. Podéis reproducir los pasos que vamos a dar a continuación con vuestra cuenta de github.

Para ayudarnos con el desarrollo de este proyecto, contamos con la ayuda de varias personas:

  1. El usuario aalbagarcia (que soy yo) y que es uno de los administradores del repositorio y de la organización.
  2. El usuario aprendegit-user1, que es un colaborador altruista que quiere ayudarnos con la web.
  3. Vosotros: si hacéis el tutorial y seguís los pasos (tened en cuenta que habrá dos entregas más) acabaréis enviándonos vuestras «mejoras ficticias» a través de un pull request.

No dudamos de las buenas intenciones de aprendegit-user1 ni de sus capacidades y aptitudes (ni de las vuestras tampoco). Aún así, siguiendo las buenas prácticas en el uso de git, aprendegit-user1 sólo tendrá permiso de lectura en el repositorio https://github.com/aprendegit/fork.

Si no tiene permiso de escritura, el usuario aprendegit-user1 podrá clonar el repositorio (porque es público) pero no podrá hacer un push. De poco le va a servir clonarlo y trabajar sobre él si luego no va a poder hacer un push ¿qué debe hacer? Hacer un fork.

El usuario aprendegit-user1 va a github, accede con su usuario y contraseña y abre la URL del repositorio original https://github.com/aprendegit/fork

En la página del repositorio, aprendegit-user1 hace clic sobre el botón fork. Al hacer clic, Github va a crear un nuevo repositorio en su cuenta que es una copia del repositorio aprendegit/fork:

github está haciendo un fork del repositorio de aprendegit

Cuando el proceso de forking termina (puede durar varios minutos si el repositorio que estamos bifurcando es muy grande) aprendegit-user1 acaba en la siguiente pantalla:

 

Este repositorio es una copia del original (https://github.com/aprendegit/fork). Si comparáis la historia de los dos repositorios veréis que es idéntica.

Este nuevo repositorio (https://github.com/aprendegit-user1/fork) es el que nuestro usuario aprendegit-user1 va a utilizar para trabajar y, cuando termine, enviarnos sus modificaciones.

aprendegit-user1 empieza a colaborar con nosotros

La primera tarea que aprendegit-user1 va a hacer como colaborador nuestro es modificar la página de inicio añadiendo nuestro logo. Para ello, clonará su fork y trabajará sobre él como si fuese un repositorio normal. Dado que el fork está en su cuenta, él es el propietario y como tal  podrá hacer push sin ningún problema. Recordad que al repositorio original (https://github.com/aprendegit/fork) este usuario no puede hacer push.

Al cabo de unos minutos, aprendegit-user1 ha clonado su repositorio (https://github.com/aprendegit-user1/fork) en su máquina, ha añadido el logo y ha hecho un push a su fork:

Si volvéis al repositorio original (https://github.com/aprendegit/fork) veréis que este sigue igual, las modificaciones que aprendegit-user1 ha subido están sólo en el fork de aprendegit-user1.

Misión cumplida: aprendegit-user1 ya está trabajando en su repositorio sin preocuparnos ninguno de los dos de que algo salga mal.

Esto es todo por hoy. En la siguiente entrada veremos qué ocurre si después de que aprendegit-user1 ha hecho un fork, nuestro administrador (aalbagarcia) sube cambios al repositorio original ¿cómo actualiza aprendegit-user1 su fork?.

¡Happy gitting!

]]>
https://aprendegit.com/fork-de-repositorios-para-que-sirve/feed/ 37 337
Git Workflows: el tema que más interés despierta https://aprendegit.com/git-workflows-git-es-el-tema-que-mas-interes-despiert/ Fri, 25 Jan 2013 11:05:27 +0000 https://aprendegit.com/?p=319 Hace unos días os pedimos ayuda a través de un formulario para enfocar el contenido del blog a lo que más os interesa.

Queremos dar las gracias en primer lugar a todos los que os habéis tomado el tiempo de rellenar el formulario. A partir de los siguientes posts enfocaremos el contenido a lo que nos habéis pedido.

Resultados: Git Workflows, CLI y git-config

Con respecto al contenido, lo que más interés ha suscitado es lo relacionado con Workflows de git, seguido de la línea de comandos y la configuración con git-config.

Resultados: 30% Workflows, 19% Configuración con git-config, 19% Línea de comandos, 11% Github, 11% Crear mi servidor git, 7% GUIs, 4% Bitbucket.

También nos habéis convencido de que empecemos a grabar vídeos, así que en las próximas semanas empezaremos a hacerlo:

¿Prefieres vídeo o tutorial?

Resultados: 40% Las dos cosas, 30% Ver un vídeo, 30% Leer un tutorial

Con respecto a vuestros conocimientos, poco más de la mitad (60%) trabajáis con vuestro repositorio remoto y sabéis hacer pull y push. Sin embargo, pocos sois los que habéis trabajado con repositorios remotos, muy necesarios para poder implementar workflows en equipos distribuidos:

Conocimientos

Resultados: 60% Trabajo con mi repositorio haciendo pull y push, 20% ¡apenas se instalarlo!, 10% se crear ramas y hacer un merge, 10% Trabajo con múltiples repositorios remotos y hago pull request a diario.

Entre los que nos habéis respondido, hay un porcentaje importante que todavía no trabajáis con remotos (30%). ¡Eso hay que cambiarlo!.

Conclusión

Empezaremos a generar contenido tanto en formato tutorial y vídeo relacionado con trabajo con múltiples ramas, git workflows y configuración de git. ¡Sin olvidarnos por supuesto de aquellos que estáis empezando!

De nuevo muchas gracias por vuestra ayuda.

]]>
319
¿Sobre qué te gustaría que hablásemos? https://aprendegit.com/sobre-que-te-gustaria-que-hablasemos/ https://aprendegit.com/sobre-que-te-gustaria-que-hablasemos/#comments Tue, 22 Jan 2013 12:36:55 +0000 https://aprendegit.com/?p=309 El objetivo de este blog es que sea útil, y para que sea útil necesitamos tu ayuda. Cuéntanos qué te gustaría saber de git o sobre qué te gustaría que profundizásemos ¿flujos de trabajo? ¿configuración? ¿palabrejas raras como cherry picking o rebase? También puedes envíarnos una pregunta para que la convirtamos en un post.

¡Te estamos escuchando! ¡aprovecha y pide, que es gratis!

]]>
https://aprendegit.com/sobre-que-te-gustaria-que-hablasemos/feed/ 1 309
Opciones del comando git add https://aprendegit.com/opciones-del-comando-git-add/ https://aprendegit.com/opciones-del-comando-git-add/#comments Mon, 21 Jan 2013 13:23:17 +0000 https://aprendegit.com/?p=301 Un comando con el que todos estamos familiarizados es git add. Cuando nos iniciamos en el uso de git, este es de los que no faltan en las recetas que podemos en ver en cualquier tutorial. Es de los primeros que empezamos a utilizar cuando aprendemos git ¡En el libro de git de Scott Chacon aparece en la sección 2.2!

Es una pieza fundamental del flujo básico de git ya que es el comando que mueve al índice las modificaciones que hayamos realizado. El índice es un snapshot del contenido del área de trabajo en un momento dado. Este snapshot es el que posteriormente se convertirá en un commit.

La receta de git add

La forma más habitual de invocar el comando git-add es:

$ git add .

Este comando añade al índice cualquier fichero nuevo o que haya sido modificado:

$ git add .
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
#       new file: app/assets/javascripts/home.js.coffee
#       new file: app/assets/stylesheets/home.css.scss
#       new file: app/controllers/home_controller.rb
#       new file: app/helpers/home_helper.rb
#       new file: app/views/home/.erb
#       modified: config/database.yml
#       modified: config/routes.rb
#       new file: test/functional/home_controller_test.rb
#       new file: test/unit/helpers/home_helper_test.rb
#
# Changes not staged for commit:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
#       deleted: app/assets/images/rails.png

Sin embargo, los ficheros borrados no se actualizan en el índice. En este caso, tendríamos que ejecutar el comando git rm app/assets/images/rails.png:

$ git rm app/assets/images/rails.png
rm 'app/assets/images/rails.png'
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# deleted: app/assets/images/rails.png
# new file: app/assets/javascripts/home.js.coffee
# new file: app/assets/stylesheets/home.css.scss
# new file: app/controllers/home_controller.rb
# new file: app/helpers/home_helper.rb
# new file: app/views/home/.erb
# modified: config/database.yml
# modified: config/routes.rb
# new file: test/functional/home_controller_test.rb
# new file: test/unit/helpers/home_helper_test.rb
#

Las opciones -u y -A del comando git-add añaden al índice los ficheros eliminados, aunque gestionan de manera diferente los ficheros nuevos. Veamoslo usando este mismo ejemplo.

git-add -u

Partimos de la siguiente área de trabajo:

$ git status
# On branch master
# Changes not staged for commit:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
#    deleted: app/assets/images/rails.png
#    modified: config/routes.rb
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
#    app/assets/javascripts/home.js.coffee
#    app/assets/stylesheets/home.css.scss
#    app/controllers/home_controller.rb
#    app/helpers/home_helper.rb
#    app/views/home/
#    test/functional/home_controller_test.rb
#    test/unit/helpers/
no changes added to commit (use "git add" and/or "git commit -a")

La opción -u sólo añade al índice aquellos ficheros que ya estén siendo monitorizados por git, así que en este caso, únicamente se subirán al índice rails.png y routes.rb:

$ git add -u
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
#    deleted: app/assets/images/rails.png
#    modified: config/routes.rb
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
#    app/assets/javascripts/home.js.coffee
#    app/assets/stylesheets/home.css.scss
#    app/controllers/home_controller.rb
#    app/helpers/home_helper.rb
#    app/views/home/
#    test/functional/home_controller_test.rb
#    test/unit/helpers/

La opción -u acepta un patrón de búsqueda. Si este patrón está vacío, el resultado es que se actualicen todos los ficheros borrados o modificados en el área de trabajo. Si el patrón no está vacío, sólo se actualizarán en el índice los ficheros que encajen con el patrón. En el siguiente ejemplo, ejecutamos el mismo comando para añadir únicamente los ficheros de la carpeta config:

$ git add -u config/*
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
#    modified: config/routes.rb
#
# Changes not staged for commit:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
#    deleted: app/assets/images/rails.png
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
#    app/assets/javascripts/home.js.coffee
#    app/assets/stylesheets/home.css.scss
#    app/controllers/home_controller.rb
#    app/helpers/home_helper.rb
#    app/views/home/
#    test/functional/home_controller_test.rb
#    test/unit/helpers/

git-add -a

Esta opción funciona como la opción -u añadiendo también a la búsqueda los ficheros del área de trabajo. El resultado es que los ficheros que no estén siendo monitorizados también se añadirán al índice.

Partimos de la siguiente situación:

$ git status
# On branch master
# Changes not staged for commit:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
#    deleted: app/assets/images/rails.png
#    modified: config/routes.rb
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
#    app/assets/javascripts/home.js.coffee
#    app/assets/stylesheets/home.css.scss
#    app/controllers/home_controller.rb
#    app/helpers/home_helper.rb
#    app/views/home/
#    test/functional/home_controller_test.rb
#    test/unit/helpers/
no changes added to commit (use "git add" and/or "git commit -a")

Al ejecutar el comando git add -A, se añadirán al índice los ficheros borrados, los modificados y los nuevos:

$ git add -A
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
#    deleted: app/assets/images/rails.png
#    new file: app/assets/javascripts/home.js.coffee
#    new file: app/assets/stylesheets/home.css.scss
#    new file: app/controllers/home_controller.rb
#    new file: app/helpers/home_helper.rb
#    new file: app/views/home/.erb
#    modified: config/routes.rb
#    new file: test/functional/home_controller_test.rb
#    new file: test/unit/helpers/home_helper_test.rb

Al igual que la opción -u, esta opción también acepta un patrón. En el siguiente ejemplo, actualizamos el índice con las modificaciones, ficheros nuevos y ficheros borrados sólo de la carpeta app/assets:

$ git add -A app/assets
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
#    deleted: app/assets/images/rails.png
#    new file: app/assets/javascripts/home.js.coffee
#    new file: app/assets/stylesheets/home.css.scss
#
# 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: config/routes.rb
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
#    app/controllers/home_controller.rb
#    app/helpers/home_helper.rb
#    app/views/home/
#    test/functional/home_controller_test.rb
#    test/unit/helpers/

git-add -n

Esta opción es muy práctica ya que nos mostrará en pantalla lo que el comando git-add haría sin actualizar el índice. Continuando con el comando anterior (git add -A app/assets) si quisiésemos ver qué ficheros se actualizarán en el índice sin realmente actualizarlos, haríamos los siguiente:

$ git add -n -A app/assets
remove 'app/assets/images/rails.png'
add 'app/assets/javascripts/home.js.coffee'
add 'app/assets/stylesheets/home.css.scss'

Resumen

Hemos visto tres opciones del comando git-add: -u, -A y -n. Las dos primeras nos permiten actualizar en el índice directamente ficheros borrados sin necesidad de ejecutar el comando git-rm. La última opción, -n, simula lo que hará el comando git-add sin realmente actualizar el índice. Los tres son opciones útiles que de haberlas conocido cuando empecé con git hace años me habrían ahorrado unos cuantos comandos.

Referencias

]]>
https://aprendegit.com/opciones-del-comando-git-add/feed/ 3 301
Ignorando ficheros en git – Parte IV: Más patrones https://aprendegit.com/ignorando-ficheros-en-git-parte-iv-mas-patrones/ https://aprendegit.com/ignorando-ficheros-en-git-parte-iv-mas-patrones/#comments Mon, 14 Jan 2013 09:04:31 +0000 https://aprendegit.com/?p=270 En la entrega anterior estuvimos analizando los patrones básicos que podemos utilizar para ignorar ficheros a través de .gitignore, .git/info/exclude y .gitignore_local. En esta entrega veremos cómo git utiliza los patrones de la shell dentro de estos ficheros.

Todos los patrones que usa git

Hagamos un pequeño repaso de lo que ya sabemos:

  • Las líneas en blanco no se consideran un patrón. Se usan para hacer los ficheros más legibles
  • Si la linea comienza con #, se considera un comentario
  • El prefijo ! sirve para negar un patrón
  • Si el patrón termina en / sólo se aplicará a carpetas, es decir, un patrón «web/» ignorará la carpeta web/ pero no ignorará un fichero que se llame web

Hasta aquí lo que ya habíamos visto ¿qué nos falta?

  • Si el patrón no termina en /, git lo interpreta como un «shell glob pattern«. Internamente git llama a la función fnmatch con el flag FNM_PATHNAME: esto significa que ni el * ni el ? incluyen el carácter /. En seguida veremos ejemplos.
  • Una / al principio del patrón indica el inicio de una ruta relativa a la carpeta en la que se encuentre el fichero .gitignore. Una línea del tipo /config.php ignorará el fichero config.php pero no ignorará web/config.php

Shell globs en git

Los ficheros .gitignore, .git/info/exclude y .gitignore_local permiten incluir patrones de tipo shell. Si habéis trabajado con cualquier shell de Unix o el CMD de windows, estaréis familiarizados con el funcionamiento de estos patrones. En caso contrario, aquí tenéis las reglas que se siguen.

En una expresión que contenga el símbolo «?», éste se corresponde con uno y sólo un carácter

Ejemplos:

# Ignora los ficheros bg-01.jpg bg-lt.jpg
#
# No ignora los ficheros bg-1.jpg y bg-001.jpg
#
bg-??.jpg

Este patrón ignorará los ficheros cuyos nombres empiezan por «bg-«, van seguidos exactamente de dos caracteres, y luego van seguidos de «.jpg». Por eso el fichero bg-1.jpg no se ignora, porque entre «bg-» y «.jpg» no hay dos caracteres, sólo uno. Este ejemplo ilustra que el símbolo «?» no indica un caracter opcional.

En una expresión que contenga el símbolo » * «, éste se corresponde con cualquier número de caracteres

Ejemplos:

# Ignora todos los ficheros acabados en .nib
#
# Ignora tanto MainWindow.nib y builds/MainWindow.nib
*.nib

#Ignora todos los ficheros que empiecen por "bg-" y acaben en ".jpg"
bg-*.jpg

En el primer ejemplo, estamos ignorando cualquier fichero que acabe en .nib, independientemente de la carpeta en la que se encuentre. En el segundo ejemplo, estamos ignorando cualquier fichero que empiece por «bg-» y acabe por «.jpg». Una pregunta: ¿se ignorará el fichero «bg-.jpg» usando este patrón?. La respuesta la tenéis un poco más abajo.


En una expresión que contenga corchetes [ ], éstos se corresponden con uno y sólo un caracter de los que están incluidos en los corchetes.

Ejemplos:

# Ignora los ficheros *.o y *.a
*.[ao]

# Ignora los ficheros .nib y .xib
*.[xn]ib

Estos patrones no ignoran los ficheros liberia.so o los ficheros mainwindow.ib. Es necesario que alguno de los caracteres que están entre corchetes aparezcan en el fichero.

Si se necesita utilizar los caracteres ? * [ ] en un patrón, estos deberán escaparse con \

Ejemplo:

# Ignorando ficheros que contienen [ y ] en el nombre
#
# Este patrón ignorará los ficheros
# cache/cache-[hG7].cache y cache/cache-[009].cache
cache/cache-\[???\].cache

Shell globs y carpetas

¿Qué significa que git utilice el flag FNM_PATHNAME al llamar a la función fnmatch? Que los símbolos * ? y [] no incluyen el caracter » / » de separación de directorios.

# El uso de FNM_PATHNAME hace que el siguiente patrón ignore los ficheros
# web/fichero.html, pero no ignore el fichero web/admin/fichero.html
#
# Como el " * " no incluye " / ", el fichero web/admin/fichero.html no 
# encaja con el patrón
web/*.html

¿Qué ocurre si necesitamos justo el efecto contrario? es decir, queremos ignorar todos los ficheros .html que están en las subcarpetas de web pero no ignorar los ficheros .html que están en web. El patrón sería el siguiente:

# Ignora los ficheros .html que están en subcarpetas de la carpeta web
# No ignora los ficheros web/*.html
#
# Con este patrón, el fichero web/fichero.html se incluirá en el repositorio
# mientras que ficheros con web/admin/fichero.html o web/images/ se 
# ignorarán
web/**/*.html

Otra pregunta: Este patrón ¿ignora el fichero web/admin/subcarpeta/fichero.txt?

Rutas relativas

Un patrón que comienza por » / «, indica que para decidir si el fichero se ignora o no, se utiliza una ruta relativa al fichero .gitignore:

# Ignora los fichero *.c en la carpeta raiz del proyecto: memory.c
# No ignora los ficheros en subcarpetas como modules/cache.c
/*.c

Conclusiones

En esta entrega hemos visto cómo interpreta git los patrones glob shell y los patrones a rutas relativas. En la siguiente entrega veremos cómo podemos usar múltiples ficheros .gitignore. Estos nos ayudarán a salvar las limitaciones que tenemos a la hora de trabajar con múltiples subcarpetas.

Respuestas:

  1. Efectivamente, el patrón «bg-*.jpg» ignora que fichero «bg-.jpg». Eso es porque a diferencia de símobol «?», el símbolo «*» se corresponde con cualquier número de caracteres, incluido cero caracteres.
  2. El patrón web/**/*.html no ignora el fichero web/admin/subcarpeta/fichero.txt. Dado que se usa el parámetro FNM_PATHNAME, el » ** » no incluye el caracter » / » y por lo tanto este patrón sólo incluye las carpetas que son hijos de web, no incluye los nietos y niveles de más profundidad en la jerarquía de carpetas.
]]>
https://aprendegit.com/ignorando-ficheros-en-git-parte-iv-mas-patrones/feed/ 2 270
git alias de Nicola Paolucci https://aprendegit.com/git-alias-de-nicola-paolucci/ Fri, 11 Jan 2013 08:45:23 +0000 https://aprendegit.com/?p=286 Hoy una entrada corta pero muy interesante. Os recomiendo leáis este post de Nicola Paolucci en el que comparte con todos nosotros los aliases que utiliza en sus repositorios git:

Must Have Git Aliases: Advanced Examples

También podéis acceder al fichero .gitconfig que Nicola tiene en github.

Confío en que os resulte tan interesante y útil como a mí.

]]>
286
Ignorando ficheros en git – Parte III: Patrones https://aprendegit.com/ignorando-ficheros-en-git-parte-iii-patrones/ https://aprendegit.com/ignorando-ficheros-en-git-parte-iii-patrones/#comments Tue, 08 Jan 2013 09:00:16 +0000 https://aprendegit.com/?p=234 En la segunda entrega de esta serie aprendimos en qué orden se aplican los patrones para ignorar cambios en ciertos ficheros del repositorio. En esta tercera entrega veremos los patrones y reglas que git utiliza para interpretar los ficheros it ignore.

Comentarios y líneas en blanco

Podemos hacer nuestro fichero más legible si incluimos comentarios y separadores:

  • Cualquier línea que comience por # es un comentario
  • Una línea en blanco no se considera un patrón por parte de git, por lo que puede ser usada como un separador

Sé considerado con el resto de los miembros del equipo y comenta adecuadamente cada uno de los patrones que utilices. Indica el porqué de ese patrón de forma que el resto de compañeros o colaboradores sepan porqué has decidido en un momento dado ignorar ciertos ficheros. Y una cosa más, no todo el mundo usa las mismas herramientas que tú ni tiene tu mismo nivel de conocimientos en determinadas materias así que piensa un poco en los demás y ayúdales:

# Jetbrains IDEs: PHPStorm / RubyMine  
# (No todo el mundo tiene que saber que los ficheros .idea son de un 
# entorno de desarrollo)
.idea 

# Ficheros de documentación sphynx. Puedes generar tu copia local de la doc
# en /doc/build utilizando los scripts sphynx en /doc
/doc/build/

Negación

Utilizando el carácter podemos invertir un patrón ¿Qué significa invertir un patrón? Veamoslo con un ejemplo:

# Incluir expresamente en el repositorio todos los ficheros con extensión php
!*.php

¿Porqué podemos necesitar este tipo de patrones? Imagina que estás trabajando en un proyecto en PHP; como te puedes imaginar, si tu repositorio sólo tuviese estas dos líneas en los ficheros git/info/exclude, .ignore y .gitignore_local podríamos quitarlas ya que el efecto sería el mismo. Ahora bien ¿para qué podemos necesitar un patrón como este?:

  • Tal y como vimos en la anterior entrega, para invertir patrones de menor prioridad
  • Crear excepciones a patrones muy restrictivos

Veamos un ejemplo del segundo caso. Siguiendo con el ejemplo de un proyecto en PHP, podemos eliminar la línea anterior ya que no hace falta. Ahora bien ¿qué hacemos con los ficheros html?:

# Ignorar todos los ficheros .html...
*.html

 #... excepto en la carpeta web
!web/*.html

En este caso, cualquier fichero con extensión .html en cualquier carpeta se ignorará, excepto los ficheros que estén en la carpeta web. Cuidado porque ficheros .html que estén en una subcarpeta de web, como por ejemplo web/archive, también se ignorarán. Más adelante veremos porqué.

Ignorando carpetas enteras

Si un patrón acaba con una barra /, git ignorará cualquier fichero dentro de esa carpeta:

# Ignorar el contenido de las carpetas log y cache
cache/
log/

Git ignorará cualquier fichero que esté dentro de cache/ o log/ o en cualquier subcarpeta que cuelgue de ellas.

Este patrón no se lleva muy bien con la negación ¿Por qué decimos esto? Imagina que quieres ignorar el contenido de la carpeta web entera (incluyendo todas las subcarpetas que cuelgan de ella) excepto el fichero web/index.php. Con lo que sabemos hasta ahora, intentaríamos una combinación de patrones como la siguiente:

#Esto no funciona:
# git ignorará también el fichero index.php
web/
!web/index.php

Desafortunadamente esto no funciona y git ignorará fichero index.php. Veremos en una futura entrega cómo resolver este problema.

Una última nota sobre el uso de /. Si usamos el siguiente patrón

#Ignorar el contenido de la carpeta web
web/

y web no es una carpeta sino un enlace simbólico o un fichero regular:

total 16
-rw-r--r-- 1 aalba staff 0 22 dic 14:42 Alumno.php
-rw-r--r-- 1 aalba staff 0 22 dic 14:41 Curso.php
-rw-r--r-- 1 aalba staff 0 22 dic 14:42 Licencia.php
-rw-r--r-- 1 aalba staff 339 7 dic 16:39 README.md
drwxr-xr-x 3 aalba staff 238 29 dic 08:29 builds
lrwxr-xr-x 1 aalba staff 11 29 dic 08:29 web -> builds/html

¡el fichero no se ignora!

$ git status
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# web
  ^^^ -> el enlace simbólico o fichero regular no se ignora ya que el patrón
         web/ sólo se aplica a carpetas

Esto es todo por hoy, en la siguiente entrega de la serie veremos los patrones shell que podemos utilizar.

]]>
https://aprendegit.com/ignorando-ficheros-en-git-parte-iii-patrones/feed/ 1 234