Por admin |

Este artículo es una introducción y me sirve de guía de uso y aprendizaje, como todos los artículos aquí expuestos, no esperéis un manual pormenorizado. He comenzado a colaborar en un proyecto de desarrollo en grupo y en este usan GIT, por ello vamos a ver para que sirve y como se usa.

Git es un software de control de versiones, un sistema que registra los cambios realizados sobre un archivo o conjunto de archivos a lo largo del tiempo, de modo que puedes recuperar versiones específicas más adelante.

Existen diferentes modos de enfocar el control de versiones, las más populares son un repositorio centralizado (SVN) o un repositorio distribuido (Git).

Repositorio centralizado

Esto es un lugar donde se almacena el proyecto en su totalidad. Así los usuarios se conectan al repositorio central y pueden descargar el código o hacer commits (enviar sus cambios) hacia este.

Repositorio distribuido

Cada cliente tiene una copia local de todo el proyecto, es decir todo el histórico, etiquetas, ramas, etc. Así los clientes pueden hacer commits parciales, y pensar en una funcionalidad por rama.

Instalando Git

Vamos a empezar a usar un poco de Git. Lo primero es lo primero: tienes que instalarlo. Puedes obtenerlo de varias maneras; las dos principales son instalarlo desde código fuente, o instalar un paquete existente para tu plataforma.

Para instalar Git, necesitas tener las siguientes librerías de las que Git depende: curl, zlib, openssl, expat, y libiconv. Por ejemplo, si estás en un sistema que tiene yum (como Fedora) o apt-get (como un sistema basado en Debian), puedes usar uno de estos comandos para instalar todas las dependencias:

$ yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel

$ apt-get install libcurl4-gnutls-dev libexpat1-dev gettext libz-dev

Cuando tengas todas las dependencias necesarias, puedes descargar la versión más reciente de Git desde su página web:

$ wget http://git-scm.com/download

Luego compila e instala:

$ tar -zxf git-1.6.0.5.tar.gz
$ cd git-1.6.0.5
$ make prefix=/usr/local all
$ sudo make prefix=/usr/local install

Una vez hecho esto, también puedes obtener Git a través del propio Git para futuras actualizaciones:

$ git clone git://git.kernel.org/pub/scm/git/git.git

Instalando en Linux

Si quieres instalar Git en Linux a través de un instalador binario, en general puedes hacerlo a través de la herramienta básica de gestión de paquetes que trae tu distribución. Si estás en Fedora, puedes usar yum:

$ yum install git-core

O si estás en una distribución basada en Debian como Ubuntu, prueba con apt-get:

$ apt-get install git-core

Explicando GIT con ejemplos

Creo que la mejor forma de aprender es viendo ejemplos. Ahora explico una de las maneras de trabajar con Git, existen muchas otras formas.

Tengo un proyecto que funciona perfectamente en mi repositorio GIT (al proyecto que funciona se le rama master ) y quiero crear una nueva funcionalidad o experimentar algo nuevo. Entonces hago esto:

$ git branch experimento1
$ git checkout experimento1

He creado una rama nueva y en esta rama puedo hacer lo que quiera como crear la kill feature de mi proyecto, incluso puedo hacer commits por si existen errores en esta nueva rama.

Sigo trabajando y si al final veo que este experimento me gusta puedo integrarlo con la rama master así:

$ git checkout master
$ git merge experimento1

Pero puede que los cambios no me gusten, o que quiera dejar de momento el proyecto sin el nuevo experimento. Entonces solo tengo que hacer:

$ git checkout master
$ git branch -D experimento1

Podemos obtener un proyecto Git o directorio de un repositorio existente en otro servidor llamemos le remoto, esta es la opción que nos interesa para nuestro proyecto.

Pero antes de nada vamos a ver los comandos disponibles en la ayuda de Git.

$ git help
$ git --help
$ man git

Vamos a ver ejemplos de estos y su uso:

$ git config --system

archivo ~/.gitconfig (configuración global para un usuario dentro del sistema)

$ git config --global

archivo .git/config (configuración específica para el repositorio actual)

$ git config --global user.name "Carlos Fernandez"
$ git config --global user.email "carlos.fernandez@dominio.com"

Verificar las opciones de configuración

$ git config --list

Inicializar un repositorio git en el directorio actual, crea un nuevo directorio .git con el esqueleto básico. Ningún fichero es "traqueado" todavía.

$ git init

Comenzar el control de versiones de ficheros existentes

$ git add *.c
$ git add README
$ git commit -m "Versión inicial del proyecto"

Obtener una copia de un repositorio existente

$ git clone git://githup.com/schacom/grit.git 

(crea el directorio de nombre grit, inicializa y descarga los datos en el directorio git y crea el directorio de trabajo con la última versión del repositorio)

$ git clone git://githup.com/schacom/grit.git mi-grit 

(hace lo mismo que el comando anterior pero en lugar de crear el directorio grit crea el directorio mi-grit poniendo toda la información en este directorio)

Cada fichero en tu área de trabajo puede estar en uno de estos dos estados: traqueado (ya presente en la última instantánea). Al estar traqueado puede estar no modificado, modificado o preparado (staged). O puede estar no traqueado (ni preparado ni en la última instantánea)

Verificar el estado de tus ficheros

$ git status

Traquear y preparar ficheros no traqueados (ATENCIÓN: versión actual de los ficheros, no las modificaciones a los ficheros después de la ejecución de este comando)

$ git add

Ignorar ficheros

$ nano .gitignore

Formato del fichero .gitignore

  • Las líneas en blancas o comenzando por # son ignoradas
  • Los patrones estándar de "globing" funcionan (como los comodines *)
  • Puedes terminar un patrón con una barra '/' para especificar un directorio
  • Puedes negar un patrón comenzando por un carácter de exclamación

Ejemplo de fichero .gitignore

# comentario - esto es ignorado
*.a # ignorar todos los ficheros con extensión .a
!lib.a # pero traquear el fichero lib.a, incluso aunque se ignoren los ficheros con extensión .a por la linea anterior 
/TODO # sólo ignorar el fichor TODO de la raiz, no /subdirectorio/TODO
build/ # ignorar todos los ficheros en el directorio build/
doc/*.txt # ignorar doc/notes.txt, pero no doc/server/arch.txt por ejemplo

Viendo los cambios preparados y no preparados

$ git diff (cambios no preparados)
$ git diff --staged (que está preparado e irá en el próximo envío, commit)
$ git diff --cached (igual que el anterior)

Enviando tus cambios (commit)

$ git commit 
$ git commit -m "Mensaje de envío"

Evitando el área de preparación "stage area"

$ git commit -a -m "Commit message" 

(permite evitar la ejecución del git add)

Eliminando ficheros

$ rm 
$ git status 
$ git rm (esta es la única linea necesaria y suficiente para eliminar ficheros)

Mover ficheros

$ git mv

Ver el historial de envíos

$ git log 
$ git log -p -2 (ver los dos últimos envíos) 
$ git log stat 
$ git log --pretty=oneline (otras opciones de pretty: short, full, fuller y format) 
$ git log --pretty=format:"%h - %an, %ar, %s" 

Opciones de "format". Descripción de la opción y salida:

  • %H Hash del envío
  • %h Hash del envío abreviado
  • %T Hash del árbol de directorios
  • %t Hash del árbol de directorios abreviado
  • %P Hash del envío padre
  • %p Hash abreviado del envío padre
  • %an Nombre del autor
  • %ae E-mail del autor
  • %ad Fecha del autor del envío (el formato respeta la opción -date=)
  • %ar Fecha del autor del envío, relativa
  • %cn Nombre de la persona que ejecutó el envío (commit)
  • %ce E-mail de la persona que ejecutó el envío (commit)
  • %cd Fecha del envío
  • %cr Fecha del envío, relativo
  • %s Mensaje del envío
$ git log --pretty=oneline --graph (pequeño gráfico ASCII incluido en la salida)

Limitar informe log

$ git log --since=2.weeks

Usando un GUI (interfaz de usuario gráfico) para visualizar el historial

$ gitk 

Modificar el último envío (commit)

$ git commit --amend

(modifica el último commit con los nuevos cambios incluidos en este commit. El resultado es un simple commit)

Sacando fichero del área de envío (unstaging)

$ git reset HEAD

Volviendo a su anterior estado un fichero modificado en el directorio de trabajo

$ git checkout -- 

Mostrando servidores remotos

$ git remote
$ git remote -v

Añadiendo repositorios remotos

$ git remote add 
$ git remote add pb git://githup.com/paulboone/ticgit.git

Obtener datos desde repositorio remoto

$ git fetch 
$ git pull (obtiene los datos remotos y los mezcla desde rama remota a la rama actual)

Enviando datos a tus repositorios remotos

$ git push 
$ git push origin master

Inspeccionando un repositorio remoto

$ git remote show

Eliminar o renombrar repositorios remotos

$ git remote rename (renombrar repositorio remoto) 
$ git remote rm (eliminar repositorio remoto de tu lista de remotos)

Como afrontar la ramificación o brach en GIT

Existen en internet multitud de discusiones sobre los pro y los contras, Git da a los desarrolladores una nueva forma de pensar, en fusión y ramificación. Desde CVS/Subversión siempre se ha tenido un poco de miedo por las bifurcaciones, sobre todo con los conflictos al mezclar (merge)

La configuración que utilizamos y que funciona viene con este modelo de ramificación, es tener un repositorio central. Git es distribuido y no hay un repositorio central a nivel técnico, pero nos referimos a tener un repositorio origin.

Cada desarrollador realiza pull y push sobre el original. Pero ademas de los cambios en el "repositorio central" cada desarrollador también puede extraer cambios de otros compañeros y formar subequipos. Esto puede ser util para trabajar con con "miniequipos" o parejas de desarrolladores. (En la figura anterior hay 3 subequipos Alice y Bob, Alice y David, y Clair y David).

Técnicamente esto sólo quiere decir que Alice ha definido un Git remoto, llamado bob, señalando al repositorio de Bob y viceversa.

Las ramas principales

En el nucleo el modelo de desarrollo es clásico, el repositorio central tiene 2 ramas principales:

  • master
  • develop

La rama master debe ser un elemento familiar para todos los usuarios de Git. Paralelamente a la rama master, existe otra rama denominada develop.

Consideraremos origin/master la rama principal, donde esta el código fuente de la HEAD siempre SIEMPRE siempre está listo para producción.

Consideramos origin/develop la rama principal, donde el código fuente de la HEAD siempre refleja un estado con los últimos cambios de entrega para el desarrollo de la próxima versión. (Hay gente que a esta rama la llama "rama de integración"). En esta rama es donde se construyen las compilaciones automáticas.

Cuando el código fuente que está en develop llega a un punto estable (totalmente probado y funcional) todos los cambios se incluyen en master y se etiqueta master con un nuevo numero de versión (veremos más detalles de esto más adelante).

Por tanto cada vez que se combinan los cambios en master tenemos por definición una nueva versión en producción. En este paso debemos ser muy estrictos.

Ramas de apoyo

Junto a las ramas principales master y develop podemos tener una serie de ramas de apoyo para que nos ayuden en el desarrollo. A diferencia de las ramas principales, estas tienen un tiempo de vida limitado.

Los diferentes tipos de ramas que podemos utilizar son:

  • Ramas de características (features)
  • Ramas de lanzamiento (Realise)
  • Ramas de revisiones (hotfixes)

Cada una de estas ramas tiene un propósito específico están sujetas a estrictas normas.

*Los tipos de ramas se clasifican por la forma en la que se utilizan.

Ramas de características

Estas ramas se utilizan para desarrollar nuevas características para una nueva versión. La esencia de una rama de la característica es que existe, siempre y cuando la función está en desarrollo, pero finalmente se fusiona de nuevo en develop.Se ramifican a partir de develop y de combinan de nuevo en develop. Las ramas de características no existen en origin.

Creación de una rama de funcionalidad

Este es el comando para crear una nueva funcionalidad, desde develop.

$ git checkout -b myfeature develop 
Switched to a new branch "myfeature"

Incorporación de una nueva característica en develop

$ git checkout develop 
Switched to branch 'develop' 
$ git merge --no-ff myfeature 
Updating ea1b82a..05e9557 (Summary of changes) 
$ git branch -d myfeature 
Deleted branch myfeature (was 05e9557). 
$ git push origin develop

La opción no hace que se cree un nuevo objeto con cada commit, para así no perder el histórico.

A ver si me explico, en este último caso es imposible saber cual de los objetos son los que tienen la nueva funcionalidad y en el caso de querer volver atrás habrá que leerse todo el registro de mensajes para deshacer la nueva característica. Por ello es más fácil utilizar la opción no-ff.

*Hay que tener cuidado porque no-ff no es el comportamiento predeterminado y las prisas pueden jugarnos una mala pasada.

Ramas de lanzamiento (release)

Se ramifican a partir de develop. Se deben combinar de nuevo en develop y master. La nomenclatura para estas branchs es release-*

Las ramas de lanzamiento apoyan la preparación de una nueva versión para producción. Permiten "limar" los últimos detalles y corregir los errores menores. Además de la preparación de los metadatos, fechas, ...

Creación de una rama de lanzamiento

Las ramas de versión se crean a partir de develop. Por ejemplo, tenemos nuestro proyecto en la versión 1.1.5 y vamos a realizar un nuevo lanzamiento en breve. El estado de develop se convertirá en listo para el "próximo lanzamiento", hemos decidido que la nueva versión será 1.2. Por tanto, se ramifica la rama de lanzamiento con un nombre que refleje el número de versión:

$ git checkout -b release-1.2 develop 
Switched to a new branch "release-1.2" 
$ ./bump-version.sh 1.2 
Files modified successfully, version bumped to 1.2. 
$ git commit -a -m "Bumped version number to 1.2" 
[release-1.2 74d9424] Bumped version number to 1.2 
1 files changed, 1 insertions(+), 1 deletions(-)

Después de crear una nueva rama y cambiar a ella, nos topamos con el número de versión. Aquí bump-version.sh b es un script de trabajo que cambia algunos archivos de la copia de trabajo para reflejar la nueva versión (esto puede ser un cambio manual lo importante es que algunos archivos cambien). Entonces, el numero de versión cambia.

Esta nueva rama va a existir durante un tiempo, hasta que se libere la nueva release. Durante ese tiempo la corrección de errores DEBE aplicarse en esta rama en vez de en develop.

*No se deben añadir grandes caracteristicas en esta rama, es necesario esperar a otro lanzamiento.

Terminar un lanzamiento

Cuando la rama de lanzamiento está lista para llevarse a producción (liberarse) es necesario realizar una serie de acciones. En primer lugar, la nueva rama se fusiona con master (ya que por definición cada commit en master es una nueva versión). A continuación, se deben tagear/documentar los nuevos cambios para tener referenciado el histórico de esta versión. Por último, los cambios realizados en la rama de lanzamiento deben ser incluidos de nuevo en develop, con el fin de que futuras versiones también contengan estas correcciones de errores.

Los dos primeros pasos de Git son:

$ git checkout master
Switched to branch 'master'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2

El lanzamiento y los etiquetados se realizan ahora. Para mantener los cambios en la rama de lanzamiento, tenemos que unir lo de develop

$ git checkout develop 
Switched to branch 'develop' 
$ git merge --no-ff release-1.2 
Merge made by recursive. 
(Summary of changes)

Este paso puede dar algún conflicto de combinación, si es así debemos fix and commit.

Ahora ya estamos llegando al final y la rama de release debe ser eliminada, ya que no la vamos a necesitar más.

$ git branch -d release-1.2 
Deleted branch release-1.2 (was ff452fe).

Ramas de revisiones (hotfixes)

Se ramifican a partir de master y se deben combinar de nuevo en develop y master. La nomenclatura debe ser hotfix.

Las ramas de revisión son muy similares a las ramas de release, ya que ambas están destinadas para producción, aunque estas (hotfixes) no estén planificadas.

Si un bug es crítico debe ser resuelto inmediatamente. La esencia de este método de trabajo es que los miembros del equipo (rama develop) pueden seguir trabajandomientras que otra persona soluciona el bug.

Creación de una rama hotfix

Las ramas de revisión se crean a partir de la rama master. Veamos lo con un ejemplo, digamos que estamos en la versión de producción 1.2 y esta hay un bug bastante grave, supongamos que los cambios en develop son todavía bastante inestables. A continuación vamos a bifurcar la rama master para arreglar el problema.

$ git checkout -b hotfix-1.2.1 master 
Switched to a new branch "hotfix-1.2.1" 
$ ./bump-version.sh 1.2.1 
Files modified successfully, version bumped to 1.2.1.
$ git commit -a -m "Bumped version number to 1.2.1" 
[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1 
1 files changed, 1 insertions(+), 1 deletions(-)

No hay que olvidarse de modificar el número de versión después de la ramificación.

Después, arreglar el fallo y confirmar la corrección con uno o mas commits separados.

$ git commit -m "Fixed severe production problem" 
[hotfix-1.2.1 abbe5d6] Fixed severe production problem 
5 files changed, 32 insertions(+), 17 deletions(-)
Terminar una rama de hotfix

Cuando se termine la corrección de errores, las soluciones deben ser incluidas de nuevo en la rama master, pero tambien deben incluirse en la rama develop con el fin de salvaguardar todos los cambios. Este paso es similar la liberación de una rama despues de una release.

En primer lugar actualizamos master para marcar la liberación.

$ git checkout master 
Switched to branch 'master' 
$ git merge --no-ff hotfix-1.2.1 
Merge made by recursive. 
(Summary of changes) 
$ git tag -a 1.2.1

Después incluimos este "parche" también en develop

$ git checkout develop 
Switched to branch 'develop' 
$ git merge --no-ff hotfix-1.2.1 
Merge made by recursive. 
(Summary of changes)

La única excepción de la regla es que, cuando existe una rama release, los cambios en las revisiones se fusionaran en esa rama de lanzamiento en lugar de develop.

Por ultimo matamos la rama temporal

$ git branch -d hotfix-1.2.1 
Deleted branch hotfix-1.2.1 (was abbe5d6).

Aunque no hay nada nuevo, impactante y/o asombroso en este modelo de ramificación, tener este modelo puede ser realmente útil en nuestros proyectos. Con este texto es fácil construir un modelo mental que permite a los miembros del equipo entender los procesos de ramificación y liberación.

Como crear solicitudes de combinación (merge requests) en Gitorious

Utilizamos Gitorious como herramienta de colaboración, permite que cada uno tenga sus propios clones de las fuentes públicamente visible y mantenido por debajo por Gitorious, navegar fácilmente por nuestro proyecto, ver los repositorios de origen y el material de otros depósitos disponibles.

También permite a todo el mundo presentar solicitudes oficiales de combinación (más tarde MR) de sus propias modificaciones para que podamos comentar y aplicarlas ya sea tal cual o modificandolo.

Lo primero es clonar el repositortio deseado alojado en Gitorious, necesitaría crear su cuenta personal en gitorious.org. Después habría que hacer una llave ssh (alli se explica cómo hacerlo) y crear un clon personal.

Antes de poder trabajar dentro de su repositorio personal, tienes que obtener una copia de trabajo (sustituir usuario por su nombre de usuario y el proyecto por el deseado, yo he usado bulmages):

$ git clone git@gitorious.org: user/bulmages/bulmages.git

Ahora ya podríamos trabajar en nuestra copia local, pero solo tendríamos la rama origin/master, creamos nuestra rama local de trabajo. (sustituye tubranch por el nombre de tu rama nueva)

$ git checkout -b tubranch master

Con los siguentes comandos podríamos ver nuestras ramas locales el primero y remotas el segundo, como ya hemos comentado anteriormente:

$ git branch
$ git branch -r

La rama creada anteriormente, solo lo haría localmente, así que para que esta sea reconocida por gitorius, habría que ejecutar el siguente comando:

$ git push origin tubranch

Ya puede realizar los cambios y commits con git commit, y refrescar los cambios en el repositorio con:

$ git push

Para obtener los últimos cambios conocidos en su repositorio Base, primero hacer que el repositorio externo sea conocido para git. Esto se podría hacer así:

$ git remote add upstream git://gitorious.org/bulmages/bulmages.git

A continuación, puede descargar el repositorio base con los cambios y unirlos a su maestro local

$ git fetch upstream && git checkout master && git rebase -i upstream/master
Si el mensaje del commit de rebase dice "noop" eso es que está todo bien (ZZ para guardar y salir del editor). Pero pueden aparecen conflictos, podría intentar resolverlos con git mergetool. Si no es asi, puede pasar todos los cambios a su rama principal con:
$ git push origin master

Ahora estaríamos trabajando con las últimas fuentes del proyecto base del que hemos hecho el clonado.

Si por ejemplo tenemos diferentes branches o ramas, podemos cambiar y crear una de contruccion o build que nos sirva de pruebas e incluya todas las modificaciones que deseemos, esto lo podemos hacer uniendo los diferentes cambios en una rama:

git checkout -b master build master && git merge tubranch1 && git merge tu-branch2 && git merge tubranch3 && ant all

despues de que acabe todo, espero que bien, vamos nuevamente a limpiar y eleiminar la rama master build:

git checkout master && git branch -d master build
Publicado el: nov 25, 2012
Enviado por: admin
Categoría:Software
Fuentes:http://git-scm.com/book/es/
http://jesuslc.com