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.