miércoles, 14 de septiembre de 2011

Branch remotos en git, dos pasos. ¿Y despues? (version Tortoise)

Anteriormente, en gitevangelism, hice un post que explica como crear un branch remoto en dos pasos, aca un resumen:

Crear un branch de manera local



Publicar el branch


Despues, hay que trabajar con el branch, hay cosas que no resultaran tan triviales al principio

Trabajar en el branch, en los branches

Si se ejecutaron los comandos para creacion de branch explicados, habra quedado activo el nuevo_branch, sino se esta seguro se puede revisar el menu contextual de tortoise git, asi:

Si el branch en el que queremos trabajar no es el activo, entonces utilizamos la opción de switch/checkout (accesible desde el menu contextual de tortoise git)


A partir de entonces, todos los commits seran dirigidos al branch activo, actualizando el branch para que apunte a cada commit que se hace.

Si por alguna razon, es necesario dejar el trabajo que se esta realizando en este branch para trabajar en otro (por ejemplo, en master), se utiliza el comando checkout para reactivar master


Si hay cambios no commiteados, seguramente el comando se negara a cambiar el branch activo, si ese fuera el caso hay que commitearlos o stashearlos (stash es un commit temporal que se usa para guardar el indice y los cambios no commiteados y que despues se puede recuperar):

Para volver, otra vez hay que utilizar otra vez la opcion switch/checkout y si se tuvo que salvar los cambios mediante stash, hay que recuperarlo haciendo

Por ultimo, se debe hacer un push, este sube cada branch trackeado a su correspondiente branch remoto (en este caso subiria el master local al master remoto y el nuevo_branch local al nuevo_branch remoto)

Colaboracion

Si se necesita que otra persona contribuya al branch, desde otra maquina, tiene que trackearlo, primero haciendo un pull o fetch, y despues con la opcion switch/checkout también:


NOTA: el checkout a remotes/origin/demo_branch solo es necesario la primera vez que se trabaja con el branch para crear el branch local que trackea, el resto de las veces un checkout al branch local alcanza

Despues, trabajar de esa manera es lo mismo que trabajar al master, con la diferencia (claro esta) que es el nuevo_branch el que recibe los cambios que se pushean

Integrar los cambios

Esta es la manera mas practica de integrar, que utiliza el 3-way-merge (otro dia hago un articulo explicando eso), no hay mas que hacer que lo siguiente:

Activar el branch destino del merge, es decir al que se va a integrar


Utilizar la opcion merge del tortoise

Elegir el branch que mergear y las opciones (es conveniente por ahora dejar las default, que son todas desmarcadas)





Branch remotos en git, dos pasos (la version Tortoise)

En dos pasos se puede crear un branch remoto

PASO 1: Crear branch de manera local (esto no es necesario si ya existe el branch local)


NOTA: en switch to, se puede seleccionar cualquier otro branch (en este caso el master), cualquier tag o cualquier commit arbitrario, en ese caso el branch se creara a partir de ese commit.

PASO 2: Publicar el branch


También se puede trabajar en el branch local antes de publicarlo.

miércoles, 7 de septiembre de 2011

Beyond git svn clone: Svn Survival Kit Part I

Si alguna vez hay que trabajar con un repositorio svn...

Comandos basicos


Clonar un repositorio svn (equivalente a git clone)
git svn clone [url]

Bajar últimos cambios del repositorio svn (equivalente a git fetch)
git svn fetch

Bajar ultimos cambios e integrar con cambios propios (equivalente a git pull --rebase)
git svn rebase

Commitear cambios (equivalente a git push)
git svn dcommit

Mantener linealidad

Mientras git es un versionador diseñado para representar cambios no-lineales, la estructura de svn representa cambios lineales, esto en terminos de usar git con svn significa que siempre sin excepción los cambios que se hacen al master local deben ser lineales, es decir que no se permiten merge commits, en el workflow normal de git-git es frecuente que se generen merge commits cuando se hace pull de cambios que divergen, pero esa operacion se reemplaza por git svn rebase en el workflow de git-svn, la cual mantiene la linealidad re-aplicando los commits divergentes locales en la rama remota.

Eso quiere decir que si uno commitea B despues de A en la rama local, y otro commitea C despues de A, cuando el primero hace git svn rebase quedara lineal, asi:

A -C - B'

Mientras que en git queda la ramificacion de C y B y el merge commit que une ambas lineas divergentes.

Local Branches: De manera local se puede diverger

No hay ningun problema en hacer branches locales, el unico impedimento es que esos branches no se pueden publicar al servidor svn de una manera practica (existe una forma, pero es tan engorrosa que es mejor no utilizarla en un principio).
Lo que es muy importante tener en cuenta, es que si se necesita integrar esos branches a la rama principal con el objetivo de commitearlo a svn hay que hacerlo preservando la linealidad de la rama principal, esto se puede hacer con un squash merge (es la opcion q mas me gusta) o con rebase, rebase es mas complicado pero mantiene todo el historial del branch y yo en lo personal no lo considero conveniente por razones que voy a explicar mas adelante.

Local Merges al trunk: Mantener linealidad --squash

Suponiendo que hay que mergear un branch al master, hay que hacerlo de esta manera:
git merge --squash nombre_del_branch
Ese comando pone el resultado del merge en el indice y la working copy , posteriormente hayque commitear con el mensaje que se considere apropiado y por supuesto ese commit no rompera la linealidad. Esto mezcla todos los cambios del branch en un solo commit

Local Merges al trunk: Mantener linealidad con rebase

Rebasear el branch al master y despues mergearlo (debe ser fast-forward)

git checkout nombre_del_branch
git rebase master
git checkout master
git merge --ff-only nombre_del_branch

El primer comando cambia el branch actual a nombre_del_branch, el segundo lo rebasea a master (es decir, mueve todos los commits divergentes para que esten linealmente a continuacion de master), vuelve a master otra vez y mergea el branch rebaseado, la opcion --ff-only es para indicar que solo haga el merge si es fast-forward

Remote branches: Mejor NO

Da problemas especialmente cuando se elimina un branch y tiende a ser complejo, podria servir como una herramienta para manipular branches de svn de manera mas facil pero generalmente trae complicaciones si uno no esta ducho con la combinacion git-svn

Hacer commit frecuente pero dcommit no tan frecuentes ni tan pesados

Normalmente en git no es un problema hacer push de varios commits, pero efectuar un dcommit que envie muchos commits a svn no conviene. La razon es que git svn dcommit convierte cada commit local de git en un commit de svn y lo envia, este proceso es muy costoso en terminos de network en comparacion del git push de siempre (esto sin contar posibles problemas de race condition mas probables en dcommits que tarden mucho).
Por eso lo mejor siempre es tratar de enviar de a uno o como maximo dos o tres commits a la vez (por eso me parece mejor usar el squash merge para los branches), si se avanzo demasiados commits en el repo local lo mejor sera fusionar esos commits en unos pocos o incluso uno solo si tiene sentido (se puede guardar el historial completo en un tag o branch local)

Debo los links


Git Agile: Push automatico

Parte de la adaptación de git a agile es habilitar la posibilidad de que los push sean automaticos, como en el modo autosync de fossil
La forma mas simple de realizar esto seria editar .git/hooks/post-commit (deje los comentarios del script a propósito)
#!/bin/sh
#
# An example hook script that is called after a successful
# commit is made.
#
# To enable this hook, rename this file to "post-commit".

echo Doing automatic push... edit .git/hooks/post_commit to disable it
git push

Por supuesto que después de hacer eso se encontraran varias razones para invocar push manualmente, como por ejemplo crear un nuevo branch remoto. No obstante un git push después de cada commit cubre la mayoría de los casos.

sábado, 6 de agosto de 2011

Fusionar commits

No hay excusa para no commitear con la frecuencia que mas nos convenga, ya que existen formas de editar el historial antes de publicarlo.
Uno de los trucos mas utiles es el de fusionar commits, que permite fusionar una serie de commits consecutivos en solo uno. Por ej, si se necesita condensar los ultimos 6 commits, se deben ejecutar los siguientes comandos:
git reset --soft HEAD~6
git commit -m 'mensaje de commit'
Previamente a ejecutar el comando commit, se pueden (o no) realizar los ajustes adicionales que se consideren necesarios

Como disclaimer aclaro que no se deben fusionar commits que ya se hayan pusheado

Deshacer

Para deshacer el efecto de los dos comandos, se debe restaurar el branch a su estado original, asi:
git reset --hard HEAD@{2}

Git reset


git reset es el comando que permite modificar a mismo tiempo el puntero HEAD y el puntero del branch activo.
Si se usa con --soft mantiene el indice y el working tree, por lo que todo queda listo para efectuar el commit, en este caso se reseteo el branch activo a un estado 6 commits previos al que se encontraba manteniendo el contenido del ultimo commit en el indice por lo que el commit posterior sera equivalente en contenido al ultimo commit con la diferencia de que el parent sera el viejo commit y asi este por si solo contendra el cambio hecho por los otros 6
Para deshacer, se utilizo git reset --hard para restaurar el estado del branch a como era antes, --hard indica que no se mantienen ni el indice ni el working copy

HEAD~6

Hace referencia al commit que esta 6 pasos atras del commit HEAD (el commit activo), en el ejemplo se pudo haber especificado otra cosas como un SHA, un branch, un tag, una entrada de reflog, etc... Ejemplos:

Resetea al remote master para que el proximo commit tenga el remote branch como parent
git reset --soft origin/master
Resetea a un commit especifico por SHA para que el proximo commit tenga ese commit como parent
git reset --soft 01abcdef
HEAD@{2}

Hace referencia a una entrada en el reflog, el reflog es un registro de los valores que adquiere una ref, el reflog principal es el de HEAD al que se puede acceder a todos los valores que HEAD ha adquirido historicamente. HEAD@{1} hara referencia al anterior del ultimo valor que adquierio, HEAD@{2} hara referencia al anterior del anterior y asi sucesivamente...
Y sea que se efectuen commits, resets, checkouts o lo que sea las entradas de reflog permiten acceder a los commits previos, muy util para localizar commits "perdidos"

Links

lunes, 25 de julio de 2011

Branch remotos en git, dos pasos. ¿Y despues?

Anteriormente, en gitevangelism, hice un post que explica como crear un branch remoto en dos pasos, aca un resumen:

Crear un branch de manera local
git checkout -b nuevo_branch
Publicar el branch, y trackearlo local (al especificar -u)
git push -u origin nuevo_branch

Despues, hay que trabajar con el branch, hay cosas que no resultaran tan triviales al principio

Trabajar en el branch, en los branches

Si se ejecutaron los comandos para creacion de branch explicados, habra quedado activo el nuevo_branch, sino se esta seguro se puede utilizar git branch sin argumentos, asi:
git branch
Devuelvera la lista de branch, indicando con un asterisco el branch activo en el momento

Si el branch en el que queremos trabajar no es el activo, entonces ejecutamos el comando checkout
git checkout nuevo_branch
A partir de entonces, todos los commits seran dirigidos al branch activo, actualizando el branch para que apunte a cada commit que se hace.

Si por alguna razon, es necesario dejar el trabajo que se esta realizando en este branch para trabajar en otro (por ejemplo, en master), se utiliza el comando checkout para reactivar master

git checkout master

Si hay cambios no commiteados, seguramente el comando se negara a cambiar el branch activo, si ese fuera el caso hay que commitearlos o stashearlos (stash es un commit temporal que se usa para guardar el indice y los cambios no commiteados y que despues se puede recuperar):

git stash

Para volver, otra vez hay que ejecutar
git checkout nuevo_branch
Y si se tuvo que salvar los cambios mediante stash, hay que recuperarlo haciendo
git stash pop

Por ultimo, se debe ejecutar el comando git push, este sube cada branch trackeado a su correspondiente branch remoto (en este caso subiria el master local al master remoto y el nuevo_branch local al nuevo_branch remoto)

Colaboracion

Si se necesita que otra persona contribuya al branch, desde otra maquina, tiene que trackearlo
git fetch
git checkout --track -b nuevo_branch origin/nuevo_branch

Despues, trabajar de esa manera es lo mismo que trabajar al master, con la diferencia (claro esta) que es el nuevo_branch el que recibe los cambios que se pushean

Otra opcion, para mirar el branch es directamente usar las ref remotas

git fetch
git checkout origin/nuevo_branch


Esto es mas practico si solo se necesita "ver" el contenido del branch, pero para trabajar con el es conveniente trackearlo, de otra manera se tendria que explicitar el branch cada vez que se hace push:


git push origin HEAD:refs/heads/nuevo_branch


Integrar los cambios

Esta es la manera mas practica de integrar, que utiliza el 3-way-merge (otro dia hago un articulo explicando eso), no hay mas que hacer que lo siguiente:
git checkout master
git merge nuevo_branch

Puede ser que master y nuevo_branch no sea divergentes (esto es que una, generalmente master, apuntara a un commit ancestro del otro), en ese caso no habra ningun problema y simplemente master cambiara para igualar a nuevo_branch.
Cuando master y nuevo_branch no son divergentes, se utilizara el algoritmo de merge que
puede no dar conflicto en cuyo caso efectuara un commit automaticamente, ese commit sera un commit de merge (es lo mismo que cuando se hace git pull despues de que un git push fue rechazado)
O puede dar conflicto dependiendo de los cambios que se hayan hecho, para resolver esos conflictos hay que ejecutar git status, ver cuales son los archivos marcados como en conflicto y resolverlos (estan marcados claramente dentro del archivo de texto)
Despues de resolver todos los conflictos, se puede hacer un add de update al indice
git add -u
Y entonces commitear
git commit -m 'merged nuevo_branch into master'

Eliminar el branch cuando ya no se use

Para eliminar el branch local
git branch -d nuevo_branch

NOTA: no funciona si el branch que se quiere eliminar es el activo en ese momento, para evitar eso hay que cambiar a otro branch o commit
NOTA2: si el branch no esta integrado a nada, se negara a borarrlo a no ser que se use la opcion -D en lugar de -d

Para eliminar el branch remoto
git push origin :refs/heads/nuevo_branch

Links

Branch remotos en git, dos pasos

Actualizacion: ¿Y despues?, sigue en este post

En dos pasos se puede crear un branch remoto


Crear branch de manera local

git checkout -b nuevo_branch


Publicar el branch

git push -u origin nuevo_branch

Despues, el branch queda traqueado, con lo que cada push sin parametros envia los commits de nuestro branch local a ese branch remoto sin necesidad de explicitarlo

Tambien se puede trabajar en el branch local antes de publicarlo y por supuesto despues.

Actualizacion:
¿Y despues?, sigue en este post

sábado, 23 de julio de 2011

Publicar el repo y el historial, pero sin contraseñas harcodeadas

El historial, la secuencia de commits detallando todo lo que fue cada "snapshot" es muy util, pero ¿Que pasaria si quisiesemos publicar branches en cuyo historial hay contraseñas que no queremos que el publico las vea ?

Para todo "gitero" el historial es importante, pero tambien lo es evitar la fuga de informacion y mas cuando somos concientes de que si hacemos ese "push", esa contraseña o codigo de acceso sera publico

La respuesta a esto es el comando filter-branch ¿ Que hace filter-branch ? crea un commit inicial aparte (que es como el commit inicial del repositorio, no tiene parent) y va copiando los commits del branch que donde estemos parados al momento de ejecutar el comando, pero esto lo hace aplicandole un filtro que se define como argumento del comando

filter-branch tiene muchas opciones muy interesantes, pero la que mas sirve para el caso que describo en este post, es la opcion --tree-filter, que ejecuta una secuencia de comandos a cada tree de cada commit, esa secuencia podria agregar, eliminar, mover o crear archivos. Asi, el siguiente comando eliminaria un archivo Web.config de todo el historial haciendo que no se pueda recuperar ninguna version de el de ningun commit en el historial:

git filter-branch --tree-filter 'rm Web.config'


NOTA: no olvidar poner la ruta completa si corresponde, el script se ejecutara en el root directory del proyecto

A algunos puristas podria no gustarle esa opcion, ya que eliminar ese archivo vital dejaria invalido y "unbuildeable" esos commits pasados. En lugar de eso se podria usar algo mas especifico y recurrir al amigo "sed" para editar ese archivo y remover la contraseña

git filter-branch --tree-filter "sed 's/mipasswordloco/insert your password here/g' Web.config > Web.config.bkp; mv Web.config.bkp Web.config"

En este caso, en lugar de simplemente eliminar el archivo, se lo esta procesando con sed, una "navaja suiza" de la shell para editar archivos de texto desde la linea de comandos de manera no interactiva.

Hay dos comandos en el script separados por punto y coma, el primero es sed que reemplaza el texto "mipasswordloco" por "insert your password here" y usa el parametro g para indicar que debe reemplazar todas las ocurrencias en cada linea del archivo de texto (ver la man page de sed para mas informacion), el segundo parametro escribe en Web.config los cambios realizados con un move, recalco que esto es asi porque no se debe dejar ningun archivo extra o formara parte del tree tambien (que no es lo que se esta tratando de hacer en este caso)

Aplicando scripts mas complejos como este, despues de ejecutar filter-branch es conveniente revisar el historial para verificar que efectivamente se obtuvo el resultado buscado

Si por casualidad hicieron un git-filter-branch y despues se arrepintieron, se restaura el branch con la penultima entrada del reflog, asi:

git reset --hard HEAD@{1}


Links

Ahorrando espacio con git gc

Pregunta frecuente ¿Cuanto espacio ocupa un repositorio de git?
Respuesta: Depende, no solamente de los contenidos sino tambien de si los objetos estan empaquetados o no.
Si estan empaquetados pueden llegar a ocupar hasta 10 veces menos cantidad de espacio que si no lo estuvieran.

Para empaquetar los objetos, hay que ejecutar el comando

git gc

NOTA: Despues de que gc limpie y comprima los objetos el repositorio se puede seguir usando de manera transparente. No es necesario ejecutar ningun comando especifico ni nada ya que git trabaja con los objetos empaquetados
NOTA2: por default git viene configurado para correr este comando automaticamente cuando sea necesario, pero puede ser util correrlo a mano algunas veces


Si despues de esto todavia se necesita liberar todavia mas espacio, se pueden eliminar los logs y hacer git gc de nuevo

rm -fr .git/logs


Pero un advertencia, esos logs almacenan los registros que se acceden mediante git reflog y los stashes, con lo que seguramente se perderan cambios que no hayan sido commiteados a alguna rama existente

Como Funciona

Este comando, lo que hace como su nombre lo indica es actuar de "garbage collector", es decir que elimina todos aquellos objetos que son inalcazables, esto es analago a un entorno gestionado como .NET, Java, Ruby, etc... donde el gc borra de la memoria objetos que no estan siendo referenciados por nadie, en este caso las referencias vendrian a ser los branches, los tags, las entradas de logs y los propios objetos que hacen referencia a parent commits (si son commits), blobs y trees. Es decir que git gc no elimina nada que este a nuestro alcance como la informacion referenciada por los branches en los que estamos trabajando e incluso los commits referenciados por los logs.

Pero la accion de git gc no solo se limita a su papel como garbage collector, sino que tambien se encarga de realizar el packing de los objetos, lo cual implica reorganizarlos todos en un solo archivo y comprimirlo usando delta compression, un metodo de compresion optimizado para comprimir snapshots que tiene ligeras diferencias uno con el otro

Para dar un ejemplo, en un repo relativamente nuevo (200 commits aproximadamente) que pesa 1.8 Megabytes, si se examina el directorio .git/objects se podria ver como git almacena los objetos unpacked:
dario@dario-laptop:~/projects/imageruby-devil/.git/objects$ find | head -n 15
.
./71
./71/a0a195d6b9192f3a2ed92afce74600a18d5463
./5e
./5e/d0b14304e16bb8404fc1106923e47b9e8efc65
./11
./11/4db5a061a6a3d9c010c132cc90890bbfe5c8a9
./34
./34/66e89a2fe1078cbd96bccdce9f0525e1039f2c
./06
./06/21559a3294f6d11c7fa80727d8f9dbc8594ad8
./0f
./0f/f89b8482e83ee109dbf2061ea77b436eaa91c8
./0f/ccf20d3f9fc5f92d56ea4f5959218d6a3109eb
./be
...
...
# sigue un monton
...
...

Pero despues de ejecutar git gc, el repositorio pasa a pesar 232 Kilobytes y los objetos ya no estan almacenados de esa forma, ya que se empaquetaron y comprimieron en solo dos archivos:

dario@dario-laptop:~/projects/imageruby-devil/.git/objects$ find
.
./info
./info/packs
./pack
./pack/pack-eaadc1cff53d9b6d8f5a5ba7eb52fe733c61aac6.pack
./pack/pack-eaadc1cff53d9b6d8f5a5ba7eb52fe733c61aac6.idx

NOTA: Para los que no esten enterados, el comando find busca todos los archivos en el directorio y subdirectorios y muestra las rutas de los archivos que encontro por por salida estandar

Links

martes, 12 de abril de 2011

Versionamiento individualista

Git sin duda es la mejor solucion a mano para versionar de manera individual (independientemente de cualquier repositorio externo)

Para crear un repositorio, hay que posicionarse en el directorio donde se va a versionar, y ejecutar el siguiente comando
git init

Posteriormente, hay que efectuar el primer commit, primero agregando los archivos que se tienen que versionar (se pueden agregar desde directorios completos con todo su contenido hasta archivo simples, tantas veces como sea necesario)
git add archivo1
git add archivo2
git add archivo3
git add directorio/


Y efectuando el commit
git commit --message 'first commit'

Y sucesivamente sigue el ciclo:

  • Efectuo las modificaciones en mis archivos
  • Agrego los archivos que modifique
    git add -u

    Y si hay que agregar archivos nuevos que no se estaban versionando:
    git add archivo


  • Efectuo el commit con el mensaje apropiado
    git commit --message 'mensaje de commit'

En proximos posts:
  • Como hacer lo mismo con el front-end grafico TortoiseGIT en Windows
  • Como hacer lo mismo con svn (tambien se puede, es un poco mas complicado)
  • Git basico: examinar el historial, versiones previas y despues volver a la "ultima"
  • Dejar de ser individual, migrar a un repositorio en la nube (ejemplo con Github)


domingo, 27 de febrero de 2011

Ad-hoc git infrastructure for team development

En este articulo se va a explicar como crear un repositorio "servidor" de git para poder trabajar en equipos de desarrollo distribuidos en varias maquinas, como nota adicional cabe destacar que si lo que se necesita es usar el git para desarrollo en solitario, es tan sencillo como crear un repositorio (git init), y directamente usarlo.

Para ir mas al tema, se puede ver en el grafico se tienen dos roles, uno es un "server" linux (alternativamente existen maneras de utilizar un servidor windows) y el otro la terminal de desarrollo que puede ser de cualquier OS. Se puede crear este setup en 3 simples pasos:

  • Crear un usuario en el servidor (Opcional) y crear el repositorio vacio con permisos de escritura para ese usuario
  • Clonar el repositorio desde otro lugar para hacer el "first commit"
  • Clonar el repositorio desde las terminales
Crear el usuario (Opcional) y el repositorio en el server

root@server# adduser git
(Va a pedir informacion acerca del nuevo usuario como el password que se pedira mas adelante)

El repositorio debe ser creado en un directorio al que el usuario "git" o el que hayan elegido tenga acceso, para eso tienen que cambiar a ese usuario mediante el comando login:

root@server:~# login
El cual les va a pedir usuario y password, posteriormente se debe crear un directorio para el nuevo repositorio y entrar en el

git@server:~# mkdir repositorio
git@server:~# cd repositorio
Y finalmente, crear el repositorio (Prestar especial atencion al parametro --bare que indica que se esta creando un repositorio "central")

git@server:~/repositorio$ git init --bare

Inicializar el repositorio

Para hacer esto hay que clonar el repositorio desde un client (o puede ser en el mismo servidor) y efectuar el primer commit
user@client:~$ git clone git@server:repositorio
remote: Counting objects: 3, done.
Receiving objects: 100% (3/3), 202 bytes, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
user@client:~$ cd repositorio
user@client:~/repositorio$ touch README
user@client:~/repositorio$ git add README
user@client:~/repositorio$ git commit --message 'first commit'
[master (root-commit) 5b4ee6e] first commit
0 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README
user@client:~/repositorio$ git push origin HEAD:refs/heads/master
Counting objects: 3, done.
Writing objects: 100% (3/3), 203 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@localhost:repositorio
* [new branch] HEAD -> master
Clonar el repositorio desde las terminales

En cada workstation desde donde se va trabajar con el repositorio, se tiene que ejecutar el siguiente comando
user@client:~$ git clone git@server:repositorio
remote: Counting objects: 3, done.
Receiving objects: 100% (3/3), 202 bytes, done.
remote: Total 3 (delta 0), reused 0 (delta 0)

miércoles, 16 de febrero de 2011

git push --force and merging without understanding are both FORBIDDEN

When we make "git push" and the changes are rejected, the two "fast" options are incorrect options:

  • make a "git push --force"
  • do a quickly merge after git pull
Both options lead to different kinds of disasters.

git push --force only "destroy" changes made by the others by overwriting the history with not fast-forward, it's desired the use of git checkout and "overwrite" the tree to revert changes, and KEEP the history. Even the latter must be avoided if possible

Merging without understanding is wrong too, the merge operation must be a pair task with the entire team or almost somebody responsible and with time to dedicate to that task (the author(s) of the commit being merged). Because of this, the developers must work in separated branchs and merge the changes WHEN THEY ARE READY, not as in the example:

Bill: "Tim knows as fix this fu**ing bug , then I will send my changes to the central repository and so that he can fix them..." (git push) "Ooops! rejected push, I need to pull and then merge, BUT QUICKLY, because we need to fix this a continue working. There are diverged changed made by Richard to merge with my changes, but HE WENT TO LUNCH, Then i will merge (and solve confllicts) in a FEW SECONDS, do MY tests and then push "

later, when Richard return from lunch:

Richard: Hello, good lunch, etc... I will continue working in my tasks
...
Richard: WTF!!! $##@|~]]¡±¡±?¡±!!!!!? ##@~}@?]@]@?]±¡¡¡¡ ··# !!!!
main.cpp: In function 'int main()':
main.cpp:3: error: expected primary-expression before '<<' token
main.cpp:3: error: expected primary-expression before '<<' token
main.cpp:3: error: expected primary-expression before '<<' token
main.cpp:3: error: expected primary-expression before '<<' token
main.cpp:3: error: expected primary-expression before '<<' token
main.cpp:3: error: expected primary-expression before '<<' token
main.cpp:3: error: expected primary-expression before '<<' token

Conclusion: Bill and Tim would have to have worked in a centralized and separated branch and waiting for Richard to properly merge the changes to the "master", with the needed time, dedication and the presence of the authors of all the changes involved in the merge, Also using techniques such TDD it's possible to maintain a base to easily test the "integrity" of any version of the project

jueves, 13 de enero de 2011

TFS mirror con GIT

Para mirrorear un repositorio de Team Foundation Server, basta con ejecutar este comando:

git tfs clone

Ejemplo (no les puedo dar uno real porque no conozco ninguno en la web)

git tfs clone http://tfs:8080

NOTA: Esto no es una ninguna broma, se pueden bajar bridge entre git y tfs de aca: https://github.com/spraints/git-tfs

SVN mirror con GIT

Para mirrorear un repositorio de svn, basta con ejecutar este comando:

git svn clone

Ejemplo

git svn clone http://zxing.googlecode.com/svn/trunk/

Actualizar el mirror

git svn rebase

Salu2

GIT mirror con GIT

Para mirrorear un repositorio de git, basta con ejecutar este comando:

git clone

Ejemplo:

git clone git://github.com/tario/shikashi.git

Actualizar el mirror

git pull

Salu2


miércoles, 12 de enero de 2011

git-svn: A GIT lo que es de GIT...

... y a SVN lo que es de SVN

El que el repositorio al cual haya que commitear sea de SVN no implica necesariamente que se tenga que usar esa herramienta como cliente. Git tambien puede "pushear" , por decirlo de alguna manera, a servers de svn. Lo que tiene esto es que se pueden aprovechar las ventajas que tiene git localmente o tambien si se esta mas comodo con git. Por ejemplo, se puede commitear localmente varias veces hasta decidir cuando subir los cambios, y ni hablar cuando hay algun problema que impide la conexion con el server, en ese caso es de gran ayuda.

Para clonar un server svn:

git svn clone $URL

Posteriormente se trabaja como lo harian siempre con git, commit, branch, reset, checkout, etc...

La unica diferencia es al momento de subir los cambios, no es el push de siempre, sino

git svn dcommit


martes, 4 de enero de 2011

Fix commit message

¿Cuantas veces se equivocaron al escribir el mensaje de un commit, poniendo haverrantes faltas hortograficaz, escribiendo cosas que no correspondian, o el peor de los casos, pegando basura que habia en el clipboard?. Bueno, eso se corrige con la opcion amend, es la misma opcion que tambien sirve para corregir el contenido de los commits, solo que esta vez hay que mantener el mismo contenido y se cambia el message del commit.

Ejemplo:

git commit --message 'fixed type'

Me equivoque :S, quise poner 'fixed typo', no 'fixed type' se corrige asi:

git commit --amend --message 'fixed typo'