Tutorial - Trabajando con ramas
¡Hola a todos! Es importante cuando estamos trabajando con Git tener una política de ramas con la que el equipo se sienta cómodo. En otro post profundizaremos en Gitflow, pero hoy os voy a dar unas nociones básicas de cómo empezar a trabajar con ramas y os dejaré un tutorial práctico para que podáis probarlo vosotros mismos.
Política de ramas
Cuando trabajamos con Gitflow tenemos varias ramas que nos sirven para diferentes propósitos: implementar una funcionalidad, corregir un bug en producción, preparar una release…
Nosotros para este tutorial, vamos a simplificarlo bastante. Vamos a trabajar con una rama principal (master) y vamos a ir implementando funcionalidades mediante feature branches.
Introducción
Planteamos un ejemplo con unos tests unitarios. Vamos a ir implementando la funcionalidad poco a poco, trabajando con ramas y colaborando con nuestros compañeros. El código para empezar el tutorial lo tenéis disponible en Github.
Para probar el ejemplo, basta con ejecutar el script de python:
python main.py
A medida que vayamos avanzando en el tutorial, iremos completando los métodos, haciendo que pasen todos los tests.
Squash
El Squash es una técnica que nos permite agrupar los cambios de varios commit
en uno.
El Squash se hace a través de un rebase
interactivo, que nos da mayor control de cómo se ejecuta la reorganización del trabajo.
El comando básico es:
git rebase -i HEAD~{number_of_commits}
Lo que indicamos es el número de commit
que queremos agrupar. Para que sea más sencillo y no tener que contar cuántos commit
quiero agrupar, podemos indicar contra qué rama queremos que se haga la resta. De tal forma que nos agrupa aquellos commit
que están por delante en la rama actual.
git rebase -i origin/master
Nueva rama de feature
Estando en master
, creamos una nueva rama para desarrollar la funcionalidad que afecta a las operaciones de las listas.
(master)$ git checkout -b feature/list
Count
Lo primero que vamos a hacer es implementar la función de count
:
def count(input):
try:
input[0]
return 1 + count(input[1:])
except:
return 0
Una vez terminada, hacemos un commit
:
(feature/list)$ git commit -a -m "Add count"
Sum
A continuación, implementamos la función sum
y hacemos commit
:
def sum(input):
try:
input[0]
return input[0] + sum(input[1:])
except:
return 0
(feature/list)$ git commit -a -m "Add sum"
Max/Min
Implementamos las funciones max
y min
. A continuación, hacemos commit
:
def max(input):
items_count = count(input)
if items_count == 0:
return 0 # Only for 0 items list
elif items_count == 1:
return input[0]
else:
max_other = max(input[1:])
return max_other if max_other > input[0] else input[0]
def min(input):
items_count = count(input)
if items_count == 0:
return 0 # Only for 0 items list
elif items_count == 1:
return input[0]
else:
min_other = min(input[1:])
return min_other if min_other < input[0] else input[0]
(feature/list)$ git commit -a -m "Add max and mix"
Sort
A continuación, implementamos la función sort
y hacemos commit
:
def sort(input):
items_count = count(input)
if items_count <= 1:
return input
return sort([e for e in input[1:] if e <= input[0]]) + [input[0]] + sort([e for e in input[1:] if e > input[0]])
(feature/list)$ git commit -a -m "Add sort"
Squash
Una vez hemos terminado la funcionalidad, podemos hacer el rebase -i
para agrupar los commits.
Nota: Como lo queremos hacer contra origin/master
, hacemos un fetch
para asegurarnos que la rama está actualizada.
(feature/list)$ git fetch
(feature/list)$ git rebase -i origin/master
A continuación, nos aparecerá un listado con los commit
que hay para que podamos elegir cómo queremos que se haga el rebase
. Debemos dejar el primer marcado como pick y el resto los tenemos que marcar como squash.
pick 43fa23 Add count
s 13fa1e Add sum
s 2aff1e Add max and min
s 245eef Add sort
Simplemente añadimos el mensaje del commit
:
Add list functions
Push y Pull Request
Una vez tenemos nuestra rama preparada para integrarse con la rama principal, en este caso master
, tenemos dos opciones: o hacer un merge
en master
o subir la rama y hacer una Pull Request.
Merge
Lo que tenemos que hacer es ir a la rama master
, asegurarnos de que está actualizada, hacer un merge
y subir master
al remoto.
(feature/list)$ git checkout master
(master)$ git fetch
(master)$ git pull
(master)$ git merge feature/lists
(master)$ git push origin master
Pull Request
En este caso, únicamente subimos la rama feature/list
y hacemos la gestión de la Pull Request desde el portal de Azure DevOps o Github.
(feature/list)$ git push origin feature/list
Rebase
Otro punto importante cuando trabajamos con Git es poder adaptarnos a que haya código que necesitemos y que se encuentren en otras ramas.
Para poder traernos ese código utilizaremos el comando rebase
.
Al igual que hemos hecho antes, vamos a implementar la nueva funcionalidad en diferentes commit
y luego haremos un Squash.
Primero creamos una nueva rama desde master
.
(master)$ git checkout -b feature/calc
Mult
Impementamos el método mult
y hacemos un commit
.
def mult(n1, n2):
if n1 == 0 or n2 == 0:
return 0
if n1 < 0 and n2 < 0:
return abs(n1) + mult(abs(n1), abs(n2)-1)
elif n2 < 0:
return n2 + mult(n1-1, n2)
else:
return n1 + mult(n1, n2-1)
(feature/calc)$ git commit -a -m "Add mult"
Div
A continuación, implementamos la función div
y hacemos un commit
.
def div(n1,n2):
if n2 == 0:
raise ZeroDivisionError
elif n1 == 0:
return 0
elif abs(n1) < abs(n2):
return 0
elif n1 < 0 and n2 < 0:
return 1 + div(abs(n1)-abs(n2), abs(n2))
elif n1 < 0 or n2 < 0:
return -1 + div(n1+n2, n2)
else:
return 1 + div(n1-n2, n2)
(feature/calc)$ git commit -a -m "Add div"
Squash y crear una Pull Request
Lo siguiente que hacemos es hacer un Squash de nuestros dos commit
y subir la rama feature/calc
para hacer una Pull Request.
(feature/calc)$ git fetch
(feature/calc)$ git rebase -i origin/master
(feature/calc)$ git push origin feature/calc
Hacemos una Pull Request, pero nosotros tenemos que seguir trabajando.
Nueva rama y Rebase
Una vez que hemos hecho la Pull Request, tenemos que dejar tiempo para que nuestros compañeros puedan revisarla y validarla. Pero nosotros tenemos que seguir trabajando.
Para ello vamos a crear una nueva rama desde master
y hacernos un rebase
desde origin/feature/calc
para poder seguir con el código que en que ya estábamos trabajando.
(feature/calc)$ git checkout master
(master)$ git fetch
(master)$ git pull
(master)$ git checkout -b feature/calc-1
(feature/calc-1)$ git rebase origin/feature/calc
Pot
Implementamos el comando pot
y hacemos un commit
.
def pot(b,e):
if e == 0:
return 1
elif b == 0:
return 0
elif e < 0:
return 1 / pot(b, -e)
else:
return mult(b, pot(b, e-1))
(feature/calc-1)$ git commit -a -m "Add pot"
Cambios en la Pull Request
En ese momento, nos sugieren cambios en la Pull Requst. Nos piden implementar nuestro propio método abs
. Lo primero que tenemos que hacer es volver a la rama feature/calc
para implementar ahí la nueva funcionalidad.
(feature/calc-1)$ git checkout feature/calc
Añadimos los test unitarios para el método abs
:
{'test': lambda: abs(0), 'expected': 0, 'method': "abs of zero"},
{'test': lambda: abs(5), 'expected': 5, 'method': "abs of positive number"},
{'test': lambda: abs(-5), 'expected': 5, 'method': "abs of negative"},
E implementamos la función abs
:
def abs(n):
if n >= 0:
return n
else:
return -n
Por último, hacemos un commit
.
(feature/calc)$ git commit -a -m "Add abs"
De nuevo, hacemos un Squash y subimos el código. Esta vez, como hemos cambiado la historia de Git, tendremos que añadir el argumento -f
al push
.
(feature/calc)$ git fetch
(feature/calc)$ git rebase -i origin/master
(feature/calc)$ git push origin feature/calc -f
Por fin nuestros compañeros nos aprueban la Pull Request, así que ya podemos completarla.
Actualizar mi rama con el trabajo integrado en master
Lo siguiente que hacemos, es volver a la rama feature/calc-1
y hacer un rebase
de origin/master
, después de hacer un fetch
para tener la rama actualizada.
(feature/calc)$ git checkout feature/calc-1
(feature/calc-1)$ git fetch
(feature/calc-1)$ git rebase origin/master
Fac
Continuamos con nuestro trabajo de forma normal en la rama feature/calc-1
. Añadimos ahora, la función fac
y hacemos commit
.
def fac(n):
if n == 0:
return 1
elif n < 0:
return mult(n, fac(n+1))
else:
return mult(n, fac(n-1))
(feature/calc-1)$ git commit -a -m "Add fac"
Finalizamos nuestro trabajo: Squash, push y Pull Request
Hacemos el Squash y subimos la rama.
(feature/calc-1)$ git fetch
(feature/calc-1)$ git rebase -i origin/master
(feature/calc.1)$ git push origin feature/calc-1
Creamos la Pull Request y, tras que nos aprueben nuestros compañeros, la completamos para finalizar nuestro trabajo.
Siguientes pasos
El objetivo de este tutorial es ver el uso de las feature branches y poder mostrar cómo se trabaja con ellas y cómo podemos integrar código en las ramas principales.
Cualquier duda sobre el tutorial, por favor, ponedla en los comentarios. En siguientes post podemos ver más sobre Gitflow y cómo trabajar con otro tipo de ramas.
¡Nos vemos en el futuro!