Git Community Book

Que es Git ?

Git es un sitema de control de revisiones distribuido, o software de administracion de proyectos de codigo fuente con un enfasis en ser rapido. Git fue inicialmente creado por Linus Torvalds para el desarrollo del kernel Linux

Git se diferencia de CVS en que cada directorio de trabajo contiene un repositorio con una copia completa de la historia del proyecto, y ningun repositorio es inherentemente mas importante que los demas. Esta es la naturaleza distribuida de Git, el cual no depende de acceso a red o un servidor central. Sin embargo, se puede emular el modelo CVS designando un repositorio compartido, contra el cual los desarrolladores pueden sincronizar. Mas adelante se explica como configurarlo de esta forma

Referencias

sitios con documentacion:


screenshot herramienta grafica gitk, usada para visualizar historiales

IDE historial gitk.gif

Algunos proyectos usando Git

  • Git
  • Linux Kernel
  • Perl
  • Ruby on Rails
  • Android
  • WINE
  • Fedora
  • X.org
  • VLC
  • Prototype

Comentaré brevemente los puntos sobresalientes que he encontrado en este sistema de versionado. No voy a escribir aqui un tutorial completo, puesto que los existentes son muy buenos. Simplemente desarrollare los primeros capitulos del libro Git community Book, remarcando las diferencias entre este sistema de versionado con los sistemas actuales mas utilizados, como por ejemplo Subversion. Por lo tanto asumiré que el lector tiene un background en sistemas de versionado, y sobre todo en el uso diario de Subversion (svn).

Conceptos Git

Algunos conceptos interesante y novedosos en los que se basa Git:

  • La base de datos de objetos es un sistema elegante usado para almacenar la historia de los proyectos — archivos, directorios y commits.
  • El archivo index es una especie de cache del estado de un arbol de directorio, usado para crear un commit, hacer check out de directorios de trabajo, y mantener varios arboles involucrados en un merge.

Git soporta varios protocolos para acceso remoto **ssh:// http(s) git:// rsync **

Representacion interna

  • Todos los nombres de archivos en Git tiene 40 digitos (el object name) , los cuales representan un codigo SHA1 y son unicos dentro de cada proyecto.
  • Cada archivo puede contener alguno de los 4 tipos de objetos (blob, tree, commit o tag) con los cuales se representan todas las cosas.

Ventajas:

  • Es muy facil verificar diferencias, simplemente comprando los nombre de archivos
  • Facil detectar errores, comprando el SHA1 del archivo con su contenido.

Estructura de un Git Object

Object =

  • size
  • content
  • type
    • blob : simplemente un stream de datos
    • tree : es como un directorio, a su vez puede referenciar trees y blobs
    • commit : snapshot + meta informacion
    • tag : marca un commit especifico

El comando git show puede ser usado entre otras cosas para ver la estructura interna de los objetos:

$ git log --stat

commit e94bbd6e0b71efc4e6f6ec8d2d59b9fcf4964f08
Merge: b93c84f... 9edade8...
Author: Sebastian Emilio Narvaez <sebastian@miemail.com.ar>
Date:   Sun Jan 18 19:29:54 2009 -0200

[...]

$ git show e94bbd6e0b71efc4e6f6ec8d2d59b9fcf4964f08 --pretty=raw

commit e94bbd6e0b71efc4e6f6ec8d2d59b9fcf4964f08
tree aa16d4c0828ce61ea72f4e1e13b02033354b6736
parent b93c84f0a30f030ab68c7b991cb12a510544603e
parent 9edade8e672770a470b2a028f9a593dc05663623
author Sebastian Emilio Narvaez <sebastian@gcoop.com.ar> 1232314194 -0200
committer Sebastian Emilio Narvaez <sebastian@gcoop.com.ar> 1232314194 -0200

[...]

Directorio Git

Git guarda toda la informacion de versionado dentro del directorio .git, en el directorio principal de nuestro proyecto.

$ ls -AF .git/
branches/       config       gitk.cache  hooks/  info/  objects/   refs/
COMMIT_EDITMSG  description  HEAD        index   logs/  ORIG_HEAD

En el archivo config, se guarda la configuracion del repositorio: nombre de usuario, URL o direccion remota del repositorio, etc

Se puede usar el comando git config para setear valores en este archivo, sin tener que modificarlo manualmente

$ git config --global user.name "Sebastian E. Narvaez"
$ git config --global user.email "seba@email.com"

El archivo index es especial. Es una especie de staging o archivo temporal, donde se guardan los cambios antes de hacer un commit.

Obteniendo un repositorio Git

Git soporta varios protocolos para acceso remoto **ssh:// http(s) git:// rsync **

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

Usar:

  • Protocolo git: es mas rapido y eficiente
  • Protocolo http: Cuando estemos detras de un firewall corporativo

Inicializando un nuevo repositorio

$ tar xzf project.tar.gz
$ cd project
$ git init

git init crea el directorio .git dentro del directorio principal del proyecto, junto con toda la metadata con informacion de versionado.

Luego, usamos el comando git add para agregar los archivos al sistema de versionado.

NOTA: Hay una diferencia importante con el comando svn add de subversion. En subversion, svn add se utiliza unicamente la primera vez, o para agregar archivos nuevos, mientras que en Git, el comando add se utiliza tanto para agregar nuevos archivos, como para indicar cuales archivos han sido modificados. Es decir, en Git tenemos que usar git add cada vez que modificamos un archivo. Lo que hace el comando git add, es agregar los cambios al archivo index. Estos cambios en el archivo index son los que luego son commiteados al ejecutar git commit.

Para simplificar, existe la opcion -a: git commit -a, el cual tiene la funcion de realizar un add de todos los archivos modificados localmente, y luego realizar un commit normal

Siguiendo con el ejemplo, agregamos algunos archivos

$ git add file1 file2 file3

git diff nos mostrara los archivos modificados localmente, pero que todavia no han sido agregados con add ( o sea, todavia no se encuentran en el archivo index, por lo tanto no seran commiteados al ejecutar git commit.

git diff –cached, por otro lado nos mostrará los cambios contenidos en el archivo index, y que por lo tanto seran commiteados al ejecutar git commit

git commit -a
Automaticamente encuentra cualquier archivo modificado (pero no nuevo), los agrega al index, y commitea, todo en un solo paso
git add
Es usado para archivos nuevos, y para archivos modificados
git branch experimental
Crear una nueva rama, llamada experimental
git branch
Lista de branches
git checkout experimental
Cambiar el directorio de trabajo a la rama experimental
git checkout master
Devuelta en la rama principal
git merge experimental
Mezcla los cambios hechos en la rama experimenta, en la rama actual
git diff
Si hubo conflictos, los archivos se marcan con markers
gitk
Representacion grafica de la historia de un proyecto
git branch -d experimental
Borrar la rama experimental. Se asegura que los cambios de la rama experimental hayan sido mezclados en la rama principal
git branch -D idea-loca
Borra la rama experimental, sin revizar si los cambios fueron mergeados

Flujos de trabajo distribuidos

A continuacion, un ejemplo de trabajo distribuido (sin un servidor y repositorio central )

Bob se descarga el proyecto de Alice, colabora modificando algunos archivos, y luego realiza un commit con todos sus cambios:

bob$ git clone /home/alice/project myrepo
bob$ ( edita archivos )
bob$ git commit -a

Alice mezcla los cambios de la rama principal de Bob en su rama actual:

alice$ cd /home/alice/project
alice$ git pull /home/bob/myrepo master

Otra forma en que Alice puede mezclar (merge) los cambios, pero teniendo mas control es la siguiente:

alice$ git remote add bob /home/bob/myrepo  # define un shortcut al repo de Bob
alice$ git fetch bob     # solo trae los datos, pero no hace merge
                         # guarda los cambios en la rama de tracking remoto

alice$ git log -p master..bob/master  # revisa los cambios hechos por Bob.
alice$ git merge bob/master   # por ultimo, mezcla los cambios de Bob en su propio repo

Bob actualiza su repositorio con los cambios de Alice.

bob$ git pull

Ejemplo configuracion repositorio Git publico via http

Configurando un repositorio compartido

Asumiremos que ya tienes creado el repositorio git para tu proyecto, posiblemente creado desde cero o desde un tarball, o importado desde un repositorio CVS existente.

Suponiendo que el repositorio existente es ~/public_html/pruebagit/ , hay que crear un nuevo repositorio en modo “bare” (un repositorio sin directorio de trabajo) y hacer un fetch (traer) el proyecto en el nuevo directorio

Repositorio “bare”

Un repositorio “bare” es normalmente un directorio con un sufijo .git que no tiene una copia localmente descargada (cheked out) de ninguno de los archivos bajo control de revision. Esto es, todos los archivos git administrativos y archivos de control que estarian normalmente presentes en un subdirectorio oculto .git, estan directamente presentes en el directorio repositorio.git, y ningun otro archivo esta presente. Usualmente repositorios publicos son hechos repositorios “bare”

~/public_html$ mkdir bare-repo.git
~/public_html$ cd bare-repo.git/
~/public_html/bare-repo.git$ git --bare init --shared
Initialized empty shared Git repository in /home/seba/public_html/bare-repo.git/
~/public_html/bare-repo.git$ ls
branches  config  description  HEAD  hooks  info  objects  refs
~/public_html/bare-repo.git$ git --bare fetch ~/public_html/pruebagit/ master:master
remote: Counting objects: 21, done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 21 (delta 2), reused 4 (delta 0)
Unpacking objects: 100% (21/21), done.
From /home/seba/public_html/pruebagit
 * [new branch]      master     -> master

Al intentar hacer un clone via http de nuestro nuevo repositorio “bare”, puede que nos encontremos con el siguiente problema:

~$ git clone http://localhost/bare-repo.git/
Initialized empty Git repository in /home/seba/bare-repo/.git/
warning: remote HEAD refers to nonexistent ref, unable to checkout.

Para resolver ese problema, ejecutamos el comando **git update-server-info **

~/public_html/bare-repo.git$ git update-server-info

Ahora probamos, y git clone funciona correctamente.

~$ git clone http://localhost/bare-repo.git master

Muchas opciones

A continuacion, algunos ejemplos que muestran la gran cantidad de opciones que soportan los comandos de git. La mayoria de las opciones pueden combinarse para formar consultas complejas, por ejemplo realizar busqudas de commits por determinadas fechas, que contengan ciertos strings, y en determinados directorios, etc.

Historial

El comando git log sirve para ver informacion historial del repositorio, y nos presenta con una gran cantidad de opciones

git log
Todos los commits visibles desde el commit padre
git log v2.5..
Todos los commits a partir de (pero no visibles desde ) la version V2.5
git log test..master
Commits visibles desde master, pero no desde test
git log master..test
Commits visibles desde test, pero no desde master
git log master…test
Commits visibles desde test o master, pero no desde ambos
git log –since=”2 weeks ago”
Los commits de las ultimas 2 semanas
git log Makefile
Todos los commits que modificaron el archivo Makefile
git log fs/
Commits que modificaron cualquier archivos bajo el directorio fs
git log -S’foo()’
Commits que agregaron o borraron datos conteniendo el string ‘foo()’
git log -no-merges
No mostrar commits de merges
git log v2.5.. Makefile fs/
Se pueden combinar consultas
git log -p –since=”yesterday”
la opcion -p Muestra patches (diffs)
git log –stat
Similar a svn log -v
git log –pretty=online –date-order –graph –reverse
Formato solo una linea, en modo grafico (ASCII representando branches) ordenado por fecha, y en forma descendente. Existen muchas opciones para –pretty, como raw y short

Diferencias – git diff

El comando git diff es muy util para ver cambios antes de commitear, o para ver diferencias entre distintas ramas o versiones.

git diff
Cambios en el directorio de trabajo actual, que todavia no han sido marcados para guardar en el siguiente commit
git diff –cached
¿ Que archivos han sido marcados para guardar en el siguiente commit ?
git diff master..test
Diferenias entre dos ramas
git diff master…test
Diferencias desde su rama ancestro comun
git diff HEAD
¿ que estaria commiteando si ejecutara git commit -a ?
git diff test
Diferencias entre el directorio de trabajo y la rama test
git diff HEAD — ./lib
Limitando la comparacion al subdirectorio lib
git diff –stat
Solo imprime archivos, resumido

Dejanos tus comentarios

Bueno, eso es todo por ahora. Por favor, si tienes alguna duda, o quieres sugerir algo, no dudes en dejar tu comentario. Muchas gracias.

Copyright: http://snarvaez.poweredbygnulinux.com Sebastian Narvaez</p>

este documento ha sido publicado bajo la siguiente licencia: “Verbatim copying and distribution of this entire article are permitted in any medium provided this notice is preserved.”