Documentos de Académico
Documentos de Profesional
Documentos de Cultura
En primer lugar se abordan los conceptos técnicos, es decir, los comandos nece-
sarios para la mayorı́a de las operaciones y el funcionamiento y filosofı́a del sistema
de control de versiones git.
Índice general I
Índice de figuras II
1. Tutorial 1
1.1. Descripción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2. Importar un proyecto nuevo . . . . . . . . . . . . . . . . . . . . . . 1
1.3. Realizando cambios . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.4. Git controla contenidos, no ficheros . . . . . . . . . . . . . . . . . . 3
1.5. Consultando la evolución del proyecto . . . . . . . . . . . . . . . . . 3
1.6. Gestionando ramas . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.7. Git como herramienta de colaboración . . . . . . . . . . . . . . . . 6
1.8. Explorando el histórico . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.9. Siguientes pasos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Referencias 26
i
Índice de figuras
ii
Capı́tulo 1
Tutorial
1.1. Descripción
Git es un software de control de versiones diseñado por Linus Torvalds, pensando
en la eficiencia y la confiabilidad del mantenimiento de versiones de aplicaciones
cuando éstas tienen un gran número archivos de código fuente.
En este tutorial sobre git [1] se explicará cómo importar un proyecto, hacer cambios
en él y compartir esos cambios con otros desarrolladores.
Antes de nada señalaremos que se puede conseguir documentación para cualquier
comando de git en una lı́nea de comando tipo UNIX con un comando del estilo de
$ git init
1
1.3. Realizando cambios 2
$ git add .
$ git commit
Ahora ya estás listo para hacer un commit. Puedes ver los cambios que vas a
confirmar usando git diff con la opción --cached:
(Sin --cached, git diff te mostrarı́a cualquier cambio que hayas hecho pero
no hayas añadido al ı́ndice.) También puedes obtener un resumen del estado del
repositorio con git status:
$ git status
# On branch master
# Changes to be committed :
# ( use " git reset HEAD < file >..." to unstage )
#
# modified : file1
# modified : file2
1.4. Git controla contenidos, no ficheros 3
# modified : file3
#
Si necesitas hacer algún ajuste adicional, hazlo ahora, y entonces añade cualquier
archivo nuevamente modificado al ı́ndice. Finalmente, confirma tus cambios con:
$ git commit
$ git commit -a
$ git log
$ git log -p
En muchas ocasiones un resumen de los cambios es útil para tener una idea sobre
cada etapa:
Si ahora ejecutas
$ git branch
experimental
* master
( editar fichero )
$ git commit -a
$ git checkout master
( editar fichero )
$ git commit -a
en este momento las dos ramas son divergentes, con diferentes cambios realizados
en cada una. Para juntar los cambios de la rama “experimental” en “master”, ejecuta
$ git diff
nos mostrará esto. Una vez que hayas editado el fichero para resolver los conflictos,
$ git commit -a
$ gitk
Las ramas con sencillas y rápidas, por lo que probarlas es una buena práctica.
1.7. Git como herramienta de colaboración 6
Esto crea un nuevo directorio “mirepo” con una copia del repositorio de Alicia. La
copia es exactamente igual al proyecto original, teniendo su propia copia del histórico
del original.
Roberto entonces hace algunos cambios y los confirma:
( editar ficheros )
rober$ git commit -a
( repetir si es necesario )
Cuando esté listo, le dice a Alicia que traiga sus cambios desde el repositorio en
/home/rober/mirepo. Para ello hace:
Esta operación es segura incluso si Alicia tiene cambios locales sin confirmar. La
notación de rango “HEAD..FETCH HEAD” significa “muestra todo lo que es alcan-
zable desde FETCH HEAD pero excluye todo lo que sea alcanzable desde HEAD”.
Alicia ya conoce todo lo que conduce a su estado actual (HEAD), y comprueba lo
que Roberto tiene en su estado (FETCH HEAD) que ella no ha podido ver con este
comando.
Si Alicia quiere visualizar lo que hizo Roberto desde que sus trabajos divergieron
puede hacerlo con el siguiente comando:
Esto emplea la misma notación de rangos con dos puntos que vimos antes en git
log.
Alicia puede querer ver qué hicieron exactamente los dos desde que divergieron.
Puede usar lo notación de tres puntos en lugar de la de dos:
Esto significa “muestra todo lo que es alcanzable desde cualquiera de ellos, pero
exclude lo que sea alcanzable desde ambos”.
Toma nota de que esta notación para el rango se puede emplear tanto para gitk
como para git log.
Tras inspeccionar lo que Roberto hizo, si no hay nada urgente, Alicia decide
continuar trabajando sin aplicar los cambios de Roberto. Si el trabajo de Roberto
tuviera algo urgente para Alicia, ella decidirı́a apartar sus cambios, descargar lo que
realizó Roberto y luego aplicar su trabajo en los ficheros resultantes.
Cuando se trabaja en un grupo pequeño y cercano, no es habitual interactuar con
el repositorio una y otra vez. Definiendo un repositorio remoto se simplifica:
Con esto, Alicia puede realizar la primera parte de la operación de “pull” por
separado usando el comando git fetch sin tener que mezclar los cambios con su
propia rama, usando:
Al contrario que la forma más larga, cuando Alicia realiza “fetch” desde Roberto
usando el atajo con un repositorio remoto preparado con git remote, los cambios que
fueron descargados de almacenan en una rama con información remota, en este caso
rober/master. Ası́ que después de esto:
enseña una lista de todos los cambios que Roberto ha hecho desde que creó su
rama a partir de la rama “master” de Alicia.
Tras examinar esos cambios, Alicia puede mezclarlos en su rama “master”:
Este merge puede hacerse también actualizando desde su propia rama de segui-
miento remoto, de este modo:
Nótese que “git pull” siempre mezcla en la rama actual, sin importar ninguna otra
cosa en la lı́nea de comando.
Más tarde, Roberto puede actualizar su repo con los últimos cambios de Alicia
empleando
Nótese que no necesita dar la ruta al repositorio de Alicia; cuando Roberto clonó el
repositorio de Alicia, git almacenó la localización de su repositorio en la configuración
del repositorio, y esa localización es la usada para el “pull”:
(La configuración completa creada por git clone es visible usando git config
-l, y git-config explica el significado de cada opción.)
Git también mantiene una copia limpia de la rama “master” de Alicia bajo el
nombre “origin/master”:
Si Roberto decide más adelante trabajar desde un host diferente, todavı́a puede
realizar operaciones “clone” y “pull” con ssh:
$ git logcommit c 8 2 a 2 2 c 3 9 c b c 3 2 5 7 6 f 6 4 f 5 c 6 b 3 f 2 4 b 9 9 e a 8 1 4 9 c 7
Author : Junio C Hamano < junkio@cox . net >
Date : Tue May 16 17:18:22 2006 -0700
Podemos pasar este nombre a git show para ver detalles sobre ese commit.
$git show c 8 2 a 2 2 c 3 9 c b c 3 2 5 7 6 f 6 4 f 5 c 6 b 3 f 2 4 b 9 9 e a 8 1 4 9 c 7
Pero hay otros modos de referenciar commits. Puedes emplear cualquier trozo
inicial del nombre que sea suficientemente largo como para identificar de manera
inequı́voca al commit:
Todos los commits tienen habitualmente un commit “padre” que apunta al estado
previo del proyecto:
Nótese que los commits de mezcla (operaciones “merge”) pueden tener más de
un padre:
También puedes dar tus propios nombres a los commits; tras ejecutar
Ten cuidado con este último comando: además de perder cualquier cambio en
el directorio de trabajo, eliminará los commits más recientes de esta rama. Si esta
rama es la única que contiene esos commits, se perderán. Tampoco debemos usar git
reset en una rama visible públicamente de la que otros desarrolladores actualizan, ya
que obligará a realizar operaciones “merge” innecesarias para limpiar los históricos.
Si necesitas deshacer cambios que has confirmado, emplea git revert en su lugar.
El comando git grep puede buscar cadenas en cualquier versión de tu proyecto,
ası́ que
realizará a la inversa.
El comando git log tiene un contra: debe presentar los commits en una lista.
Cuando un histórico tiene lı́neas de desarrollo que divergieron y se juntaron de nuevo,
el orden en el que git log presenta esos commits no tiene sentido.
La mayorı́a de los proyectos con múltiples colaboradores (como el kernel de Linux
o el propio git) tienen operaciones “merge” frecuentes, y gitk realiza un mejor trabajo
para visualizar su histórico. Por ejemplo,
permite navegar por cualquiera de los commits de las últimas 2 semanas que
modificaron cualquier fichero bajo el directorio “driver” (Nota: la fuente de gitk se
puede ajustar presionando la tecla Ctrl y “-” o “+”.)
Finalmente, la mayorı́a de los comandos que toman nombres de ficheros opcional-
mente permitirán preceder cualquier nombre de fichero con un commit, para especi-
ficar una versión concreta del fichero:
El fichero de ı́ndice es una caché del estado del árbol de directorio, usado para
crear commits, confirmar cambios en directorios de trabajo y almacenar los
diversos árboles vinculados en una operación “merge”.
2.1. Introducción
En este apartado se recoge el modelo de trabajo propuesto por Vincent Driessen
y explicado en su blog [2].
13
2.2. ¿Por qué git? 14
master
develop
La rama master en origin será familiar para todo usuario de Git. De forma para-
lela a la rama master, existe otra llamada develop. Consideramos origin/master
como la rama principal donde el código fuente de HEAD siempre está en un estado
de versión de producción estable.
Consideramos origin/develop la rama principal donde el código fuente de
HEAD siempre refleja el estado de los últimos cambios realizados pendientes de aplicar
a la siguiente release. Algunos llamarı́an a esto “rama de integración”.
Cuando el código dentro de la rama develop alcanza un punto estable y está listo
para ser liberado, todos los cambios deberı́an ser aplicados en la rama master y
marcados con un tag con el número de versión. Más adelante discutiremos en detalle
este proceso.
2.5. Soportando ramas 16
Por lo tanto, cada vez que se aplican cambios en master, es una nueva versión
de producción por definición. Siendo muy estrictos en este aspecto, teóricamente
podrı́amos usar un script para automáticamente compilar y desplegar nuestro software
en nuestros servidores cada vez que hay un commit en master.
Cada una de estas ramas tendrá un propósito especı́fico y estará sometida a reglas
estrictas como de qué ramas pueden nacir y con cuáles se pueden mezclar. Hablaremos
de ellas en un minuto.
2.5. Soportando ramas 17
De ningún modo estas ramas son especiales desde un punto de vista técnico. Las
ramas las categorizamos según cómo las empleamos. Todas son por supuesto simples
ramas de Git.
El flag --no-ff hace que el “merge” siempre cree un nuevo objeto commit, incluso
si la operación fue realizada con “fast-forward”. Esto evita la pérdida de información
sobre la existencia histórica de la rama y agrupa todos los commits que conforman la
caracterı́stica nueva. Compara:
En el último caso es imposible saber del histórico de Git cuáles de los objetos
commit juntos conforman la caracterı́stica - habrı́a que leer manualmente el log.
Revertir una caracterı́stica completa (i.e. un grupo de commits), es un quebradero de
cabeza en este caso, mientras que es mucho más fácil si se utilizó el flag --no-ff.
Sı́, creará unos pocos más objetos commit (vacı́os), pero la ganancia supera con
creces a las pérdidas.
Desafortunadamente, aún no conozco ningún modo de hacer que --no-ff sea el
comportamiento por defecto de git merge, pero deberı́a ser ası́.
Este paso puede llevar fácilmente a un conflicto, y en tal caso deberı́amos solu-
cionarlo y hacer commit.
Ahora ya hemos acabado realmente y la rama de release debe ser eliminar, ya que
no la necesitamos más:
Las ramas para arreglos rápidos se parecen mucho a las ramas de release en que
también están pensadas para preparar una nueva versión de release, pero en este
caso no planeada. Nacen de la necesidad de actuar inmediatamente ante un estado
no deseado en la versión actual en producción. Cuando un bug crı́tico de la versión
actual debe ser solucionado inmediatamente, una rama de arreglo rápido puede nacer
del tag correspondiente de la rama master que marca la versión en producción.
La esencia es que el trabajo de miembros de equipo (en la rama develop) puede
continuar, mientras otra persona está preparando una solución rápida.
De nuevo, quizás quieras usar los flags -s o -u <clave> para firmar el tag crip-
tográficamente.
Luego incluimos el arreglo también en develop:
La excepción a esta regla es que, cuando actualmente existe una rama de release,
la solución al bug será mezclada en esa rama de release en lugar de en develop.
Aplicar la solución en la rama de release conduce a que en algún momento sea
también aplicado a la rama develop, cuando la rama de release se termine. (Si el
trabajo en develop requiere la solución al bug inmediatamente y no podemos esperar
a que la rama de release se termine, también podemos aplicar la solución en develop
sin problemas.)
Finalmente, eliminamos la rama temporal:
2.6. Resumen
Aunque realmente no hay nada nuevo en este modelo de ramificación, la imagen
general en la que se basa ha demostrado ser tremendamente útil en nuestros proyectos.
Conforma un modelo mental muy elegante que es fácil de comprender y permite
a miembros de equipos compartir una única visión del proceso de ramificación y
liberación del software.
Capı́tulo 3
Comenzando a trabajar con
Git en Windows
1. Nos descargamos la versión más reciente del entorno (los archivos con formato
Git-x.x.x.x) de su web oficial.
2. Durante la instalación se aconseja instalar las dos entradas del menú de contexto
en lugar del git-cheetah.
24
3.2. Inicialización del repositorio para NetBeans 25
1. Iniciaremos la interfaz gráfica de Git (es indiferente si con el click derecho sobre
una carpeta cualquiera o por el menú de inicio), y seleccionamos Clone Existing
Repository.
Una vez completado, podemos comprobar que es correcto si al hacer click dere-
cho sobre la carpeta del proyecto y pulsar en Git GUI Here nos abre directamente el
repositorio y no la ventana inicial para crear, clonar y abrir repositorios.
Creamos un proyecto con el nombre que deseemos, y copiamos dentro los con-
tenidos descargados del repositorio.
Muy probablemente debamos copiar también las librerı́as que necesita el pro-
yecto, manteniendo la misma ruta que en la configuración original del proyecto
(podemos comprobar la ruta con Click derecho sobre el proyecto -> Properties
-> Libraries).
Una vez que la configuración de las librerı́as está lista, de nuevo podemos com-
probar que todo es correcto si Git GUI nos abre el repositorio en lugar de la pantalla
inicial.
Referencias
26