Ramificaciones e integración de cambios en Git
Ya hemos visto como crear un repositorio con Git, también hemos hecho un par de commits bastante básicos. Ahora quiero hablar un poco acerca de las ramas en Git y básicamente que utilidad tienen, que es bastante. El proyecto mi libreria solo es la estructura de archivos y no tenemos nada de código aún, ¿Cómo continuar con el desarrollo?
Lo ideal es que siempre trabajemos la versión estable de nuestros proyectos en la rama master que es el estándar bajo el ecosistema Gitero. Es posible usar otro nombre de rama pero como un amigo mío dijo “las convenciones existen por algo, si no las sigues es síntoma de que un proyecto OpenSource fracase.
Preparativos
La rama que vamos a crear y utilizar intensivamente en el desarrollo es conocida como develop, a partir de esa rama podemos desprender otras ramas para desarrollar otras características de nuestro software sin afectar el desarrollo principal, ni mucho menos la versión estable del repositorio.
Para mostrar las ramas existentes localmente ejecutamos:
$ git branch
* master
Entonces creamos la rama develop:
$ git branch develop
$ git branch
develop
* master
El asterisco al inicio del nombre de una rama nos indica que estamos actualmente en dicha rama, para cambiar entre ramas debemos usar checkout:
$ git checkout develop
Switched to branch 'develop'
Bien, ahora si podemos comenzar el desarrollo de nuestro proyecto desde la rama develop. ¿No les parece genial?
Ramas inferiores
Es recomendable crear ramas cuando los cambios que llevemos a cabo tenga una relación entre sí, digamos, si vamos a editar tan solo nuestros archivos en include/ sería conveniente crear una rama exclusivamente para los cambios realizados ahí.
No es obligatorio, pero de verdad mas adelante descubrirán el poder que existe al separar nuestros cambios sin la posibilidad de afectar a otros archivos.
Así pues, vamos a crear una rama llamada include-specs a partir de nuestra rama actual (develop) donde describiremos lo que haga nuestro software:
$ git checkout -b include-specs
Switched to a new branch 'include-specs'
Este sería el contenido de nuestro archivo include/funciones.php:
<?php
/* Especificaciones */
# asignación sencilla
config('clave', 'valor');
# asignación múltiple
config(array('clave' => 'valor'));
# asignación múltiple (fancy)
config(function ($t) {
$t->clave = 'valor';
});
La bandera -b de checkout nos permite crear una nueva rama basada en la rama actual y cambiar a ella, usualmente es un atajo que nos ahorra el trabajo de hacer lo siguiente:
$ git branch include-specs
$ git checkout include-specs
Switched to a new branch 'include-specs'
Revisamos los cambios con status:
$ git status
# On branch include-specs
# 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: include/funciones.php
#
no changes added to commit (use "git add" and/or "git commit -a")
Hacemos commit y revisamos cambios de nuevo:
$ git commit -am "Especificaciones para config()"
1 files changed, 13 insertions(+), 0 deletions(-)
$ git status
# On branch include-specs
nothing to commit (working directory clean)
Más cambios, por favor
Excelente, ya sabemos crear ramas y realizar cambios que solo permanezcan ahí, para comprobarlo cambiamos a la rama develop y revisamos el contenido del archivo que modificamos en include-specs:
$ git checkout develop
$ cat include/funciones.php
No hay nada, y eso es bueno, quiere decir que vamos bien. Ahora necesitamos comenzar a implementar la función config()
para posteriormente hacer pruebas y si todo funciona como esperamos combinamos el resultado a nuestra rama develop.
Cambiamos de nuevo a la rama include-specs y agregamos lo siguiente a nuestro script de funciones:
/* Contenedor estático de configuraciones */
function config($key = NULL, $val = NULL) {
static $bag = array();
if (func_num_args() === 0) {
// Si no hay argumentos devolvemos la configuración
return $bag;
} elseif (is_string($key)) {
if (func_num_args() === 1) {
// Si solo hay un argumento devolvemos la opción (getter)
return isset($bag[$key]) ? $bag[$key] : NULL;
} else {
// Si hay dos argumentos asignamos un único valor (setter)
$bag[$key] = $val;
}
}
// TODO: implementar los specs restantes
}
/* Pruebas */
print_r(config());
Verificamos la sintaxis y ejecutamos el script desde la consola:
$ php -l include/funciones.php
No syntax errors detected in include/funciones.php
$ php include/funciones.php
Array
(
[clave] => valor
)
El script funciona, no en su totalidad, pero cumple al menos una de las especificaciones que contemplamos en nuestro script inicialmente.
Si no queremos perder los cambios que llevamos hasta este punto vamos a hacer commit y no más.
$ git commit -am "El primer spec funciona, y muy bien"
1 files changed, 27 insertions(+), 0 deletions(-)
Las banderas -am nos permiten agregar automáticamente los archivos modificados y establecer un mensaje para el commit.
Integrando los cambios, gracias
Hemos creado ya la rama develop, una auxiliar include-specs para separar los cambios en porciones y ya verificamos que nuestro código cumple las expectativas que nos planteamos. Entonces ya es tiempo de formalizar todo esto y llevar los cambios hacía la rama de desarrollo, hay que utilizar merge para finalizar nuestro trabajo del día de hoy:
$ git checkout develop
Switched to branch 'develop'
$ git merge include-specs
Updating 14d8578..cfdd6ae
Fast-forward
include/funciones.php | 40 ++++++++++++++++++++++++++++++++++++++++
1 files changed, 40 insertions(+), 0 deletions(-)
Y ahí tenemos, nuestros cambios realizados en la rama auxiliar los hemos integrado a la rama oficial de desarrollo.
Integrar cambios es lo más sencillo del mundo si mantenemos la calma y trabajamos en orden, despacio y por partes, si nos ponemos a editar y mover mucho código en una sola sesión de commits cuando intentemos mezclar los cambios nos vamos a encontrar conflictos. Tampoco son complicados de solucionar cuando hablamos de un solo archivo, pero bueno, creo que ya se darán una mejor idea cuando toquemos el tema.
¡Buen trabajo!
Es importante notar que no trabajamos directamente sobre la rama develop, mucho menos aún con la rama master. Aunque hay quienes les gusta arriesgar su trabajo poniendo en riesgo la integridad y estabilidad de su software pero no es conveniente hacer todo en un solo sitio, para eso están diseñadas las ramas y efectivamente funcionan. No hay que ser extremista tampoco, pero de verdad, un poco de sentido común basta.
Aunque por ahora no hemos terminado de usar la rama include-specs vamos a suponer que ya no sirve, pues nuestro código se encuentra estable y necesitamos eliminar referencias innecesarias. Veamos lo siguiente para ejemplificar:
$ git branch experimental
$ git branch -d experimental
Deleted branch experimental (was cfdd6ae).
Resumen
- Así como un commit debe ser considerado atómico, una rama debe tratarse como un conjunto de dichos átomos, es decir, una forma de agrupar cambios en común y no más.
- Es sencillo pensar en ramas cuando agregamos alguna funcionalidad a nuestro software, de hecho es la manera sugerida para su utilización.
Por ahora no vamos a profundizar a detalle sobre banderas y opciones de cada comando así como ningún tipo de técnica avanzada. La idea de estos ejercicios es mostrar el flujo de trabajo mas sencillo posible que se puede llevar a cabo con Git. Hay escenarios mas complejos y cuando se trabaja con más de una persona pueden suceder cosas complicadas, pero no hay que temer, Git es el salvador de nuestro código.
Github: Mi librería.
muy buena entrega! hasta aquí más o menos lo sabía manejar aunque me quedó muy claro la parte teórica (que la tenía más flojita).
sería bueno que hablen un poco sobre el sistema de taggeado de git y las buenas prácticas, tal como lo vienen haciendo!
saludos y felicitaciones!
Hola Álvaro, soy desarrollador de .NET y por lo tanto estoy más familiarizado con el control de versiones Team Foundation Server, ahora mismo ando intentando desarrollar para iOS en grupo con varias personas y es la primera vez que me enfrento a Git o Subversion y aún no entiendo bien su cometido.
Estos programas guardan versiones de archivos pero no permiten la exclusividad al modificar éstos archivos ¿verdad? voy a intentar aprender todo lo que aquí expliques.
¿Podrías ayudarme a aprender una metodología para desarrollar teniendo en cuenta que varias personas pueden editar el mismo archivo en el mismo momento?
¿Git descarga automáticamente los commit que realizan los demás usuarios?
¡Muchisimas gracias!
Un saludo.
Leete el capitulo uno, ahi te explica como funciona el control de versiones, y algunas dudas mas que planteaste.
Pueden editar dos archivos a la vez en maquinas diferentes, y despues mergearlo, esto no te garantiza que quede perfecto, pero si surge algun conflicto te avisa para que lo analices.
los commit no se hacen automaticos (Gracias a Dios), pero leete el primer post para entender este punto.
Carlos, me parece excelente que tengas dudas, sin ellas no podríamos avanzar en esta vida.
Solo te invito a seguir el hilo de los temas ya que por ahora no pienso abarcar temas como el manejo de versiones entre mas de una persona. Es parte del plan, pero primero necesito dar una vuelta bastante básica a Git.
Lo importante es manejar un flujo básico de trabajo con Git, si los integrantes del equipo trabajan de la misma manera hacer merge es cuestión de magia y la mayoría del tiempo no hay que preocuparse demasiado.
Gracias por tus comentarios.
Hey Alvaro ya tengo arriba la estructura de mi app, genere una rama de desarrollo y ahora voy a empezar a crear el login. ¿Es correcto crear una rama(develop-login) para trabajar en el login?