<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>il libero &#187; Mercurial</title>
	<atom:link href="http://www.miltonpividori.com.ar/category/software/mercurial/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.miltonpividori.com.ar</link>
	<description>Blog de Milton Pividori</description>
	<lastBuildDate>Mon, 02 Jan 2012 04:12:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Si usás Buildbot con Mercurial&#8230;</title>
		<link>http://www.miltonpividori.com.ar/2009/11/28/si-usas-buildbot-con-mercurial/</link>
		<comments>http://www.miltonpividori.com.ar/2009/11/28/si-usas-buildbot-con-mercurial/#comments</comments>
		<pubDate>Sat, 28 Nov 2009 19:14:42 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[GNU/Linux]]></category>
		<category><![CDATA[Mercurial]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Libre]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=749</guid>
		<description><![CDATA[&#8230; y la versión de Buildbot es la 0.7.11p3 (la última al momento de escribir este post) y Mercurial 1.3.1, que son las versiones que están en Karmic, quizá tengas un problema cuando el Build Slave intenta bajar el código del repositorio para comenzar el ciclo de compilación/testing. Buildbot permite configurar de varias formas el [...]]]></description>
			<content:encoded><![CDATA[<p>&#8230; y la versión de <a href="http://buildbot.net/">Buildbot</a> es la 0.7.11p3 (la última al momento de escribir este post) y <a href="http://mercurial.selenic.com/">Mercurial</a> 1.3.1, que son las versiones que están en Karmic, quizá tengas un problema cuando el Build Slave intenta bajar el código del repositorio para comenzar el ciclo de compilación/testing.</p>
<div id="attachment_757" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2009/11/overview.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2009/11/overview-300x180.png" alt="Arquitectura de Buildbot" title="overview" width="300" height="180" class="size-medium wp-image-757" /></a><p class="wp-caption-text">Arquitectura de Buildbot</p></div>
<p>Buildbot permite <a href="http://djmitche.github.com/buildbot/docs/0.7.11/#Source-Checkout">configurar de varias formas el modo en que va a obtener el código fuente del proyecto y cómo realizará las actualizaciones subsiguientes</a>. Por ejemplo, el modo &#8220;update&#8221; hace que las operaciones de checkout/update se ejecuten en el directorio de trabajo, y no en uno independiente, como en el modo &#8220;copy&#8221; o &#8220;clobber&#8221;, que mantienen un directorio separado y limpio del repositorio (en el caso de Mercurial, &#8220;copia de trabajo&#8221; en el caso de Subversion) y hacen una copia del mismo para realizar la compilación (esto asegura que siempre se compile todo y que no influyan archivos generados en procesos anteriores, además de otros problemas menos comunes pero que existen).</p>
<p>El problema que estuve teniendo es cuando utilizo Mercurial. Al intentar traer el código fuente, Buildbot entra en un bucle infinito donde realiza el checkout (clone), borra el directorio, otra vez clone y asi&#8230; me pareció rarísimo el comportamiento. Versiones anteriores de Buildbot con versiones anteriores de Mercurial funcionan bien.</p>
<p>En uno de los pasos para realizar el checkout/update, Buildbot verifica si ha cambiado la URL del repositorio. Si esto es así, entonces hace clobbering, o sea, vuelve a bajar todos los cambios (checkout) y obviamente no realiza un update, aunque el modo no sea &#8220;clobbering&#8221;. Para saber si dicha URL ha cambiado, ejecuta un &#8220;hg paths default&#8221; en el directorio de trabajo y lo compara con la URL asignada en el archivo de configuración central del Build Master.</p>
<p>El bug está en que al ejecutar &#8220;hg paths default&#8221; Mercurial 1.3.1 devuelve el password oculto con asteriscos:</p>
<pre class="brush: bash; title: ; notranslate">
$ hg paths default 

http://miltondp:***@url.mi_proyecto.com/path/al/repo
</pre>
<p>&#8230; y, obviamente, la URL asignada en el archivo de configuración está completa (sin el password oculto). Al compararse ambas, son distintas, y por lo tanto siempre se hace clobbering.</p>
<p><span id="more-749"></span><br />
Rápidamente me fijé si Mercurial poseía alguna opción para mostrar el password en la salida de &#8220;hg paths&#8221;. No posee dicha opción por lo visto, pero me encontré con <a href="http://www.selenic.com/pipermail/mercurial-devel/2009-February/010529.html">un parche</a> que alguien envió alguna vez, el cual parece que nunca fue incluido. El mismo agrega la opción &#8220;&#8211;show-passwords&#8221; para mostrar la URL completa al ejecutar &#8220;hg paths&#8221;. Lo pueden bajar <a href="http://www.miltonpividori.com.ar/files/mercurial_commands.patch">aquí</a>. El archivo a parchear es <em>&#8220;/usr/lib/pymodules/python2.6/mercurial/commands.py&#8221;</em>.</p>
<p>También hay que parchear Buildbot para que utilice esta nueva opción al comparar los repositorios. Este otro parche lo pueden bajar desde <a href="http://www.miltonpividori.com.ar/files/buildbot_commands.patch">este lugar</a>. Tener en cuenta que el archivo a parchear tiene el mismo nombre que el de Mercurial. El path del mismo es <em>&#8220;/usr/lib/python2.6/dist-packages/buildbot/slave/commands.py&#8221;</em></p>
<p>No se olviden de reiniciar el servicio de Buildbot, y de borrar los archivos .pyc de Python (por lo visto a veces funciona aunque no lo borremos). Ahora el ciclo funciona como uno espera:</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2009/11/buildbot.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2009/11/buildbot-257x300.png" alt="buildbot" title="buildbot" width="257" height="300" class="aligncenter size-medium wp-image-763" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2009/11/28/si-usas-buildbot-con-mercurial/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Mercurial Queues: una aplicación simple</title>
		<link>http://www.miltonpividori.com.ar/2009/01/15/mercurial-queues-una-aplicacion-simple/</link>
		<comments>http://www.miltonpividori.com.ar/2009/01/15/mercurial-queues-una-aplicacion-simple/#comments</comments>
		<pubDate>Thu, 15 Jan 2009 15:47:01 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Mercurial]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Libre]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=385</guid>
		<description><![CDATA[Hace un tiempo comencé a leer un poco sobre esta extensión de Mercurial: Mercurial Queues (Mq). ¿Para qué sirve? Bueno, imagínense que tienen una instalación de WordPress con ciertas modificaciones que le han hecho. Supongan que la versión del CMS que están usando es la 2.6.5. Quieren actualizar a la 2.7 pero sin perder los [...]]]></description>
			<content:encoded><![CDATA[<p>Hace un tiempo comencé a leer un poco sobre esta extensión de Mercurial: <a href="http://www.selenic.com/mercurial/wiki/index.cgi/MqExtension">Mercurial Queues</a> (Mq). ¿Para qué sirve? Bueno, imagínense que tienen una instalación de WordPress con ciertas modificaciones que le han hecho. Supongan que la versión del CMS que están usando es la 2.6.5. Quieren actualizar a la 2.7 pero sin perder los cambios, y que la migración sea sencilla. Bueno, Mq les permite mantener estos cambios personales como parches, que pueden aplicar, modificar, quitar, reordenar&#8230; De esta forma, con una serie de pasos, pueden actualizar fácilmente el código &#8220;de fondo&#8221; (o sea, de WordPress 2.6.5 a la 2.7) y reaplicar esos parches sobre esta nueva base. En <a href="http://atlee.ca/blog/2008/10/25/upgrading-wordpress-with-mercurial/">este post</a> pueden ver el ejemplo desarrollado.</p>
<p><span id="more-385"></span><br />
De todas formas, parece que ese no es el uso principal. Piensen que están colaborando con algún proyecto, donde utilizan Mercurial (o cualquier DCVS). Están trabajando en una nueva funcionalidad. Sabemos que los commits son inmutables. No sería conveniente que hagan commits en su repositorio local y luego intenten enviar todos esos cambios (que tendrán varios merges de por medio quizá) para la revisión, porque la dificulta. Lo conveniente sería (según explican al introducirnos en Mq) enviar parches con el trabajo finalizado. De esta forma podríamos ir manteniendo distintos parches de acuerdo a nuestro trabajo e ir actualizándolos a medida que avancemos. Como Mercurial Queues integra los parches a todo el sistema, los mismos son tratados como changesets, por lo tanto podemos pensar en los mismos como commits mutables: terminamos con nuestro trabajo y actualizamos el commit. Al día siguiente nos damos cuenta de que había un error y lo volvemos a actualizar con el nuevo trabajo. Incluso, como dije, podemos descartarlos, reordenarlos, etc. Y a medida que el trabajo se hace más complejo, podemos tener distintos parches, cada uno con cambios relacionados.</p>
<p>Yo tengo hecho mi CV en LaTeX bajo Mercurial. Después de un tiempo manteniéndolo y actualizándolo, me encontré colocando notas en forma de TODO o FIXME para recordar actualizar ciertas cosas, o trabajos sobre el mismo a medio hacer. El problema es que cuando tengo que enviar una versión limpia de mi CV, debo compilar una versión &#8220;estable&#8221; quitando todas estas modificaciones no terminadas. Por lo tanto es ideal usar Mq en esta situación: mantengo estos &#8220;features&#8221; o recordatorios como parches o commits mutables. Cuando quiero agregar algún recordatorio o estoy trabajando en una ampliación o reestruración, trabajo sobre los parches y los voy actualizando. Cuando veo que ya están listos, los transformo en changeset normales (o sea, inmutables). Cuando quiero compilar una versión estable, quito todos los parches, quedando así una versión limpia lista para enviar.</p>
<p>Algunos comandos como para que se den una idea de cómo funciona:</p>
<pre class="brush: plain; title: ; notranslate">
$ hg qinit
$ hg qnew nueva.funcionalidad
# Ahora estoy trabajando en el parche &quot;nueva.funcionalidad&quot;. Realizo cambios, agrego archivos con &quot;hd add&quot;, etc... trabajo comúnmente como siempre.
$ hg qrefresh
# con este comando actualizo el parche en el que estoy trabajando. Todos los cambios realizados son guardados ahora en &quot;nueva.funcionalidad&quot;.
</pre>
<p>Si quiero quitar todos los parches aplicados ejecuto:</p>
<pre class="brush: plain; title: ; notranslate">
$ hg qpop -a
</pre>
<p>Si quiero aplicar todos los parches:</p>
<pre class="brush: plain; title: ; notranslate">
$ hg qpush -a
</pre>
<p>Si quiero moverme a un parche específico:</p>
<pre class="brush: plain; title: ; notranslate">
$ hg qgoto nombre.parche
</pre>
<p>Uno de los inconvenientes que surgió después de haberme encontrado con esta fantástica herramienta, fue que quería subir estos parches al repositorio. De esta forma, podría acceder a ellos y modificarlos desde cualquier máquina. Sin embargo esto no es trivial. La solución pasa por armar otro repositorio en el servidor. Por lo tanto el directorio local <em>.hg/patches</em> que posee todos los parches, se transforma en otro repositorio Mercurial y lo tratamos como tal: de vez en cuando subimos al repo de parches nuestros cambios a los mismos. Esto puede parecer tedioso, pero Mercurial ofrece unas utilidades que facilitan las cosas.</p>
<p>Me parece que es una extensión muy útil. En lo personal no me fue fácil agarrarle la mano rápidamente. Aunque como todo, para dominarlo hay que ponerlo en práctica.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2009/01/15/mercurial-queues-una-aplicacion-simple/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Mercurial con Meld</title>
		<link>http://www.miltonpividori.com.ar/2008/12/08/mercurial-con-meld/</link>
		<comments>http://www.miltonpividori.com.ar/2008/12/08/mercurial-con-meld/#comments</comments>
		<pubDate>Mon, 08 Dec 2008 23:54:39 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Mercurial]]></category>
		<category><![CDATA[Software Libre]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=462</guid>
		<description><![CDATA[Uso meld para realizar comparaciones entre archivos o directorios. Mercurial, al detectar un conflicto, busca en el sistema algún programa gráfico para resolverlo, mostrando las diferencias y así poder realizar el merge. La idea es que en los tres paneles de meld, a la izquierda tengamos la versión de base, en la que se basan [...]]]></description>
			<content:encoded><![CDATA[<p>Uso <a href="http://meld.sourceforge.net/">meld</a> para realizar comparaciones entre archivos o directorios. <a href="http://www.selenic.com/mercurial/">Mercurial</a>, al detectar un conflicto, busca en el sistema algún programa gráfico para resolverlo, mostrando las diferencias y así poder realizar el merge.</p>
<p>La idea es que en los tres paneles de meld, a la izquierda tengamos la versión de base, en la que se basan (valga la redundancia) nuestras modificaciones y las de la otra rama, en el medio nuestro archivo, y a la derecha el del otro. Trabajamos con la vista del medio, realizamos la fusión y guardamos los cambios al finalizar. Así resolvemos el conflicto.</p>
<p>Sin embargo no es ese el orden en el que aparecen los archivos en meld cuando trabajamos con Mercurial. Buscando en la ayuda de configuración, he encontrado estas opciones que podemos utilizar en nuestro ~/.hgrc, y así resolver este inconveniente:</p>
<pre class="brush: plain; title: ; notranslate">
[merge-tools]
meld.executable = meld
meld.args = $base $local $other
meld.priority = 1
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2008/12/08/mercurial-con-meld/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mercurial vs Subversion: branching and merging</title>
		<link>http://www.miltonpividori.com.ar/2008/10/19/mercurial-vs-subversion-branching-and-merging/</link>
		<comments>http://www.miltonpividori.com.ar/2008/10/19/mercurial-vs-subversion-branching-and-merging/#comments</comments>
		<pubDate>Sun, 19 Oct 2008 19:20:01 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Facultad]]></category>
		<category><![CDATA[Mercurial]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Libre]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=363</guid>
		<description><![CDATA[Hace un tiempo vengo estudiando este sistema de control de versiones distribuído, hecho principalmente en Python, y que lo utilizan algunos grandes proyectos como Mozilla, OpenJDK, NetBeans, etc. En este post, quería compararlo con Subversion, con respecto a mantener distintas ramas de desarrollo. Aclaro que si bien no tengo una experiencia real con ambos sistemas [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/branching.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/branching.png" alt="" title="branching" width="321" height="135" class="aligncenter size-full wp-image-359" /></a></p>
<p>Hace un tiempo vengo estudiando este sistema de control de versiones distribuído, hecho principalmente en Python, y que lo utilizan algunos grandes proyectos como Mozilla, OpenJDK, NetBeans, etc. En este post, quería compararlo con Subversion, con respecto a mantener distintas ramas de desarrollo.</p>
<p>Aclaro que si bien no tengo una experiencia real con ambos sistemas en el tema, como la podría tener algún desarrollador de un proyecto grande de Software Libre, leyendo los manuales, viendo los ejemplos y utilizándolo en pequeños proyectos con pocos desarrolladores uno puede darse una idea de cómo son las cosas a gran escala.</p>
<p>En muchos lugares se habla de las bondades de los sistemas de control de versiones distribuidos. Una de las ventajas que tienen (entre muchas otras), según se dice, es la facilidad para manejar branches, donde se mencionan las deficiencias de Subversion para manejar varias ramas de desarrollo.</p>
<p>Este post puede servir para alguien que esta pensando en alguna herramienta de versionado, donde se esperan utilizar varios branches en el proyecto, como para poder ver de forma sencilla cómo manejan esto ambos sistemas. Esa &#8220;forma sencilla&#8221; de verlo podría significar también una divergencia importante con la práctica. Así que si piensan que algo es incorrecto, los invito a dejar un comentario.</p>
<p><span id="more-363"></span><br />
En fin, ¿cómo se realizan estas operaciones en ambos sistemas?</p>
<p>Aquí con <em>branch</em> me refiero a una línea de desarrollo para agregar un nuevo feature o corregir un bug, etc. La aclaración es importante, porque en Mercurial casi siempre trabajamos con branches. Si hago un pull y traigo changesets (es decir commits) puede que surjan nuevas ramas. Este no es el significado al que me refiero aquí.</p>
<h3>Subversion</h3>
<p>En Subversion, no existe el concepto de branch. Un branch es simplemente una copia de un directorio a otro lugar. Uno mismo es el que le da ese significado.</p>
<p>Puedo hacer la copia directamente en el repositorio (donde automáticamente hago un commit):</p>
<pre class="brush: plain; title: ; notranslate">
$ svn copy http://svn.example.com/repos/calc/trunk \
           http://svn.example.com/repos/calc/branches/my-calc-branch \
      -m &quot;Creating a private branch of /calc/trunk.&quot;

Committed revision 341.
</pre>
<p>Si tengo la copia de trabajo correspondiente a todo el repositorio en mi máquina (incluyendo las típicas carpetas <em>trunk</em>, <em>branches</em> y <em>tags</em>):</p>
<pre class="brush: plain; title: ; notranslate">
$ svn copy trunk branches/my-calc-branch
$ svn status
A  +   branches/my-calc-branch
$
$ svn commit -m &quot;Creating a private branch of /calc/trunk.&quot;
Adding         branches/my-calc-branch
Committed revision 341.
</pre>
<p>Luego simplemente comienzo a trabajar en esa carpeta, en mi nuevo branch. Sin embargo, hay una serie de inconvenientes. No podemos dejar que la línea principal de desarrollo se aleje demasiado de nuestro branch (supongamos que estamos agregando un nuevo feature), ya que al intentar fusionar todo luego de un largo tiempo, podemos terminar por frustrarnos. Esto, obviamente, no se aplica sólo a Subversion.</p>
<p>Entonces, periódicamente, traemos los cambios hechos en trunk a nuestra copia de trabajo, que corresponde a la rama en la que estamos trabajando:</p>
<pre class="brush: plain; title: ; notranslate">
$ svn merge -r 100:200 http://svn.example.com/repos/trunk my-working-copy
...
$ svn commit -m &quot;Sync with trunk&quot;
</pre>
<p>El comando &#8220;svn merge&#8221; es muy similar a &#8220;svn diff&#8221;, pero aplica los cambios a mi copia de trabajo.</p>
<p>Como dice en el libro de Subversion, fusionar los cambios suena fácil, pero puede resultar en un dolor de cabeza. Yo, el usuario, soy el que tengo que controlar los merges que hago. Subversion (las versiones menores a las 1.5) no lo hacen. Esto significa que puedo fusionar los cambios dos veces, por ejemplo, o puedo comparar dos cosas sin ningún tipo de relación e intentar aplicar los cambios resultantes a mi copia de trabajo. Cuando ejecuto un comando parecido al de arriba, Subversion no sabe qué significan esos cambios. Simplemente se aplican a la copia de trabajo.</p>
<p>Supongamos que el día al fin ha llegado, y quiero traer a trunk mi nuevo feature, desarrollado en mi branch. Como dice en el libro, si están pensando en comparar la última revisión de trunk con la última del branch, se equivocan: ¿qué pasaría con los cambios hechos en trunk que nunca sucedieron en el branch? Se borrarían, y eso no es lo que queremos.</p>
<p>Lo que hay que hacer es comparar el estado inicial del branch con su estado final. De esta forma <em>adiciono</em> a trunk los cambios que he realizado en mi branch. Para esto tengo que saber en qué revisión creé mi branch. Una forma fácil de averiguar esto con Subversion:</p>
<pre class="brush: plain; title: ; notranslate">
$ svn log --verbose --stop-on-copy \

http://svn.example.com/repos/calc/branches/my-calc-branch

…
------------------------------------------------------------------------
r341 | user | 2002-11-03 15:27:56 -0600 (Thu, 07 Nov 2002) | 2 lines
Changed paths:
   A /calc/branches/my-calc-branch (from /calc/trunk:340)

$
</pre>
<p>El procedimiento completo, sacado del libro, es este:</p>
<pre class="brush: plain; title: ; notranslate">
$ cd calc/trunk
$ svn update
At revision 405.

$ svn merge -r 341:405 http://svn.example.com/repos/calc/branches/my-calc-branch
U   integer.c
U   button.c
U   Makefile

$ svn status
M   integer.c
M   button.c
M   Makefile

# ...examine the diffs, compile, test, etc...

$ svn commit -m &quot;Merged my-calc-branch changes r341:405 into the trunk.&quot;
Sending        integer.c
Sending        button.c
Sending        Makefile
Transmitting file data ...
Committed revision 406.
</pre>
<p>Noten lo descriptivos que son los mensajes de commit. Esto es necesario hacerlo así, para saber luego, por ejemplo, que ya se han aplicado los cambios del branch, y qué cambios involucran. Es información crítica: supongan que siguen trabajando en el branch y quieren traer los nuevos cambios hechos. Necesitan saber qué cambios ya han sido aplicados para no volver a traerlos a trunk. Para hacer eso, básicamente se ejecutan los comandos anteriores, alterando el rango de las revisiones según corresponda.</p>
<p>Cuando estaba aprendiendo Subversion, leí muy por arriba estas cosas, ya que no eran las que iba a utilizar habitualmente, y además me pareció un poco complicado, con varias advertencias de posibles problemas al fusionar cambios, etc. Por eso estoy copiando los ejemplos del libro, y ahora, en realidad, estoy viendo bien cómo funciona.</p>
<p>Sin embargo una de las cosas que sí aprendí a hacer ya que me parecieron muy útiles, que tiene relación con esto, es <strong>&#8220;deshacer&#8221; un commit</strong>, o sea, anular sus cambios. La forma de hacerlo es la siguiente:</p>
<pre class="brush: plain; title: ; notranslate">
$ svn merge -r 303:302 http://svn.example.com/repos/calc/trunk
U  integer.c

$ svn status
M  integer.c

$ svn diff
…
# verify that the change is removed
…

$ svn commit -m &quot;Undoing change committed in r303.&quot;
Sending        integer.c
Transmitting file data .
Committed revision 350.
</pre>
<p>Simplemente se invierten, como habrán notado, el orden de las revisiones a comparar, resultando en un patch contrario al que aplica, en este caso, el commit 303, provocando la anulación de sus modificaciones. Sin embargo, si quiero traer un objeto eliminado de vuelta, no utilizo el comando anterior, sino &#8220;svn copy&#8221;.</p>
<p>Todas estas cosas que pueden parecer complicadas (y de hecho lo son), parecen estar comenzando a cambiar a partir de Subversion 1.5. Por ejemplo, algunos de los nuevos features, que podemos leer en las <a href="http://subversion.tigris.org/svn_1.5_releasenotes.html">release notes</a>, son <a href="http://subversion.tigris.org/svn_1.5_releasenotes.html#merge-tracking">merge tracking</a> y la <a href="http://subversion.tigris.org/svn_1.5_releasenotes.html#interactive-conflict-resolution">resolución interactiva de conflictos</a>. Sin embargo el primero, como se menciona, posee una funcionalidad básica.</p>
<h3>Mercurial</h3>
<p>Veamos ahora cómo es esto en Mercurial. Aquí un desarrollador no posee únicamente la copia de trabajo, como en Subversion, sino el repositorio completo. Una forma fácil de crear un branch en Mercurial es clonar mi repositorio actual. Supongamos que tengo uno en la carpeta <em>myproject</em>:</p>
<pre class="brush: plain; title: ; notranslate">
$ hg clone myproject myproject-1.0
updating working directory
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
</pre>
<p>De esta forma puedo comenzar a trabajar en el nuevo branch creado:</p>
<pre class="brush: plain; title: ; notranslate">
$ cd myproject-1.0
$ echo 'Alguna nueva funcionalidad' &gt; algunArchivo
$ hg commit -A -m 'Nuevo feature!'
adding algunArchivo
</pre>
<p>Con esta manera de crear ramas, hay una relación uno-a-uno entre los branches en los que estoy trabajando y las carpetas existentes. Si necesito centralizar el branch porque voy a trabajar con otros desarrolladores y queremos tener un lugar común donde subir los cambios, entonces puedo subir el repositorio por FTP por ejemplo, a la carpeta donde el script <em>hgwebdir.cgi</em> verifique la existencia de repositorios. Con copiar la carpeta allí y realizar unas simples configuraciones en el archivo <em>.hg/hgrc</em> ya estamos. Otra es, si tenemos acceso shell a la máquina servidor, clonar el repositorio allí mismo.</p>
<p><a href="http://hg.mozilla.org/">Estos</a> son los repositorios Mercurial de Mozilla. Allí se pueden ver varios. En uno de ellos se hace un merge con otro, como se puede ver en <a href="http://hg.mozilla.org/actionmonkey-tamarin/rev/604b9b57495b">este changeset</a>.</p>
<p>Si corrijo algún error en mi branch <em>myproject-1.0</em>, seguramente también queramos llevar esas correcciones en la linea principal de desarrollo (digamos, trunk), en el cual, supongamos, también se han hecho modificaciones. Para hacer esto, nos ubicamos en el directorio en donde queremos llevar los cambios (la linea principal en este caso), y ejecutamos un pull indicando la carpeta del branch:</p>
<pre class="brush: plain; title: ; notranslate">
$ cd myproject/
$ hg pull ../myproject-1.0
pulling from ../myproject-1.0
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 2 changes to 2 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg merge
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
</pre>
<p>Con el comando pull lo que hago es traer los cambios (changesets) hechos en el repositorio que le paso como argumento. Cada changeset sabe cuál es su padre, por lo tanto al pullear, se armarán las ramas que sean necesarias. Después del pull, yo sigo en la revisión en la que estaba. Nada ha cambiado en mi copia de trabajo, simplemente se sincronizó mi repositorio actual con el otro.</p>
<p>Notar que Mercurial me avisa que han quedado varios heads: un head es un changeset sin hijos. Con el comando &#8220;hg view&#8221; puedo ver el panorama actual del repositorio:</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/despues_de_un_pull.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/despues_de_un_pull.png" alt="" title="despues_de_un_pull" width="443" height="491" class="aligncenter size-full wp-image-377" /></a></p>
<p>El comando &#8220;hg merge&#8221; fusiona, justamente, mi copia de trabajo con otra revisión. Lo que hace es aplicar a mi copia de trabajo todos los cambios de la otra rama, según corresponda.</p>
<p>Notar que si bien estamos diciendo que utilizamos un branch, <em>myproject-1.0</em>, estos dos heads aquí, también representan branches, pero del tipo &#8220;little picture&#8221; (como se explica en el <a href="http://hgbook.red-bean.com/">libro de Mercurial</a>). Este tipo de branches aparecen todos los días, cuando pulleamos cambios de otro repositorio: son parte del trabajo cotidiano. En cambio el branch <em>myproject-1.0</em> es del tipo &#8220;big picture&#8221;, ya que vamos a trabajar en la versión 1.0, corrigiendo errores, etc.</p>
<p>Si &#8220;hg merge&#8221; detecta conflictos, se ejecuta algún visor de diferencias, como <a href="http://meld.sourceforge.net/">meld</a> o <a href="http://kdiff3.sourceforge.net/">kdiff3</a>. Mercurial se encarga de buscarlo en el sistema, o podemos setearlo nosotros en el archivo ~/.hgrc. Estos visores tienen tres vistas: a la izquierda están mis cambios, en el medio el resultado, y a la derecha los cambios del otro. Entonces es muy sencillo resolver el conflicto.</p>
<p>Como Mercurial nos recuerda después de ejecutar el merge, no debemos olvidarnos de hacer un commit aquí. Este commit tendrá como padres a los dos heads actuales:</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/merge-hecho.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/merge-hecho.png" alt="" title="merge-hecho" width="443" height="491" class="aligncenter size-full wp-image-381" /></a></p>
<p>Si bien estamos hablando de un sistema distribuído, obviamente que si queremos compartir cambios, la manera sencilla de trabajar es poner un repositorio central visto por todos los desarrolladores, al cual todos puedan subir sus cambios, y del cual puedan bajar los cambios de otros. Si realizo commits en mi repositorio local y quiero subirlos al remoto (con un push), Mercurial me avisará si es que estoy por generar heads remotamente. Si esto sucede, tengo que hacer un pull, mergear los dos heads, y luego subir el resultado.</p>
<p>Esta situación es similar en Subversion a cuando intentamos hacer un commit y nos dice que tenemos que ejecutar un update antes: entonces aplica los cambios en nuestra copia de trabajo, resolvemos los conflictos si es necesario, y realizamos un commit.</p>
<p><strong>Otra forma de crear un branch</strong> en Mercurial, es hacerlo en el mismo repositorio, con <em>Named Branches</em>. Así nos ahorramos el tener que subir algo al servidor. Por defecto, si no hemos cambiado nada, trabajamos en el branch llamado <em>default</em>.</p>
<p>Con el comando &#8220;branches&#8221; puedo ver cuáles hay en mi repositorio:</p>
<pre class="brush: plain; title: ; notranslate">
$ hg branches
default                        0:34b3e0e21c40
</pre>
<p>Y con el comando &#8220;branch&#8221; veo en qué branch estoy trabajando ahora:</p>
<pre class="brush: plain; title: ; notranslate">
$ hg branch
default
</pre>
<p>Supongamos que hemos hecho unos commits en la rama <em>default</em>:</p>
<pre class="brush: plain; title: ; notranslate">
$ hg log
changeset:   1:7c0e8fbd1fb1
user:        Milton Pividori &lt;mimail@proveedor.com&gt;
date:        Sun Oct 12 13:52:18 2008 -0300
summary:     Agrego chau.cs

changeset:   0:936587b0804a
user:        Milton Pividori &lt;mimail@proveedor.com&gt;
date:        Sun Oct 12 13:52:05 2008 -0300
summary:     Agrego hola.cs
</pre>
<p>Entonces, para comenzar a trabajar en un nuevo branch, digamos myproject-1.0, hacemos:</p>
<pre class="brush: plain; title: ; notranslate">
$ hg branch myproject-1.0
marked working directory as branch myproject-1.0
$ hg branch
myproject-1.0
</pre>
<p>Como nos indica el comando &#8220;branch&#8221;, ahora estamos trabajando en nuestro nuevo branch recién creado. El comando por sí sólo no hace nada. Simplemente le indica a Mercurial que <em>a partir de ahora</em>, vamos a comenzar a trabajar en este branch. Si hacemos un commit, Mercurial marcará el changeset como perteneciente a ese branch, y así con todos los changesets siguientes. Supongamos que hemos realizado tres commits más en este nuevo branch:</p>
<pre class="brush: plain; title: ; notranslate">
$ hg log -b myproject-1.0
changeset:   4:188979745f99
branch:      myproject-1.0
tag:         tip
user:        Milton Pividori &lt;mimail@proveedor.com&gt;
date:        Sun Oct 12 14:05:53 2008 -0300
summary:     Agrego comoestas.cs

changeset:   3:06231db27675
branch:      myproject-1.0
user:        Milton Pividori &lt;mimail@proveedor.com&gt;
date:        Sun Oct 12 14:01:02 2008 -0300
summary:     Nuevo feature en chau.cs

changeset:   2:d2d1fd5f5b39
branch:      myproject-1.0
user:        Milton Pividori &lt;mimail@proveedor.com&gt;
date:        Sun Oct 12 14:00:48 2008 -0300
summary:     Nuevo feature en hola.cs
</pre>
<p>Y supongamos que el trabajo en la rama <em>default</em> continúa con más commits. Entonces el panorama en el repositorio luce como esto:</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/branches.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/branches.png" alt="" title="branches" width="193" height="110" class="aligncenter size-full wp-image-374" /></a></p>
<p>La rama de la izquierda corresponde a <em>default</em>, y la de la derecha a <em>myproject-1.0</em>. Para moverme entre los distintos branches de un repositorio, utilizo el comando &#8220;hg update nombreBranch&#8221;. Si después de eso realizo más commits, obviamente, pertenecerán al branch al que me he movido.</p>
<p>Supongamos que mi trabajo en el branch <em>myproject-1.0</em> ha terminado, y quiero fusionar los cambios con default. Para eso me muevo al branch <em>default</em> (notar que llamo branch a la linea principal de trabajo), o sea a donde quiero llevar mis cambios, y utilizo, nuevamente, el comando &#8220;hg merge&#8221; seguido del nombre del branch del que quiero traer los cambios:</p>
<pre class="brush: plain; title: ; notranslate">
$ hg update default
2 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg merge myproject-1.0
merging chau.cs
merging hola.cs
1 files updated, 2 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg ci -m &quot;Merge de myproject-1.0 a default&quot;
</pre>
<p>El nuevo commit pertenecerá al branch <em>default</em>. Este comportamiento es el esperado: fusiono los cambios de un branch dentro del que yo estoy trabajando.</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/meld.png">Aquí pueden ver una captura de meld</a> cuando se presenta un conflicto, y a continuación el estado final del repositorio, luego de fusionar los cambios de mi branch a <em>default</em>:</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/merge-final-named-branches.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/merge-final-named-branches.png" alt="" title="merge-final-named-branches" width="259" height="118" class="aligncenter size-full wp-image-408" /></a></p>
<p>Veamos cómo <strong>deshacer un commit con Mercurial</strong>. Supongamos que éste es el estado actual del repositorio:</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/eliminar-changeset1.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/eliminar-changeset1.png" alt="" title="eliminar-changeset1" width="155" height="113" class="aligncenter size-full wp-image-395" /></a></p>
<p>Si me doy cuenta que el changeset 4 (&#8220;Bug fix en bar&#8221;) es incorrecto, entonces lo deshago con el comando &#8220;hg backout&#8221;:</p>
<pre class="brush: plain; title: ; notranslate">
$ hg backout --merge 4
reverting bar
created new head
changeset 7:cad3793b208a backs out changeset 4:e56015c82591
merging with changeset 7:cad3793b208a
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
</pre>
<p>El comando &#8220;backout&#8221; crea una nueva revisión teniendo como padre aquella que quiere deshacer. Por lo tanto se generará un nuevo head. La opción &#8220;&#8211;merge&#8221; automáticamente fusiona los cambios con la otra cabeza.</p>
<p>Después del commit, el repositorio queda así:</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/eliminar-changeset2.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/10/eliminar-changeset2.png" alt="" title="eliminar-changeset2" width="251" height="135" class="aligncenter size-full wp-image-397" /></a></p>
<p>Al mensaje de log lo genera Mercurial.</p>
<h3>Conclusiones finales</h3>
<p>Creo que realizar branches y luego fusionarlos es bastante más fácil en Mercurial. No tengo que ver en qué revisión comencé el branch y calcular el rango como en Subversion. No tengo que preocuparme de no aplicar dos veces los mismos cambios. Si sigo trabajando en mi branch, traer los nuevos cambios es muy sencillo, ya que Mercurial es el que controla esto. No hace falta ser descriptivo con los logs de los commits, porque con &#8220;hg view&#8221; puedo ver gráficamente el panorama y saber qué commits fueron realizados para fusionar cambios.</p>
<p>Revertir el cambio de una revisión parece sencillo en ambos, salvo que en Mercurial el comando para resucitar un objeto eliminado, que en definitiva es anular un commit, sigue siendo &#8220;backout&#8221;. En Subversion había que utilizar &#8220;copy&#8221;. De todas formas habría que probarlos en situaciones reales en contextos más complicados.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2008/10/19/mercurial-vs-subversion-branching-and-merging/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Bisecando con Mercurial (o encontrando changesets con bugs)</title>
		<link>http://www.miltonpividori.com.ar/2008/09/03/bisecando-con-mercurial-o-encontrando-changesets-con-bugs/</link>
		<comments>http://www.miltonpividori.com.ar/2008/09/03/bisecando-con-mercurial-o-encontrando-changesets-con-bugs/#comments</comments>
		<pubDate>Wed, 03 Sep 2008 15:05:31 +0000</pubDate>
		<dc:creator>miltondp</dc:creator>
				<category><![CDATA[Facultad]]></category>
		<category><![CDATA[Mercurial]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Software Libre]]></category>

		<guid isPermaLink="false">http://www.miltonpividori.com.ar/?p=274</guid>
		<description><![CDATA[Hace un tiempo vengo leyendo y estudiando Mercurial, un sistema de control de versiones distribuido. Sin embargo todo lo que se es teoría, ya que mis amigos (con los que podría probarlo) no quieren dejar Subversion. Pero bueno&#8230; sin decir quiénes son, y al saber que ellos leen mi blog, sólos se darán cuenta que [...]]]></description>
			<content:encoded><![CDATA[<p>Hace un tiempo vengo leyendo y estudiando <a href="http://www.selenic.com/mercurial/">Mercurial</a>, un sistema de control de versiones distribuido. Sin embargo todo lo que se es teoría, ya que <a href="http://www.cesarsandrigo.com.ar/">mis</a> <a href="http://nacho.larrateguy.com.ar/">amigos</a> (con los que podría probarlo) no quieren dejar Subversion. Pero bueno&#8230; sin decir quiénes son, y al saber que ellos leen mi blog, sólos se darán cuenta que están en el error <img src='http://www.miltonpividori.com.ar/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>A grandes rasgos (y según lo que yo entendí y veo más notorio), la gran diferencia entre los sistemas de control de versiones centralizados como Subversion o CVS y los distribuidos como Git, Mercurial y Bazaar, es que los primeros imponen más restricciones que sus pares distribuidos. En Subversion por ejemplo, si accedo a mi repositorio vía Internet, y en algún momento no tengo conexión, entonces no puedo hacer commits. Si quiero ver los logs de algunas revisiones o realizar otras operaciones que no sean updates o commits, necesito acceder al repositorio central, lo que es más lento.</p>
<p>En los sistemas centralizados hay un servidor central, y varias copias de trabajo, una por cada desarrollador. En los sistemas distribuidos puede o no haber un servidor central con el repositorio, pero la diferencia es que todos los desarrolladores tienen el repositorio completo, no una copia de trabajo. Es decir que cada persona posee la versión actual más toda la historia del proyecto en su computadora, lo que permite operar en modo offline. Esto puede parecer ineficiente, pero de hecho no lo es: los grandes proyectos de Software Libre como Linux, NetBeans, OpenJDK, Mozilla, y en un futuro GNOME también, usan estos sistemas, ya que ofrecen grandes beneficios (especialmente para los proyectos Open Source). Imagínense hacer commits, crear branches, etc, sin necesidad de conexión. Y cuando termino mi trabajo, luego de revisarlo bien, ahí recién puedo subir todo, o sino decirle a mi colega desarrollador que actualice su repositorio desde el mío.</p>
<p>En definitiva, con un sistema distribuido puedo trabajar con menos restricciones que con uno centralizado.</p>
<p><span id="more-274"></span><br />
Estos días estaba leyendo el capítulo 9 de un <a href="http://hgbook.red-bean.com/">libro de Mercurial</a>. Uno de los subcapítulos está dedicado a la búsqueda de revisiones o changesets que han introducido bugs. Realizar esto con Mercurial es fácil, ya que tengo todo el repositorio disponible para trabajar offline, por lo que las búsquedas entre changesets son mucho más rápidas.</p>
<p>Imagínense que encontramos un error en nuestro proyecto, y queremos ver en qué revisión fue introducido para realizar un <a href="http://hgbook.red-bean.com/hgbookch9.html#x13-1790009.3">backout</a> del mismo. Para esto, en Mercurial, podemos utilizar el comando &#8220;bisect&#8221;. Hagamos el ejemplo que se muestra en el libro para ser breves y correctos. Ejecutamos:</p>
<pre class="brush: plain; title: ; notranslate">
$ hg init test
$ cd test
</pre>
<p>Con un script bash creo automáticamente algunos changesets, e introduzco un bug en el commit 22:</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/bash

buggy_change=22
for (( i = 0; i &lt; 35; i++ )); do
	if [[ $i = $buggy_change ]]; then
		echo 'i have a gub' &gt; myfile$i
		hg commit -q -A -m 'buggy changeset'
	else
		echo 'nothing to see here, move along' &gt; myfile$i
		hg commit -q -A -m 'normal changeset'
	fi
done
</pre>
<p>Ejecuto el script en el directorio del repositorio. Esperamos unos momentos a que finalice. Encontrarán varios archivos myfile*. Actualmente estamos, obviamente, en la revisión tip (o HEAD en Subversion):</p>
<pre class="brush: plain; title: ; notranslate">
$ hg parent
changeset:   34:a1c784850dca
tag:         tip
user:        Milton Pividori &lt;miltondp@gmail.com&gt;
date:        Wed Sep 03 10:53:58 2008 -0300
summary:     normal changeset

$
</pre>
<p>Para saber si en la revisión actual se encuentra el bug, simplemente ejecutamos esto:</p>
<pre class="brush: plain; title: ; notranslate">
$ grep 'i have a gub' myfile*
myfile22:i have a gub
$
</pre>
<p>Para comenzar las pruebas, ejecutamos:</p>
<pre class="brush: plain; title: ; notranslate">
$ hg bisect --reset
</pre>
<p>Le indicamos a Mercurial que la revisión tip (o sea, la 34 en nuestro caso, y la actual de la copia de trabajo), es &#8220;bad&#8221;, ya que contiene el bug (o mejor dicho, posee esa característica de la cual queremos saber en qué changeset se introdujo. Digo esto, porque podríamos querer buscar qué changeset solucionó determinado bug, con lo cual la revisión &#8220;bad&#8221; sería la que no tiene el error):</p>
<pre class="brush: plain; title: ; notranslate">
$ hg bisect --bad
$
</pre>
<p>De alguna forma, sabemos que la revisión 10 no tiene el bug, así que la marcamos como &#8220;good&#8221;. En este caso y a los fines del ejemplo saber esto es sencillo, pero digo &#8220;de alguna forma&#8221; porque en la práctica debería ser la revisión más tardía sin el bug, lo cual podría llevarnos un tiempo.</p>
<pre class="brush: plain; title: ; notranslate">
$ hg bisect --good 10
Testing changeset 22:3103b305bc80 (24 changesets remaining, ~4 tests)
0 files updated, 0 files merged, 12 files removed, 0 files unresolved
$
</pre>
<p>Vean que Mercurial nos está diciendo cuántos changesets va a procesar, y la cantidad aproximada de tests que vamos a tener que realizar. Como utiliza búsqueda binaria o dicotómica, la cantidad de comparaciones o pruebas es logarítmica, lo cual obviamente reduce mucho el proceso de búsqueda.</p>
<p>Al ejecutar el comando anterior, la copia de trabajo se actualiza a la revisión 22 ( (34 + 10) / 2 = 22 ). Ahora realizamos el test en esta revisión y le decimos a Mercurial si la misma es &#8220;bad&#8221; o &#8220;good&#8221;:</p>
<pre class="brush: plain; title: ; notranslate">
$ grep 'i have a gub' myfile*
myfile22:i have a gub
$
</pre>
<p>Lo anterior nos indica que es &#8220;bad&#8221;. Claro que esto se puede automatizar tanto como queramos. Podemos crear un script que haga casi todo:</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/bash

if ( grep -q 'i have a gub' myfile* )
then
	result=bad
else
	result=good
fi
echo this revision is $result
hg bisect --$result
</pre>
<p>Lo ejecutamos:</p>
<pre class="brush: plain; title: ; notranslate">
$ ./test.sh
this revision is bad
Testing changeset 16:2deb07b463cf (12 changesets remaining, ~3 tests)
0 files updated, 0 files merged, 6 files removed, 0 files unresolved
$
</pre>
<p>Ahora Mercurial nos sitúa en la revisión 16 ( (10 + 22) / 2 = 16 ). Faltan unos 3 tests aún. Volvemos a correr nuestro script:</p>
<pre class="brush: plain; title: ; notranslate">
$ ./test.sh
this revision is good
Testing changeset 19:dc33070521ae (6 changesets remaining, ~2 tests)
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
</pre>
<p></p>
<pre class="brush: plain; title: ; notranslate">
$ ./test.sh
this revision is good
Testing changeset 20:98953c61831c (3 changesets remaining, ~1 tests)
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
</pre>
<p></p>
<pre class="brush: plain; title: ; notranslate">
$ ./test.sh
this revision is good
Testing changeset 21:d1616a476608 (2 changesets remaining, ~1 tests)
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
</pre>
<p></p>
<pre class="brush: plain; title: ; notranslate">
$ ./test.sh
this revision is good
The first bad revision is:
changeset:   22:3103b305bc80
user:        Milton Pividori &lt;miltondp@gmail.com&gt;
date:        Wed Sep 03 10:53:56 2008 -0300
summary:     buggy changeset
</pre>
<p>La revisión que introdujo el bug que estamos buscando es la 22. Con algún tipo de software que automatice la práctica de &#8220;Integración continua&#8221;, podríamos indicar que seamos notificados cuando alguna revisión o changeset (independientemente del sistema de control de versiones utilizado) no pasa las pruebas o no compila por ejemplo. Esto nos habilitaría a detectar exactamente qué commit introdujo errores o bugs.</p>
<p>Sin embargo, puede pasar que no haya una prueba determinada que me indique que cierta revisión tiene un error, sino que nos demos cuenta de eso más tarde, y nos interese saber en qué changeset se introdujo el mismo para revertirlo (obviamente que esto no es tan sencillo. Habría que estudiar ese changeset para saber dónde está el error). Luego de introducir la prueba de unidad que verifica ese error que estamos buscando, podemos utilizarla para encontrar la revisión que introdujo el problema con algún script y el comando &#8220;bisect&#8221; que vimos anteriormente, automatizando la operación. Luego, en caso de ser los cambios de dicha revisión simples como el ejemplo, podemos revertirlo de esta forma en Mercurial (primero vuelvo a la revisión tip con &#8220;hg update&#8221;):</p>
<pre class="brush: plain; title: ; notranslate">
$ hg update
$ hg backout -m &quot;Elimino el bug&quot; 22
removing myfile22
created new head
changeset 35:37d16077cdac backs out changeset 22:a7281f19f281
the backout changeset is a new head - do not forget to merge
(use &quot;backout --merge&quot; if you want to auto-merge)
</pre>
<p>Ahora hay dos &#8220;heads&#8221; en mi repositorio (un &#8220;head&#8221; es un changeset que no tiene hijos), por lo tanto debemos, como nos está indicando Mercurial, hacer un merge entre ambos (podríamos haber utilizado la opción &#8211;merge del comando backout directamente).</p>
<p>Con el comando &#8220;hg view&#8221; podemos ver esto gráficamente:</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/09/hgview.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/09/hgview.png" alt="" title="hgview" width="500" height="520" class="aligncenter size-full wp-image-287" /></a></p>
<p>Notar que el &#8220;padre&#8221; de la nueva revisión 35 (que soluciona el bug) es el changeset 22. O sea que este cambio no introduce todos los cambios entre ésta revisión y la 34. Por lo tanto debemos hacer, como ya nos había indicado Mercurial, un merge:</p>
<pre class="brush: plain; title: ; notranslate">
$ hg merge
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg status
R myfile22
$ hg commit -m &quot;Merge hecho&quot;
$
</pre>
<p>Otra vez, ejecuto &#8220;hg  view&#8221; para ver todo esto gráficamente:</p>
<p><a href="http://www.miltonpividori.com.ar/wp-content/uploads/2008/09/hgview-mergehecho.png"><img src="http://www.miltonpividori.com.ar/wp-content/uploads/2008/09/hgview-mergehecho.png" alt="" title="hgview-mergehecho" width="500" height="520" class="aligncenter size-full wp-image-290" /></a></p>
<p>Notar que los changeset de la nueva revisión tip 36 son los commits 34 y 35.</p>
<p>Si bien nunca hice estas cosas con Subversion, por lo que me acuerdo de haber leído, en este sistema de control de versiones hacer esto no es tan sencillo. Justamente una de las críticas a Subversion es que es fácil hacer branches, pero difícil fusionarlos.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.miltonpividori.com.ar/2008/09/03/bisecando-con-mercurial-o-encontrando-changesets-con-bugs/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

