Usando Git(2): varios working copies
El el tutorial anterior, Usando Git(1), vimos cómo se inicia un proyecto en Git. En esta ocasión continuaremos con dicho proyecto, haciéndolo crecer hacia nuevos retos.
En esta ocasión dispondremos de varios working copies de la aplicación, lo que provocará que necesitemos más órdenes Git. Algunas de ellas van siendo algo avanzadas.
Trataré de introducirlas en un orden lógico, a medida que podemos ir necesitándolas.
Recordando
No viene mal repasar el dibujo que derrocha arte:
|
|
Ya conocemos las 5 zonas:
- Working copy con los archivos a modificar.
- Stash o cajón de sastre que aún no hemos utilizado
- Index para preparar nuestros commits
- local, nombre que le dimos a los archivos ocultos de Git en nuestra máquina
- remote, con los archivos de Git remotos.
Insisto una vez más en no confundier el Stash con el Index.
En esta ocasión, a penas hablaremos del Index, pero sí del Stash.
Progresando
Continuamos con el “Proyecto Fantabuloso” que nos va a hacer millonarios. Los ciclos add
y commit
dentro de ciclos push
nos funcionan bien, pero tenemos que viajar. La máquina de viaje, a la que llamaremos Fog en honor a Phileas Fogg, es un poco pesada pero también un poco lenta. Por eso en casa preferimos utilizar Flash, ya que es más rápida.
Primero tenemos que realizar la puesta a punto de Fogg, cosa que ya sabemos hacer:
|
|
Muy bien. ¿Y ahora qué? Si modificamos los archivos de Fogg, Flash estará desactualizada y viceversa. Supongamos que hicimos cambios en Flash, pusheamos y tenemos Fogg desactualizada. Existe una orden para traerse los cambios de remote a local:
|
|
Git puede parecer demasiado verboso cuando se está comenzando. No hace falta pelearse con toda esa información aún. Simplemente es necesario saber que ya tenemos en local todo lo que está en remote. El problema es que nuestra working copy no tiene todo lo que está en local. Podemos verlo fácilmente:
|
|
Me está diciendo que mi rama está 1 commit por detrás de lo que hay en el remote, y que puede ser “fast-forwardeada”. Eso sólo significa que alguien (yo) ha hecho cambios en remote y que aún no los tengo en mi working copy. Vamos, lo que ya sabíamos.
Hay distintas maneras de realizar esa operación, el “fast-forward”. “Fast-forward” tan sólo significa que “podemos avanzar sin problemas”.
|
|
Cuando hicimos el status
nos dijo que estábamos por detrás de “origin/master”, así que es de suponer que “origin/master” es como se llama al punto en que nos encontramos en remote. Y así es.
Al decir que queremos mezclar la versión que hay en remote, Git se da cuenta de que mezclar los cambios es sencillo y lo hace sin problemas. De esta manera es como si hubiéramos realizado nuestros siempre en Fogg.
Ya podemos continuar con nuestros ciclos add
-commit
-push
tranquilamente.
Conflictos
El escenario es el siguiente: en el tren la cobertura es muy mala y nos hemos visto obligados a continuar trabajando a sabiendas de que hay cambios en remote. Hemos realizado distintos ciclos add
-commit
, de manera que tenemos algo así:
|
|
Explico el gráfico: en el punto E pude hacer un fetch
y, por tanto, en ese punto Flash y Fogg son iguales. A partir de ahí cada una tiene unos cambios que no tiene la otra.
En cuanto llegamos a casa queremos arreglar este estropicio… Estamos seguros de que nos llevará horas.
Primero nos vamos a una máquina y hacemos push. No hay problemas. Ahora nos vamos a la otra y tratamos de hacer lo mismo:
|
|
¡Horror! Pero… ¿qué me está diciendo…? Dice que use pull
, pero no sé qué es eso. Vamos a hacer lo que hicimos antes, a ver qué ocurre:
|
|
Hmmm…. parece que no se queja. ¿Y si mezclamos? Bien, en ese caso pueden ocurrir dos cosas:
El mundo es precioso y maravilloso
|
|
Durante la operación se ha abierto un editor para que escribamos un comentario. Eso es porque Git ha sido capaz de resolver los conflictos y no necesita nuestra ayuda. Durante esta resolución, necesitó hacer un commit con los cambios de los dos sitios.
Resultado: ya está todo listo para continuar. Hacemos push
, nos vamos a la otra máquina, hacemos fetch
y status
y veremos que está todo preparado para hacer un “fast-forward”, por lo que podemos hacer un merge
y seguir trabajando como si nada.
El mundo tiene caminos llenos de piedras
|
|
La mezcla automática ha fallado, lo arreglo y hago commit. Pues muy bien. Vamos a ello.
Lo primero será editar el archivo del conflicto. Aunque nos lo dice el mensaje, podemos consultarlo:
|
|
veamos lo que contiene el archivo README. Veremos que será algo como esto:
|
|
¿Qué significa esto? Las líneas de “===” separan dos zonas, la de mis cambios en local (HEAD) de los cambios en remote (origin/master). Basta con editarlo como me guste a mí y borrar esas marcas. Una vez hecho, realizo el add
-commit
Una vez realizado, podemos volver a intentar un merge
. Si hay suerte, habremos terminado o Git será capaz de realizar los cambios por nosotros. Si no hay suerte… Habremos encontrado otra piedra, pero ya sabemos cómo resolver los conflictos.
Continuando
Hemos resuelto el problema. Ahora sabemos cómo trabajar desde dos máquinas sin importarnos perder la cobertura. Git comienza a demostrarnos el por qué de su fama.
¡Alto! ¡Un bug!
Mierda. Estábamos tan enfrascados en una característica nueva que no nos dimos cuenta y cometimos un error. Tenemos cambios en la working copy que no queremos perder, pero tampoco queremos que vayan en esta revisión (y recordemos que aún no sabemos qué coño es eso de las “ramas”).
¿Qué podemos hacer?
Bien, pues basta con guardarlo en un cajón. Y nuestro cajón se llama stash
|
|
Ahora podemos arreglar el bug, que era cosa de poco. Realizamos nuestro ciclo add
-commit
-push
y… ¿dónde lo habíamos dejado? Ah, sí, en el stash:
|
|
¿¿¿Cómo??? ¡¡Nos ha restaurado el espacio de trabajo!!
Al restaurar, igual que en un merge
, puede haber conflictos. Pero eso ya no nos asusta, ¿verdad?
Hay un par de órdenes muy interesantes, como stash list
, para ver qué tenemos en el stash:
|
|
o stash show
, para ver qué está modificado:
|
|
Suficiente por ahora
Y ya somos capaces de valernos por nosotros mismos. Nuestro “Proyecto Fantabuloso” progresa y no hemos necesitado ramas.
Veamos lo que hemos aprendido:
- Traer información del repositorio:
git fetch
- Mezclar la working copy y local:
git merge origin/master
- Resolver conflictos
- Meter en el stash:
git stash
- Sacar del stash:
git stash pop
Más información
De nuevo recomiendo la web de Git o el libro progit, de Scott Chacon.