Voy a intentar desmitificar o corroborar rumores, de manera unívoca y que cualquiera pueda reproducir.
Este artículo y los siguientes admiten colaboraciones :D
Este artículo es un coñazo
Pues sí. Este artículo es un coñazo total. Por eso voy a comenzar por el final: las conclusiones. Así, los crédulos, pueden evitarse la parte de demostración y leer sólo las conclusiones. Los incrédulos pueden llegar hasta el final y comprobar que he tratado de ser todo lo objetivo posible.
Conclusiones
Aquí tenemos las conclusiones finales:
Si en Mercurial renombras un archivo, el repositorio requiere de nuevo el espacio ocupado por el archivo. En git, la diferencia es inapreciable.
En Mercurial, dos “push” simultáneos sin conflicto pueden provocar que el segundo se cancele. En git no ocurre.
Esto demuestra que Git da un mejor rendimiento que Mercurial.
Críticas
Por favor, estoy dispuesto a soportar cualquier tipo de crítica. Sin embargo, me gustaría indicar que este artículo me ha costado MUCHO, ya que no es nada sencillo pensar en las demostraciones y menos realizarlas de manera que se puedan repetir. Y también ha sido compleja la maquetación. Por esa razón, espero que cualquier crítica venga acompañada de demostraciones.
Sé de algunos otros problemas, pero no puedo demostrarlos, así que me los cayo. Estas pruebas son completamente OBJETIVAS.
También acepto demostraciones a favor/en contra de ambos. Sed creativos.
Agradecimientos
Agradezco a David Villa su paciencia haciendo code review de estos scripts.
Me equivoqué al pasarle el de Mercurial y se puede decir que lo rehizo él solo.
Scripts
Los Scripts necesarios para reproducir lo que expongo aquí se pueden encontrar
en github. Allí será donde haga modificaciones a los mismos.
Demostraciones
Si mueves un archivo en mercurial, ocupará espacio de nuevo
Mercurial
Git
$ seq 10000000 > $WC1/file
$ ls -lh $WC1total 6,6M
-rw-r--r-- 1 miguel miguel 6,6M may 27 19:39 file
$ hg -R $WC1 add $WC1/file
$ seq 10000000 > $WC1/file
$ ls -lh $WC1total 6,6M
-rw-r--r-- 1 miguel miguel 6,6M may 27 19:39 file
$ git --git-dir=$WC1/.git --work-tree=$WC1 add $WC1/file
$ git --git-dir=$WC1/.git --work-tree=$WC1 mv file example
$ git --git-dir=$WC1/.git --work-tree=$WC1 commit -am "second"[master f206fe1] second
1 file changed, 0 insertions(+), 0 deletions(-) rename file=> example (100%)$ du -hs $WC18,9M /tmp/wc1-git
Conclusión: Si mueves un archivo en Mercurial, volverá a ocupar espacio. Si mueves un archivo en git, el repositorio seguirá ocupando lo mismo (prácticamente).
Conservando historia entre moves
Este apartado continúa el script anterior:
Mercurial
Git
$ hg -R $WC1 mv $WC1/example $WC1/file
$ hg -R $WC1 commit -m "third"$ du -hs $WC111M /tmp/wc1-hg
$ hg -R $WC1 log $WC1/file --follow
changeset: 2:3d54fb888504
tag: tip
user: Miguel Angel Garcia <magmax@example.org>
date: Thu Jun 13 05:31:08 2013 +0200
summary: third
changeset: 1:f13ffb871397
user: Miguel Angel Garcia <magmax@example.org>
date: Thu Jun 13 05:31:07 2013 +0200
summary: second
changeset: 0:e47df7ca3541
user: Miguel Angel Garcia <magmax@example.org>
date: Thu Jun 13 05:31:07 2013 +0200
summary: initial
$ git --git-dir=$WC1/.git --work-tree=$WC1 mv example file
$ git --git-dir=$WC1/.git --work-tree=$WC1 commit -am "third"[master dd45fed] third
1 file changed, 0 insertions(+), 0 deletions(-) rename example=> file (100%)$ du -hs $WC18,9M /tmp/wc1-git
$ git --git-dir=$WC1/.git --work-tree=$WC1 log -- file
commit dd45fedd449babb33a019f23a2dae244e18f400c
Author: Miguel Angel Garcia <magmax@example.org>
Date: Mon May 27 19:46:49 2013 +0200
third
commit f206fe12540494bf1f6f5193bd6234865da75e13
Author: Miguel Angel Garcia <magmax@example.org>
Date: Mon May 27 19:46:48 2013 +0200
second
commit 50f537cac82b6499c8519af7c7710211bf96c0c3
Author: Miguel Angel Garcia <magmax@example.org>
Date: Mon May 27 19:46:48 2013 +0200
initial
Conclusión: Tanto Mercurial como Git siguen correctamente la historia del archivo. (Gracias, Juan Penalta)
Como dato curioso, se observa que al volver a mover el archivo, en esta ocasión
no ocupa espacio en mercurial.
Dos pushes simultáneos sin conflicto
NOTA: En esta demostración se utilizará el archivo annotate-output, que se encuentra en el paquete “devscripts”. Tan solo añade la hora y el tipo de salida (stdout o stderr) y redirecciona todo a la salida estándar.
$ hg clone ssh://localhost/$SERVER$WC2requesting all changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
updating to branch default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ git clone $SERVER$WC2Cloning into '/tmp/wc2-git'...
done.
$ touch $WC1/file2
$ hg -R $WC1 branch branch1
marked working directory as branch branch1
(branches are permanent and global, did you want a bookmark?)$ hg -R $WC1 add $WC2/file2
$ hg -R $WC1 commit -m "changes on wc1"
$ touch $WC2/fileB
$ hg -R $WC2 branch branch2
marked working directory as branch branch2
(branches are permanent and global, did you want a bookmark?)$ hg -R $WC2 add $WC2/fileB
$ hg -R $WC2 commit -m "changes on wc2"
$ touch $WC2/fileB
$ git --git-dir=$WC2/.git --work-tree=$WC2 checkout -b working-copy-2
Switched to a new branch 'working-copy-2'$ git --git-dir=$WC2/.git --work-tree=$WC2 add fileB
$ git --git-dir=$WC2/.git --work-tree=$WC2 commit -m "changes on wc2"[working-copy-2 eee3889] changes on wc2
0 files changed
create mode 100644 fileB
$ annotate-output +"WC__1__%H:%M:%S" hg -R $WC1 push --new-branch &$ annotate-output +"WC__2__%H:%M:%S" hg -R $WC2 push --new-branch
WC__2__13:31:54 I: Started hg -R /tmp/wc2-hg push --new-branch
WC__1__13:31:54 I: Started hg -R /tmp/wc1-hg push --new-branch
WC__1__13:31:57 O: pushing to ssh://localhost//tmp/server-hg
WC__1__13:31:57 O: searching for changes
WC__1__13:31:57 O: remote: adding changesets
WC__1__13:31:57 O: remote: adding manifests
WC__1__13:31:57 O: remote: adding file changes
WC__1__13:31:57 O: remote: added 1 changesets with 1 changes to 1 files
WC__1__13:31:57 I: Finished with exitcode 0WC__2__13:31:58 E: abort: push failed:
WC__2__13:31:58 O: pushing to ssh://localhost//tmp/server-hg
WC__2__13:31:58 E: 'unsynced changes'WC__2__13:31:58 O: searching for changes
WC__2__13:31:58 O: remote: waiting for lock on repository /tmp/server-hg held by
'nightcrawler:6267'WC__2__13:31:58 I: Finished with exitcode 255
Conclusión: Dos pushes simultáneos sobre ramas diferentes en Mercurial dará un error a la segunda que entre, si la primera se acepta. En git ambas podrán pasar.
¿Por qué ha ocurrido esto en Mercurial? ¿Qué es “Unsynced changes”? Mirando el código es un problema en el protocolo; Mercurial realiza 4 fases principales:
Saludo
Solicitar un hash con el estado de las cabezas del servidor.
Ejecutar hooks
Enviar los deltas con el hash. Si el hash no coincide, abortará.
En nuestro caso, un proceso se ha quedado bloqueado en el paso 3 y el otro ha
obtenido una hash que no coincidirá más tarde. El resultado es que ambas ramas
se bloquean hasta poder alcanzar el paso 4. La primera que llegue, modificará
las cabezas y, por tanto, la hash, que hará que la segunda aborte.
Si el primer proceso falla (un hook que no devuelve 0), la segunda pasará.
Nota personal: Subjetivamente, encuentro mucho más útiles los mensajes de Git que de Mercurial.