GIT (no, la banda no)
April 15th, 2008
(Sé que no soy el único que entendió el chiste del título, asi que a hacerse cargo).
Ahora a lo que nos compete: Acá en OnRails no queríamos ser menos :P, y viendo la gran cantidad de blogs que hablan de GIT, no nos queríamos quedar sin nombrarlo.
There’s a new SCM in town.
Los últimos dos años he usado SVN, con algun que otro problema, pero sin realmente tener algo concreto para quejarme. Antes de SVN trabajé como administrador de ClearCase, que es la herramienta de SCM de Rational, que luego fue comprada por IBM. ClearCase (CC) se caracteriza por muchas cosas (muchas negativas), siendo la burocracia una de ellas. Como admin pude experimentar el sufrimiento de laburar con un esquema complejo, y que no facilitaba el trabajo de los desarrolladores. CC permite un montón de operaciones que en SVN son muy difíciles o muy propensas a generar conflictos. En CC se podían crear muy facilmente los “streams”, que no eran otra cosas que branches, justamente uno de los temas que GIT resuelve por sobre SVN.
Hace un mes comencé a meterme con este “nuevo” SCM, me empapé bastante del tema y puedo decirle las caracteristicas que para mi son más relevantes:
Aclaración al margen: Esto no es una guía sino que simplemente intenta transmitir algunas de las sensaciones generadas en las primeras semanas de uso. Recursos sobran a mi entender.
La creación de branches es trivial.
En SVN era necesario hacer “svn copy ../trunk ../branches/mi_branch”, y luego hacer checkout en otro directorio apuntando a la ruta recién creada, terminando así con varios directorios del mismo repo, cada uno apuntando a un branch diferente.
Con GIT es solo cuestión de ejecutar: git branch mi_branch, y luego hacer checkout mi_branch. Si, sin cambiar de directorio. GIT cambia los archivos automáticamente según el branch seleccionado. Quizás con un ejemplo se vea mejor.
(Mi prompt indica el branch actual, si lo quieren usar copien este link en $HOME/.profile)
driven:~/programming/test_app $ git init
driven:~/programming/test_app $ git add . # Agregando archivos, sino git no se hace cargo
driven:~/programming/test_app $ git commit -a -m "Initial Import"
driven:~/programming/test_app (master)$ git branch
* master
driven:~/programming/test_app (master)$ git branch req_23568
driven:~/programming/test_app (master)$ git branch
* master
req_23568
driven:~/programming/test_app (master)$ git checkout req_23568
Switched to branch "req_23568"
driven:~/programming/test_app (req_23568)$
A partir de aquí solo me restaría trabajar en el req_23568, hacer commit lo que sea necesario (los commits son por branch) y luego hacer un rebase del master (nuestro omni presente branch) apuntándolo a req_23568. Cómo sería eso?
driven:~/programming/test_app $ mate . # trabajo, mucho, cambio, pongo, saco
..
driven:~/programming/test_app (req_23568) $ git commit -a -m "Algo 1"
...
driven:~/programming/test_app (req_23568) $ git commit -a -m "Algo 2"
....
driven:~/programming/test_app (req_23568) $ git commit -a -m "Algo 3"
# laburo con repo remoto? Antes deberia hacer un pull.
driven:~/programming/test_app (req_23568)$ git checkout master
driven:~/programming/test_app (master)$ git pull # por default es el origin
driven:~/programming/test_app (master)$ git checkout req_23568 # y vuelvo
driven:~/programming/test_app (req_23568)$ git rebase master # por si alguien estuvo laburando en master
driven:~/programming/test_app (req_23568)$ git checkout master # si todo funciono OK me paso a master
Switched to branch "master"
driven:~/programming/test_app (master)$ git rebase req_23568 # y realizo el rebase
... mucho ruido ... (ojo, muy útil)
driven:~/programming/test_app (master)$
Nota: Se actualizó acorde a lo sugerido por el estimadísimo Luis Lavena.
Lo que hace rebase es interesante. Rebobina el branch MASTER al momento en que se creo el branch REQ_23568, aplica lo cambios del mismo, y luego aplica todos los commits que se hayan aplicado posteriormente en el branch MASTER.
No hay un servidor centralizado.
Cada uno tiene una copia, y es autónoma de la de los demás. Todas las operaciones se realizan localmente y luego se envían los cambios a los repositorios remotos que uno tenga configurado localmente. Obvio, siempre hay que tener permiso, sino no pasa un byte.
Ignorar archivos es una huevada.
Sólo hace falta crear el archivo .gitignore en el root del repo y cargarlo con entradas que pueden incluir el nombre relativo del elemento a excluir, o wildcards más abarcativos.
driven:~/programming/backoffice (tab_container)$ cat .gitignore
.DS_Store
*.log
tmp/**/*
config/database.yml
db/*.sqlite3
db/schema.rb
db/schema.sql
Incluye una herramienta excelente para visualizar los branches y cambios aplicados o no.
Se llama gitk. Incluir el parámetro—all para que muestre información sobre todos los branches, y no solo el actual/current.
Muchas cosas más.
Dejo para cada uno que tenga ganas la tarea de investigar el stash, que a mi entender es una idea excelente. Este Linus la tiene clara.
Ah, además se integra con SVN muy facilmente. Podésusarlo localmente y hacer commit contra un repo SVN cuando termines. Para los demás que usen SVN es transparente.
Conclusión preliminar.
GIT es la evolución obligada luego de SVN. En mi caso me facilitó mucho poder trabajar con ciertos temas que requerían atención inmediata y otros que llevaban un poco más de tiempo de desarrollo.
Un branch para cada cosa. A guardar, a guardar, cada cosa en su branch! (bueh, suficiente, no?)



April 15th, 2008 at 03:58 PM
Muy buen articulo!
Ademas de que es interesante, no hay vuela atras. Ya hay varios plugins (como WillPaginate) que estan en GitHub, y si queres incluirlos en tu proyecto, la mejor forma es via GIT y no bajandote un .tar.
Por otro lado, es inminentne la salida de Rails 2.1 que entiendo incluye soporte para Git directamemte, estimo que para poder instalar plugins facilmente de github o cualquier otro repo.
April 15th, 2008 at 05:50 PM
Lucas, yo te recomendaria en lugar de hacer rebase sobre master, hacer rebase sobre tu branch.
Por que? simplemente por que si master esta siendo compartido por varios usuarios (en caso de un team de desarrollo) lo que harás haciendo rebase es cambiarle el historial cronologico a ellos, y lo que llevaria a varios conflictos cuando hagan pull o fetch+merge de estos.
Me gustaria que la propia ayuda fuera mas grafica… hay demasiados comandos que pudes usar, demasiadas maneras de hacer las cosas que es overwhelming.
Por todo lo demas, linda experiencia. :-)
Saludos!
Luis
April 15th, 2008 at 06:16 PM
Luis, tenés razón, en un punto evitás el quilombo si hacés rebase en tu branch, pero en algún momento tenés que pasar tu laburo a master, porque si no lo hacés, master te queda outdated. Se entiende lo que digo?
Cuál sería el modo entonces? Tirame la punta que se me escapa la tortuga! :P
Lucas
April 15th, 2008 at 09:05 PM
1. Haces pull en master 2. switch a tu branch 3. rebase con master 4. si nada se rompio, entonces switch a master y merge del branch 5. se feliz :-D
Por lo menos asi lo vine usando yo, y anda por ahora :-D
April 15th, 2008 at 11:05 PM
Pero muchas gracias, Luis. Usted siempre listo, y a la orden del día! :)
Ahora toco el artículo para que no haya que mirar los comments.
Thanks again.
April 16th, 2008 at 12:54 AM
Al pie del cañon como se dice!
Aqui tenes por ejemplo, bien al pie del post, un justificativo de por que hacer el rebase sobre tu branch y no sobre el master:
http://www.tpope.net/rails-git-best-practices
April 16th, 2008 at 03:06 AM
No entendí la referencia a la banda… eso es malo?
Independientemente…
Ayer me puse a mirar sobre Git, y hoy haces un post… parece a propósito.
Git vs Mercurial, ¿tenés alguna opinion? hg tiene la ventaja de andar en Windows, así que alcanza más gente…
April 16th, 2008 at 12:12 PM
Tordek: GIT es una banda de los 80 (http://es.wikipedia.org/wiki/G.I.T.), de ahí el chiste fácil.
De mercurial no se nada, pero nada. Será cuestión de ponerse a leer un poco, no?
Luis: Ya me los estoy leyendo… :P
April 16th, 2008 at 01:14 PM
Ah, sí, veo que la banda es más vieja que yo. [Palazo]
Ahora mismo estoy queriendo asesinar a alguien porque tengo un proyecto en GIT y lo quiero subir a un repo en SVN, pero no quiere andar…