GitHub

GitHub es un servicio de hosting para git. Está pensado para el trabajo colaborativo entre varios programadores.

Clonar un repositorio

Para clonar un repositorio nos basta con conocer su url. Por ejemplo, imaginemos que queremos descargar el proyecto https://github.com/chef/chef.git. En tal caso, solo es necesario que hagamos lo siguiente:

git clone https://github.com/chef/chef.git

Crear un par de claves pública/privada para poder comunicarnos con GitHub

GitHub utiliza una clave ssh para establecer una conexión segura entre nuestra máquina y el servidor git. Si no tenemos un par de claves pública/privada, debemos generarla con el siguiente comando:

$ ssh-keygen -t rsa -C "tu_email@tu_dominio.com"

Al ejecutar este comando se nos pedirá su ubicación, que por defecto es ~/.ssh/id_rsa. El resultado será algo como esto:

Generating public/private rsa key pair. Enter file in which to save the key (/home/usuario/.ssh/id_rsa): Created directory '/home/usuario/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/usuario/.ssh/id_rsa. Your public key has been saved in /home/usuario/.ssh/id_rsa.pub. The key fingerprint is: cf:b7:da:fe:0d:31:20:97:1d:f9:44:3d:0d:77:55:9a micorreo@midominio.com The key's randomart image is: +--[ RSA 2048]----+ | ooO| | o *+| | . + E .| | o = . | | S = | | o o | | o . . | | o . o | | .o+.. .| +-----------------+

Crear una cuenta en GitHub

Necesitamos crearnos una cuenta en GitHub. Crear una cuenta en GitHub no tiene nada de particular.

Una de las tareas que debemos hacer para poder enviar confirmaciones a github es registrar nuestra clave pública en GitHub. Para hacer esto, vamos hasta el botón que aparece arriba a la derecha con el "hint" View profile and more, desplegamos y elegimos la opción Settings. En la página de configuración, en el panel izquierdo está la opción SSH keys. Para terminar hacemos clic en el botón "Add SSH key". Aquí debemos pegar el contenido del archivo /home/usuario/.ssh/id_rsa.pub generado anteriormente. Dicho contenido será algo como lo siguiente:

ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3 Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx NrRFi9wrf+M7Q== schacon@agadorlaptop.local

Al añadir la clave, nos aparecerá nuestra lista de claves, con su hash, cuenta de correo electrónico, y la opción de borrarla.

Para comprobar que podemos conectarnos correctamente a GitHub, hacemos lo siguiente:

ssh git@github.com

El resultado será lo siguiente:

The authenticity of host 'github.com (192.30.252.129)' can't be established. RSA key fingerprint is cf:b7:da:fe:0d:31:20:97:1d:f9:44:3d:0d:77:55:9a. Are you sure you want to continue connecting (yes/no)?

Aquí escribimos "y" y pulsamos intro. Y obtendremos lo siguiente:

Warning: Permanently added 'github.com,192.30.252.129' (RSA) to the list of known hosts. PTY allocation request failed on channel 0 Hi usuario! You've successfully authenticated, but GitHub does not provide shell access. Connection to github.com closed.

Para subir el proyecto solo tenemos que hacer lo siguiente, para compartirlo con el resto del equipo:

git remote add origin git@github.com:mmatpein/miproyecto

Crear un nuevo repositorio

Para crear un nuevo repositorio, podemos seguir la ayuda de GitHub en https://help.github.com/articles/create-a-repo/. Sólo hay un punto que aclarar, que es la opción "Intialize this repository with a README".

Tenemos dos maneras de crear un nuevo repositorio:

  • Opción 1: Crear primero un nuevo repositorio en GitHub, seleccionando la opción "Initialize this repository with a README". Una vez creado, clonamos localmente el repositorio, añadimos los nuevos archivos y lo volvemos a subir.
  • Opción 2: Crear un repositorio en GitHub, y NO seleccionar la opción "Initialize this repository with a README", lo que creará un repositorio vacío en GitHub. Inicializamos nuestro proyecto localmente como un repositorio Git, y después los subimos a GitHub.

Según ya tengamos un repositorio creado localmente o no, marcaremos la opción "Initialize this repository with a README". En nuestro caso, no vamos a marcarla, puesto que tenemos ya un repositorio creado localmente.

Una vez que creamos el repositorio, GitHub nos ofrece ayuda sobre qué hacer. En nuestro caso, vamos a suponer que ya tenemos hecho al menos un "commit" en nuestro respositorio local. Así que para subir a GitHub nuestro repositorio, hacemos lo siguiente:

$ git remote add origin git@github.com:cuenta_usuario/repositorio.git $ git push origin master

Después de hacer esto, podremos ver algo como lo siguiente (si todo ha ido bien):

Counting objects: 15, done. Delta compression using up to 4 threads. Compressing objects: 100% (11/11), done. Writing objects: 100% (15/15), 2.15 KiB | 0 bytes/s, done. Total 15 (delta 3), reused 0 (delta 0) To git@github.com:cuenta_usuario/repositorio.git * [new branch] master -> master Branch master set up to track remote branch master from origin.

De hecho ya podemos ver nuestros archivos en el repositorio.

origin es similar a master, pero refiriéndolos al repositorio remoto. De este modo, podemos hablar de la rama origin/master para referirnos al último commit del repositorio remoto que tenemos en nuestro repositorio local. Por ejemplo, en el siguiente código podemos ver un repositorio en el que la rama master tiene ciertos cambios que origin/master no.

$ git log --oneline --decorate --graph --all * cd78ae4 (HEAD, master) Añadiendo el archivo TODO * f763def (origin/master, origin/HEAD) Initial commit

Comprobar nuestros repositorios remotos

Para poder ver qué repositorios remotos tenemos configurados, podemos ejecutar el siguiente comando:

git remote -v

Confirmando las ramas de nuestro repositorio

Supongamos que tras clonar nuestro repositorio remoto, hemos hecho algunas modificaciones localmente. También vamos a suponer quen nadie ha modificado nada en el repositorio remoto. Ahora queremos subir los nuevos cambios. En este momento tenemos lo siguiente:

  • En el repositorio remoto, la rama master sigue en el sitio donde lo descargamos
  • En el repositorio local, la rama origin/master sigue apuntando al commit descargada.
  • En el repositorio local, la rama master apunta al último commit realizado localmente

Para subir los nuevos cambios al repositorio remoto, haremos los siguiente:

$ git push origin nombre_rama

Supongamos que el árbol de nuestro repositorio y su contenido es el siguiente:

$ git log -p --decorate commit cd78ae4904c0302d4a8253e5b0d869c8f93a4da8 (HEAD, master) Author: Mauricio Matamala <mauriciomatamala@hotmail.com> Date: Wed Jan 13 14:11:23 2016 +0100 Añadiendo el archivo TODO diff --git a/TODO b/TODO new file mode 100644 index 0000000..359a564 --- /dev/null +++ b/TODO @@ -0,0 +1,4 @@ +Actividades que quedan por hacer +================================ + +1. Actividad 1. commit f763deff8c5e4863467cf863ef35bf027f126069 (origin/master, origin/HEAD) Author: mmatpein <mmatpein@users.noreply.github.com> Date: Tue Jan 12 18:57:11 2016 +0100 Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..ddc9403 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# clase_github

Ahora supongamos que quiero hacer una propuesta de una idea en una rama nueva, para que el resto de componentes del equipo puedan verla. Para ello, creo primero una nueva rama.

$ git branch idea_feliz $ git checkout idea_feliz

Hago las modificaciones precisas, y luego subo la nueva rama.

$ git push git@github.com:mmatpein/clase_github.git idea_feliz

Si compruebo el estado del repositorio en GitHub, podré ver que hay una nueva rama llamada "idea_feliz"

Actualizaciones de colaboradores en el repositorio

Supongamos un usuario colaborador descarga nuestro repositorio, realiza una modificación en la rama "master" y vuelve a subir el repositorio a GitHub. De forma que nosotros queremos actualizar la rama "origin/master". Entonces usaremos el siguiente comando:

$ git fecth origin

Con este comando obtenemos la rama "origin/master" así como el resto de ramas del repositorio. Pero "origin/master" todavía no coincide con "master". Para que esta rama sea también nuestra rama "master", tendremos que fusionar:

$ git merge origin/master

En este momento nuestro repositorio "master" ya coincide con "origin/master"

El comando git pull origin es una forma abreviada de hacer:

$ git fetch origin $ git merge origin

Fusionando ramas en github

Supongamos que tenemos la rama "idea_feliz" sin fusionar en GitHub. Hemos hablado y estamos de acuerdo en que podemos fusionarla con la rama "master". Si queremos fusionar estas dos ramas, podemos hacerlo desde GitHub, o bien utilizando Git en nuestro repositorio local y luego subiendo los cambios. Los pasos a seguir son:

Paso 0: Asegurarnos de que tenemos la última versión de origin

$ git fetch origin $ git merge origin

Paso 1: Fusionar la rama "idea_feliz" con "master".

$ git checkout master $ git merge idea_feliz

Paso 2: Subir los cambios

$ git push origin master

Hecho esto, podremos ver en GitHub cómo se han fusionado los cambios, indicando la etiqueta "Merged" en la rama "idea_feliz".

Flujo de trabajo en proyectos con GitHub

En Git (y en GitHub) existe mucha libertad en la forma de trabajar. Por eso mismo, cuando el trabajo es entre varias personas, es necesario ponerse de acuerdo en cómo se va a utilizar. A estos acuerdos es a lo que llamamos workflow.

Existe más de un workflow, aunque los más aceptados son git-flow y github-flow.

Git-Flow

Podemos consultar sobre GitFlow en http://nvie.com/posts/a-successful-git-branching-model/. A grandes rasgos, el workflow propuesto por Vincent Driessen dice lo siguiente:

  • Cada desarrollador descarga y sube confirmaciones a un repositorio "origin", pero detrás de este modelo centralizado, se pueden formar subequipos que trabajen sobre ciertas ramas concretas, dejando a un lado las otras.
  • Las ramas principales son master y develop.
    • origin/master contiene solamente versiones estables.
    • origin/develop contiene versiones con los últimos cambios añadidos. De esta rama saldrán las versiones estables. Cuando el código en esta rama alcanza un punto estable que puede ser liberada, llega el momento de fusionar con la rama origin/master y etiquetado correctamente.

    La rama master contiene únicamente versiones de producción, ya que solo se fusiona con origin/develop cuando el commit se hace para una versión estable.

  • Las ramas adicionales tiene tiempos de vida limitados, y su objetivo será hacer cosas como desarrollo coordinado entre varios miembros del equipo, fácil seguimiento del desarrollo de características concretas, preparar versiones de producción, solución rápida a problemas del software de producción, etc. Diferenciamos entre los siguientes tipos de ramas:
    • Ramas feature: derivan de la rama develop y se vuelven a fusionar con ella. Tienen nombres del tipo feature-nombre_de_la_caracerística. Estas ramas suelen existir únicamente en el repositorio del programador.
    • Ramas release: derivan de la rama develop y se fusiona con develop o con master. Tienen nombres del tipo release-nombre_de_la_versión. Esta rama se utiliza para preparar un versión de producción. Se crean cuando la rama develop está CASI a punto. Permiten hacer cosas como:
      • Ultimar detalles de última hora
      • Resolver bugs menores
      • Asignar números de versión. Hasta este momento la rama release no deja claro si estamos hablando de la versión 0.3 o la versión 1.0.
    • Ramas hotfix: derivan de la rama master y se fusionan con develop o con master. Tienen nombres como hotfix-nombre_de_la_revisión. Este tipo de ramas se crean cuando hay un problema crítico que hay que resolver inmediatamente en una versión de producción. Se crea la rama para este problema crítico, mientras el resto del equipo sigue trabajando por otro lado. Cuando se cierra una rama hotfix es importante fusionar con la rama master y con la rama develop para que la siguiente versión de desarrollo incluya esta revisión (si no, volveríamos en el futuro a tener el mismo problema crítico al liberar la versión de desarrollo).
    • Es importante recordar que cuando está abierta una rama release, la rama hotfix debe ser fusionada con la rama release.

GitHub flow

El modelo propuesto por GitHut para GitHub puede consultarse en https://guides.github.com/introduction/flow/. A grandes rasgos, propone lo siguiente:

  • Cualquier cosa en la rama master es siempre desplegable en producción. Por eso, las ramas de trabajo deben derivarse de ésta.
  • Cuando se crea una nueva rama, avanzar por ella creando nuevos commits. Es importante cuidar los "commit messages", para que los demás sepan qué estamos haciendo.
  • Crear un pull request cuando queramos recibir feedback del resto del equipo. Lo podemos hacer en cualquier momento durante la existencia de la rama.
  • Una vez que se ha creado el pull request, podemos seguir creando commits conforme la conversación va avanzando.
  • Cuando el pull request ha dado lugar a un commit que pasa todos nuestros tests, podemos desplegar los cambios para comprobarlos en producción. Si la rama crea problemas, siempre podemos volver a desplegar la rama master
  • Una vez que hemos visto que el commit de nuestra rama es estable (ya que no ha dado problemas en producción), podemos fusionar con la rama master. Cada pull request conserva un histórico que permite entender que se hizo en su momento.

Poniéndolo todo junto

Vamos a suponer que dos programadores están trabajando en el proyecto calculadora. Van a utilizar PHP, git y github. los usuarios son mmatpein y karelrubi

Cada uno de ellos se va a encargar de una parte separada. Tenemos un backlog con las siguientes historias:

  • El usuario introducirá los operandos y la operación a realizar a través de un formulario
  • Un operador binario puede realizar operaciones aritméticas sencillas, como '+', '-', '/' y '*', entre dos operandos
  • El resultado de las operaciones se puede mostrar utilizando diferentes plantillas

Después de pensar en ello, les ha quedado un sprint backlog como el siguiente:

  1. H1 [mmatpein]. Formulario de entrada: toma dos parámetros y una operación y los envía a "calcular.php"
  2. H2 [mmatpein]. Calculadora: clase que puede realizar diferentes operaciones
    • T2.1. Suma
    • T2.2. Resta
    • T2.3. Divide
    • T2.4. Multiplica
  3. H3 [karelrubi]. Vista: plantilla con el resultado
    • T3.1. Muestra una página web con el resultado
  4. H4 [karelrubi]. Controlador
    • Filtrar los datos de entrada del formulario
    • T4.1. Cargar objeto de tipo calculadora y pasarle los datos filtrados[Depende de H2]
    • Pasar el resultado a un objeto tipo VistaOperacion, junto al nombre de una plantilla y mostrar.

A partir de este Sprint Backlog, mmatpein crea el nuevo repositorio y añade a karelrubi como colaborador. Inicialmente el proyecto no tiene nada salvo un archivo "readme.md".

GitHub Flavored Markdown es una sintaxis propia de GitHub, pensada para el contenido del archivo "readme.md". El contenido de este archivo se muestra en la página del proyecto, en formato html. Se puede consultar más sobre este tema en https://help.github.com/articles/github-flavored-markdown/.

El repositorio acaba de ser creado.

Puesto que el equipo de desarrollo va a seguir el flujo de trabajo git-flow, mmatpein clona localmente el repositorio, y añade una nueva rama, llamada develop. Para clonar, utiliza la url indicada en la página principal del repositorio:

Url usada para clonar el proyecto.
Clonado del repositorio

Después de esto, mmatpein crea una nueva rama en su repositorio local, llamada develop

Creando la rama develop.

Después activa la rama develop y añade un archivo vacío llamado index.php (que contendrá el formulario).

$ git checkout develop $ vim index.php // Añadir <?php al archivo. $ git add . $ git commit -m "Inicio del proyecto: index.php vacío"

Finalmente sube los cambios (la nueva rama develop) al repositorio:

Haciendo una confirmación de la rama develop en el repositorio remoto en GitHub.

Después de hacer esto, podremos comprobar en GitHub que hay dos ramas:

Se puede ver la rama master y la rama develop.

A continuación, mmatpein añade a karelrubi como colaborador del repositorio. Para ello, en la página del repositorio, hace clic en "Settings". En la página de configuración, elige la opción "Collaborators" de la columna de la izquierda.

Añadiendo al colaborador karelrubi

karelrubi recibe una notificación en GitHub, informándole de su inclusión como colaborador en el proyecto miCalculadora

karelrubi es informado de que ha sido añadido a un proyecto.

Cada programador se pone a trabajar en sus cosas

mmatpein realiza tareas iniciales

matpein realiza tareas iniciales en el proyecto, vistas anteriormente, como instalar Composer y PHPUnit. El código del proyecto en el repositorio local de mmatpein en este punto es el siguiente: miCalculadora_mmatpein_local_0.0.tgz.

De momento mmatpein lleva un test. El resultado es el siguiente:

De momento hay un test único test, que falla.

Como ya vimos anteriormente, el primer paso es obtener el rojo (de tests que fallan). mmatpein está en el buen camino, así que decide guardar sus cambios localmente. Por ello, hace un commit en la rama develop, para guardar este primer estado deseable del proyecto.

Como se puede ver, mmatpein está en la rama develop. Tras añadir los cambios, puede comprobar los cambios que se van a hacer con "git status".

Finalemente hace un commit a la rama develop del repositorio local.

$ git commit -m "Herramientas instaladas. Primer test funcional"

Y para terminar, hace una confirmación de la rama "develop" al repositorio remoto para que karelrubi pueda partir desde este punto.

Al subirlo al repositorio remoto, karelrubi ya podrá usar los archivos del repositorio.

mmatpein sigue trabajando en su repositorio local

Puesto que estamos siguiendo el flujo de trabajo de git-flow, mmatpein crea una nueva rama feature, llamada "feature_operadorBinario" donde trabajará en la clase "OperadorBinario" y sus correspondientes tests.

$ git branch feature_operadorBinario $ git checkout feature_operadorBinario

karelrubi empieza por otro lado con sus tareas

Una de las cosas que karelrubi tiene que hacer es una plantilla para el proyecto. El repositorio ya existe, y aunque mmatpein ha hecho algunas tareas locales que no ha actualizado aún, karelrubi puede empezar ya.

Lo primero que hace es clonar el repositorio mmatpein/miCalculadora localmente en su ordenador.

karelrubi clona el proyecto, para tener un repositorio local. Como podemos ver, el proyecto no tiene las modificaciones que ha hecho mmatpein en su repositorio local.

Aparentemente, karelrubi no cuenta con la rama develop, tal y como se ve al ejecutar el comando git branch. Sin embargoLo único que ocurre es que git únicamente clona la rama master y registra la existencia de otras ramas remotas. Sin embargo, cada programador tiene que activar explícitamente la rama que desee. En este caso, karelrubi va a trabajar con develop.

Para poder ver todas las ramas disponibles (aunque no estén visibles), debemos ejecutar el comando git branch -a. Hasta que karelrubi no active la rama "develop" localmente no podrá trabajar en ella.

Como se puede ver, karelrubi puede ver la rama remotes/origin/master. Pero necesita activarla localmente de manera explícita.

Una vez que ha clonado el proyecto, se pone a trabajar en la plantilla de salida. Para ello, crea una rama local llamada "feature_plantillaSalida".

Para trabajar en esta característica (la plantilla de salida), karelrubi crea una rama local llamada "feature_plantillaSalida".

karelrubi escribe la plantilla y añade una hoja de estilos. Al terminarla, karelrubi hace una confirmación en su repositorio local, en la rama "feature_plantillaSalida".

La confirmación que hace karelrubi es local, de forma que mmatpein no puede ver lo que karelrubi está haciendo.

El proyecto de karelrubi (repositorio incluido) tiene el siguiente contenido: miCalculadora_karelrubi_local_0.0.tgz.

mmatpein completa una de sus historias

mmatpein sigue trabajando en el proyecto, y complenta la historia de usuario 2 (crear una clase que realiza varios tipos de operaciones aritméticas). Todos los tests unitarios pasan, por lo que puede hacer una confirmación de la rama local "feature_operadorBinario".

Todos los tests pasan, por lo que mmatpein hace una confirmación en la rama local "feature_operadorBinario"

Ahora mmatpein decide compartir con el resto del equipo sus avances y pedir su opinión sobre fusionar la rama "feature_operadorBinario" con la rama "develop". Para ello, hace dos cosas:

Confirmación de ramas "feature" con la rama "develop" en GitHub

mmatpein confirma la rama "feature_operadorBinario" (que aún no existe en GitHub, ya que es una rama local de mmatpein) a GitHub.

En la imagen se puede ver como mmatpein sube la rama "feature_operadorBinario" a GitHub. Después consulta el estado de las ramas, y se observa como origin/feature_operadorBinario apunta a feature_operadorBinario.

En GitHub, ahora podemos ver que la nueva rama se ha añadido.

Se puede ver como la nueva rama aparece en GitHub tras hacer un git push origin feature_operadorBinario

Crear un pull request para la rama "feature_operadorBinario"

Mediante un pull request, se pide al resto del equipo que aporte ideas antes de fusionar la rama como la rama "develop". Para ello, accedemos a la rama "feature_operadorBinario" en GitHub, y hacemos clic en "New pull request".

Hacer clic en "New pull request" para la rama "feature_operadorBinario".
mmatpein añade una descripción del estado de la rama.
El pull request ya ha sido creado. El resto del equipo puede revisar el código y dar su opinión.

Como se puede ver en la imagen anterior, GitHub nos informa de que la rama es fusionable ya que no hay conflictos.

karelrubi hace observaciones al pull request

karelrubi recibe en su correo electrónico un aviso de que hay un nuevo pull request. Desde el mismo correo accede a su cuenta de GitHub y haciendo clic sobre la rama "feature_operadorBinario" puede ver los cambios que tiene esta rama respecto a "develop"

karelrubi está viendo lo que mmatpein ha añadido en esta rama.

Una vez que ha revisado lo que se ha hecho, añade sugerencias a mmatpein.

Comentarios de karelrubi al pull request

mmatpein hace algunos cambios según los comentarios de karelrubi

mmatpein considera las propuestas de karelrubi y actualiza el código. Tras estos cambios, el código que tiene mmatpein en su rama local "feature_operadorBinario" es el siguiente: miCalculadora_mmatpein_feature_operadorBinario_0.1.tgz

mmatpein confirma los cambios en su repositorio local:

mmatpein confirma los cambios al repositorio local.

Una vez que la rama local "feature_operadorBinario" de mmatpein se ha actualizado con los cambios, mmatpein quiere compartir con el resto del equipo la evolución del código tras los comentarios del pull request. Para ello sube a GitHub el nuevo estado de la rama "feature_operadorBinario"

mmatpein confirma los cambios a la rama "origin/feature_operadorBinario" en el repositorio remoto.

Después de esto, ya podemos ver el nuevo estado de la rama en GitHub.

La nueva actualización aparece a continuación del comentario de karelrubi.

Además, podemos ver los cambios que se han producido en el código haciendo clic sobre el nuevo nodo.

GitHub permite ver los cambios que se han producido en el nuevo nodo.

Si el resto del equipo ve bien los cambios, harán comentarios en este sentido, y finalmente se producirá un commit. A la hora de hacer la fusión final, podemos hacerlo desde el mimso GitHub o bien utilizando comandos. El proceso es en realidad muy simple:

  1. mmatpein descarga el proyecto desde GitHub, para garantizar que tiene al día los cambios hechos por otros componentes
  2. $ git fetch origin $ git merge origin
  3. Activa la rama donde vamos a fusionar los cambios, en este caso "develop"
  4. $ git checkout develop
  5. Fusiona con la rama deseada, en este caso "feature_operadorBinario"
  6. $ git merge --no-ff feature_operadorBinario
  7. Sube los cambios a la rama "develop"
  8. $ git push origin develop

Esto se ve en la siguiente imagen:

Fusionando la rama "feature_operadorBinario" en el repositorio remoto.

Una vez hecho esto, podremos ver como la rama "develop" incluye los cambios de la rama "feature_operadorBinario" y ya podemos cerrar el pull request.

karelrubi va a actualizar la rama "develop"

karelrubi ha trabajado en la historia de usuario H3, y ha completado la vista de usuario (en forma de una plantilla). Lo ha hecho en la rama "feature_plantillaSalida". Ahora desea subir la rama a GitHub, y hacer un pull request para fusionarla con Develop.

karelrubi sube la rama "feature_plantillaSalida" a GitHub.
En GitHub se puede ver la nueva rama.

karelrubi hará ahora un pull request para conocer la opinión de los otros programadores. Supongamos que mmatpein (el otro programador) acepta la rama. La cuestión ahora es la siguiente:

La rama "develop" ha cambiado desde que karelrubi hizo su última actualización. Podemos ver esto en la siguiente prueba:

Se puede ver que en la rama "develop" de karelrubi no se han añadido los últimos cambios que añadión mmatpein. Por ejemplo, debería poder verse un archivo llamado "DatosOperacion.php".

Si karelrubi actualizase ahora la rama "develop" y la subiera a GitHub, machacaría los últimos cambios de la rama "origin/develop" en GitHub. Por ello, antes de fusionar la rama "feature_plantillaSalida" con "develop", karelrubi va a actualizar la rama "develop"

$ git fetch origin $ git merge origin $ git checkout develop // git advierte que la rama no está actualizada $ git pull
En la imagen se puede ver como git advierte a karelrubi de que su rama local "develop" está por detrás del estado de la misma rama en GitHub. Por eso, hace "git pull". Después podemos ver como los archivos añadidos por mmatpein (en la carpeta modelo se han actualizado).

Ahora, karelrubi puede fusionar la rama "feature_plantillaSalida" con la rama "develop" y subirlo después a GitHub, con los siguientes comandos:

$ git merge --no-ff feature_plantillaSalida -m "Añadida plantilla de salida" $ git push origin develop
descripcion

Después de esto, karelrubi ya puede cerrar el pull request. En GitHub ya está la última versión de la rama "develop".

Ahora es mmatpein quien no tiene actualizada la rama "develop". En el futuro, cuando desee volver a fusionar una rama "feature" con la rama "develop" deberá repetir el proceso comentado.

Podemos ver que GitHub contiene la última versión de "develop", incluyendo los anteriores cambios que introdujo mmatpein, y los nuevos que ha añadido karelrubi.

El proceso sigue así una y otra vez...

El proceso se repite una y otra vez, con cada programador creando pull requests y añadiendo nuevas características a "develop".

Ahora supongamos que ya está todo listo, y el proyecto está listo para su primera versión.

Crear una rama "release"

Como estamos a punto de liberar nuestra primera versión estable, creamos una nueva rama "release", llamada "release_0.0", por ejemplo, y creamos un pull request. Aquí se ultimarán los últimos detalles, y cada programador aportará sugerencias y cambios de última hora. Se producirá una conversación ultimando detalles.

  • matpein sugiere un cambio de tipografía en la plantilla
  • karelrubi añade un archivo favicon.ico
  • Etc.

Ya se puede liberar la primera versión

Una vez que todo está listo, se fusiona la rama "release_0.0" con la rama "develop" y con la rama "master".

Es necesario fusionar con "develop" y con "master" para que cuando sigamos trabajando en "develop", partamos del mismo estado que hay en "master" y no se pierdan los últimos cambios hechos en la rama "release_0.0".

Los comandos a llevar a cabo serían los siguientes:

$ git fetch origin $ git merge origin $ git checkout master $ git merge --no-ff release_0.0 $ git checkout develop $ git merge --no-ff release_0.0

Finalmente se etiqueta la versión liberada.

$ git checkout master $ git tag -a v0.0 -m "v0.0"

Y para terminar subimos los cambios.

$ git push origin master $ git push origin develop

Y vuelta a empezar

Ahora que tenemos nuestra primera versión estable liberada, seguimos trabajando en la rama "develop" hasta que tengamos de nuevo otra versión estable. El proceso seguirá siendo el mismo una y otra vez.

Cómo encaja Scrum en todo esto

Lo ideal sería que al final de cada Sprint, tengamos la rama "develop" con todas las historias de usuario del sprint completadas.

Cada cierto número de sprints, tendremos una nueva versión estable, que coincidará con lo acordado en el "Release Planning Meeting".

Actividad 1. Crea un grupo con otras dos personas. Uno de vosotros gestionará la rama develop, release y master

Cada componente creará una nueva rama "feature", donde creará varios commits con cambios sencillos (como añadir un nuevo archivo, por ejemplo).

Cada componente creará un pull request una vez que su rama "feature" esté lista para fusionar con la rama develop

El responsable de las ramas develop, release y master realizará las fusiones de las ramas "feature" con la rama develop

Una vez que la rama develop se haya fusionado con las diferentes rama "feature", deberá aplicarse el flujo de trabajo git-flow, de forma que se utilizarán las ramas release y master para liberar la primera versión (v0.0) del proyecto.

En la rama release añade cualquier cambio menor, simulando cambios de última hora.

El objetivo de este ejercicio es poder ver que los diferentes repositorios locales contienen información coherente con lo que contiene el repositorio en GitHub. Entrega la actividad en un archivo llamado Act1-github.zip, donde se debe incluir lo siguiente:

  • Un archivo de texto con el nombre del repositorio.
  • Una captura llamada <nombre_repositorio>_grafo.png con el resultado de ejecutar el comando git log --graph --all --oneline --decorate en tu repositorio local una vez que hayas terminado el ejercicio
  • La misma captura obtenida por tus otros compañeros.

Trabajando con forks

Otra forma de trabajar en equipo con git y con GitHub es usando forks. 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.

La ventaja de usar forks es que se puede contribuir a un proyecto de forma segura. Cada repositorio es independiente y solo se incluirá una nueva característica a través de un pull request

Creando el fork

Suponiendo que mmatpein ha creado ya el repositorio aprendiendofork, karelrubi busca el repositorio.

Karelrubi busca el repositorio para crear una bifurcación.

Una vez que ha encontrado el repositorio, crea un fork, presionando el botón fork

Karelrubi crea un fork del proyecto aprendiendofork

Al crear el fork, karelrubi ya puede ver el repositorio en su cuenta de GitHub

Karelrubi tiene su propio proyecto karelrubi/aprendiendoforks, que es un fork del proyecto mmatpein/aprendiendoforks

mmatpein trabaja en su proyecto

Por ejemplo, supongamos que mmatpein realiza las siguientes tareas:

  • Crea una rama develop
  • Crea un rama feature_m1
  • Añade varios commits a la rama feature_m1
  • Fusiona la rama feature_m1 con la rama develop

mmatpein lleva a cabo todos estos cambios en su repositorio local.

mmatpein puede ver lo siguiente al ejecutar el comando git log --all --oneline --decorate --graph

mmatpein ha hecho cambios sobre su repositorio local.

Después de esto, sincroniza su repositorio local con GitHub con los comandos siguientes:

$ git fetch origin $ git merge origin $ git push origin feature_m1 $ git push origin develop

Lo que mmatpein puede ver es lo siguiente:

mmatpein puede ver el repositorio al día, con las distintas ramas sincronizadas con el repositorio.

karelrubi trabaja en el fork

Por su parte karelrubi realiza las siguientes acciones sobre su repositorio:

  • karelrubi crea una nueva rama llamada feature_k1
  • Añade algunos commits a la rama

La imagen que karelrubi tiene de su fork es la siguiente:

Lo que karelrubi ve del fork es muy diferente a lo que mmatpein ve del proyecto original

Añadir un repositorio remoto

Al ejecutar el comando git remote -v, karelrubi solamente ve un repositorio remoto. Con el comando git remote add upstream https://github.com/mmatpein/aprendiendoforks.git añade el repositorio original con el nombre upstream

karelrubi añade el repositorio original como repositorio remoto.

Crear un pull request

karelrubi ya tiene lista su rama feature_k1 y desea incorporarla al proyecto principal. Para ello, en primer lugar debe actualizar los cambios que se han producido en el repositorio upstream (que es el nombre que le hemos dado a repositorio principal).

Los pasos que va a dar son:

  1. descargar los cambios desde upstream
  2. fusionar con upstream para que las ramas locales y remotas coincidan
  3. actualizar el repositorio del fork
  4. crear un pull request sobre la rama develop
karelrubi actualiza los cambios hechos en el repositorio upstream. Se puede ver como queda el grafo del repositorio tras hacer esto.
Karelrubi sincroniza su repositorio local con su repositorio remoto (fork).

Ahora, karelrubi quiere que su rama feature_k1 se integre con la rama develop del proyecto principal. Para ello, hace un pull request.

Para hacer un pull request hay que hacer clic sobre el botón New pull request

Tras solicitar el nuevo pull request karelrubi tiene que indicar sobre qué rama quiere fusionar la rama feature_k1

karelrubi indica el repositorio base (mmatpein/aprendiendoforks), la rama donde se desea fusionar (develop), el repositorio del fork (karelrubi/aprendiendoforks) y por último la rama que deseamos fusionar (feature_k1)

mmatpein gestiona el pull request

Después de que karelrubi haya creado el pull request, mmatpein puede verlo.

mmatpein ve el nuevo pull request

Podría comenzar una conversáción sobre el contenido de la rama feature_k1, que incluyese algunos commits más. Cuando todo estuviese listo, mmatpein ya podría fusionar con la rama develop.

En la imagen se puede ver cómo se ha hecho algún cambio sobre la rama feature_k1 a propuesta de mmatpein.

Una vez que mmatpein considera que la rama feature_k1 está lista para ser incorporada al proyecto, en primer lugar hace lo siguiente:

  1. mmatpein crea una nueva rama llamada karelrubi-feature_k1 a partir de la rama develop.
  2. Después trae y fusiona la rama feautre_k1 del repositorio de karelrubi con la rama karelrubi-feature_k1.
mmatpein crea la rama karelrubi-feature_k1 y se trae el contenido de la rama desde el repositorio de karelrubi

Lo siguiente que hace mmatpein es fusionar la rama develop con la rama karelrubi-feature_k1

Como se puede apreciar, tras la fusión, la rama develop incluye los cambios de karelrubi-feature_k1

Finalmente, mmatpein sube a GitHub los cambios.

mmatpein sube al repositorio remoto en GitHub los cambios. Como se puede ver, origin/develop y develop apuntan a la misma confirmación.

En GitHub podremos ver cómo se ha cerrado el pull request tras realizar la fusión.

GitHub nos advierte de que se ha fusionado la rama karelrubi:feature_k1 con la rama mmatpein:develop

karelrubi atualiza su repositorio

Desde el punto de vista de karelrubi, se ha fusionado la rama feature_k1 con la rama upstream/develop. Pero hasta que karelrubi no atualice su repositorio, no podrá ver estos cambios.

karelrubi puede ver la rama upstream/develop, y cómo la rama feature_k1 se fusiona con esta.
Si karelrubi ejecuta el comando git checkout upstream/develop, el puntero HEAD apunta a dicho repositorio, de forma que podemos seguir trabajando desde el estado actual del proyecto.

Lo que karelrubi y mmatpein ven difiere ligeramente, ya que mmatpein no ve la rama feature_k1. Por lo demás, los proyectos son similares.

En el grafo de confirmaciones de mmatpein no se puede ver la rama feature_k1, aunque sí se puedan ver sus commits.

El proceso vuelve a empezar

Si karelrubi quisiera crear una nueva característica, se desplazará hasta la rama upstream/develop y creará una nueva rama. El proceso se repite del mismo modo una y otra vez.

Actividad 2. Crea un grupo con otras dos personas. Uno de vosotros tendrá el repositorio base, y los otros dos componentes crearán un fork a partir de él.

Cada componente creará una nueva rama "feature", donde creará varios commits con cambios sencillos (como añadir un nuevo archivo, por ejemplo).

El propietario del repositorio base fusionará su rama "feature" con la rama "develop".

Los otros dos componentes crearán un pull request para que el propietario del repositorio base fusione los cambios en la rama develop

El objetivo de este ejercicio es poder ver que los diferentes repositorios, tanto el base como los fork contienen información coherente. Entrega la actividad en un archivo llamado Act2-github.zip, donde se debe incluir lo siguiente:

  • Un archivo de texto con el nombre de tu repositorio, ya sea base o fork
  • Una captura llamada <nombre_repositorio>_grafo.png con el resultado de ejecutar el comando git log --graph --all --oneline --decorate en tu repositorio local
  • La misma captura obtenida por tus otros compañeros.