Introducción

Esta es la segunda parte de una serie de artículos introductorios al uso de sistemas de control de versiones.
En la primera parte se explican los conceptos generales necesarios para comprender el funcionamiento y la forma de trabajo de un sistema de control de versiones. En esta segunda parte se explica el uso particular de Mercurial, de forma que sea posible realizar con esta herramienta la gestión del código de un proyecto de software.

Mercurial

Mercurial es una aplicación para el control de versiones publicada bajo una licencia libre (GPL). Sus principales características son el carácter distribuido y la gran velocidad de funcionamiento.

La página principal del proyecto contiene abundante información (en inglés) sobre su uso, trucos, además de versiones del programa para su instalación.

Instalación de Mercurial

Existen paquetes binarios para la instalación de Mercurial, tanto para GNU/Linux como para Windows, y esa es la forma recomendada para su instalación.

El instalador de Mercurial para win32 tiene, a 5 de septiembre de 2006, su versión 0.9.1.

Es posible también hacer una instalación desde el código fuente usando:

#python setup.py install

Además del intérprete de python es necesaria la presencia de un compilador de C (gcc) para compilar las extensiones hechas en ese lenguaje.

Es posible comprobar si Mercurial está correctamente instalado en el sistema llamando a la aplicación desde la línea de comandos y comprobando que devuelve información sobre la versión instalada:

$ hg

Mercurial Distributed SCM (version 0.9.1)

Copyright (C) 2005 Matt Mackall
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Personalización del programa

Archivos de configuración

Las personalizaciones para todo el sistema se hacen en ~/.hgrc, o en ~/Mercurial.ini si trabajamos en windows, aunque es posible personalizar el funcionamiento de Mercurial para cada repositorio usando en archivo .hgrc en el directorio de trabajo.

Usuario, editor y nivel de información

Cada envío de cambios al repositorio de un proyecto almacena datos sobre el usuario que realiza el cambio. Para que esa información sea correcta es necesario proporcionar esa información mediante una opción en la línea de comandos (-u username), o, más cómodamente, aportándola en el archivo de configuración, en el apartado username del bloque [ui].

Otro de los datos que se incluye en los cambios es un mensaje que explica el cometido de los cambios. Ese texto se puede aportar en la línea de comandos con la opción -m mensaje, o utilizando un editor para escribir el comentario. El editor que abrirá Mercurial para introducir el texto se configura en el apartado editor del bloque [ui] del archivo de configuración.

Una opción global interesante, para que Mercurial sea un poco más locuaz en su operación, es -v, que puede seleccionarse por defecto en el archivo de configuración mediante el apartado verbose del bloque [ui].


[ui]
# editor por defecto (gvim o el que sea):
editor = gvim
# pedir indicación de archivos cambiados:
verbose=True

# usuario que se usa al indicar quién hace los cambios:
username="Pepito Pérez <pepito@perez.org>"

Reconciliación de cambios

Cuando se desean combinar las distintas versiones de un archivo (merge) es posible utilizar programas que facilitan la reconciliación de los cambios que existen entre ellas. Mercurial hace uso de aplicaciones externas para este cometido, que son habituales en sistemas Unix, pero que han de instalarse separadamente en sistemas Windows. A continuación describimos la configuración e instalación del programa kdiff3 para la reconciliación de cambios en windows:

Kdiff3 dispone de un instalador de su versión 0.9.90 para windows.

Para localizar los cambios entre una versión base (base) y dos versiones que queremos combinar (local, other), Kdiff3 recibe los datos en un órden (base, local, other) distinto al de Mercurial (local, base, other), por lo que es necesario escribir un pequeño script que se encargue de reordenar la información que Mercurial pasa a Kdiff3. Este script, llamado hgmerge.cmd debe tener el siguiente contenido:

...\path\to\kdiff3.exe --auto -L1 Base -L2 Local -L3 Other %2 %1 %3 -o %1

En http://www.selenic.com/mercurial/wiki/index.cgi/MergeProgram se proporciona más información sobre la reconciliación de cambios en Mercurial.

Uso de SSH como protocolo de comunicación

Mercurial usa HTTP como protocolo nativo de comunicación, aunque es posible usar SSH si tenemos un cliente de ssh instalado, tal como OpenSSH y, en algún caso, se personaliza la configuración de Mercurial. Esta configuración se explica en la tercera parte de esta serie de artículos sobre Mercurial. En ésta se explica además cómo acceder a un repositorio remoto usando ssh y claves públicas en lugar de contraseñas.

NOTA: Todas las aplicaciones externas de las que hace uso Mercurial, tal como ssh, vim o kdiff3, deben estar en la ruta por defecto (PATH) del usuario o del sistema para que Mercurial pueda localizarlas

Uso de Mercurial

Antes de explicar más detalles, es necesario señalar que Mercurial tiene su propio sistema de ayuda que nos será de utilidad a la hora de conocer los detalles de cada comando y para localizar el comando adecuado a nuestras necesidades.

En el wiki del proyecto se puede consultar la lista de preguntas frecuentes además de otras informaciones detalladas de instalación, configuración, etc… En sistemas Unix/Linux es posible también usar las páginas del manual.
Las opciones generales y una lista de órdenes básicas se pueden consultar con:

$ hg help

Para obtener ayuda sobre una orden en particular:

$ hg help orden

Creación de un repositorio

La creación de un repositorio de Mercurial consiste en la creación de un directorio con algunos metadatos. La orden init es la responsable de crear los metadatos y el directorio de trabajo:

$ hg init nombre-repositorio

Si se omite el nombre del repositorio, se puede convertir el directorio actual en un repositorio de Mercurial:

$ hg init

Incorporación de archivos al repositorio para rastrear sus cambios

Para que Mercurial rastree los cambios en un archivo que se encuentra en el directorio de trabajo es necesario incorporarlo al repositorio. Para ello se usa la orden add, con el nombre de los archivos como parámetros.

$ hg add nombrearchivo1 nombrearchivo2 ...

Estado del directorio de trabajo

Es posible conocer el estado de los archivos del directorio de trabajo en relación a su seguimiento por Mercurial utilizando la orden status.

$ hg status
? c.txt
M a.txt

La orden status devuelve una lista de archivos precedidos por un caracter indicador de estado. Los más importantes son:

  • M – el archivo contiene modificaciones que no se han registrado en el repositorio
  • A – el archivo está marcado para ser añadido al repositorio en el siguiente envío de cambios o “commit”
  • ? – el archivo no está siendo seguido por Mercurial

Envío de cambios al repositorio

Cuando se realizan modificaciones en los archivos seguidos por Mercurial es posible guardar ese conjunto de cambios (changeset) en el repositorio local utilizando la orden commit.

$ hg commit

Esta orden abre una sesión en el editor de textos que se haya configurado para la introducción de un texto que sirva de aclaración a los cambios guardados. Es posible indicar una cadena de texto en la línea de comandos para su uso en el registro de cambios, sin necesidad de utilizar el editor, y también inidicar un usuario como responsable de los cambios:

$ hg commit -u 'Pepito Pérez <pepito@perez.org>' -m "El propósito de los cambios es blah blah"

Bitácora de cambios

Se puede ver una lista de los conjuntos de cambios que se han ido haciendo a lo largo de la historia de un proyecto.

"$ hg log"
changeset: 2:f27f5477492b1d40d138e087485877659427c23b
tag: v1.0
user: Paco Pérez <pepito@perez.org>
date: Tue Jun 13 22:55:24 2006 +0200
files: a.txt b.txt
description:
El propósito de los cambios es blah blah

changeset: 1:797bf3bff932f8c36c9be4ec323f88fb524239ec
user: Paco Pérez <pepito@perez.org>
date: Tue Jun 13 22:30:52 2006 +0200
files: a.txt
description:
Modificar a.txt

changeset: 0:cb3e6e73d53bab2462e38cedc6fa68eef4e70217
user: “Usuario de prueba <prueba@cielito.sindominio.net>”
date: Tue Jun 13 22:25:17 2006 +0200
files: a.txt b.txt
description:
Guardamos versiones iniciales de los archivos a.txt y b.txt.

En la bitácora de cambios podemos ver los metadatos asociados a cada changeset:

  • changeset: Identificación del conjunto de cambios mediante: ‘número de revisión:changeset ID’. El número de revisión proporciona una referencia válida solamente para cada copia del repositorio, mientras que el changeset ID constituye una referencia absoluta, incluso entre copias en distintas máquinas.
  • user: identificación del usuario bajo el que se registra el conjunto de cambios
  • date: fecha, hora y zona horaria en la que se registró el conjunto de cambios
  • files: archivos implicados en el conjunto de cambios
  • description: texto descriptivo de los cambios

Tras esta serie de conjuntos de cambios la historia del proyecto sería algo similar a:

Commit de Mercurial

y el dirstate, o changeset padre del directorio de trabajo se encuentra en la revisión 2, la señalada en rojo en el diagrama.

Recuperación de revisiones

Podemos recuperar el estado del directorio tal como estaba tras una revisión determinada. Esta operación, llamada actualización del repositorio, permite recorrer la historia del proyecto y resulta útil para poder ver el estado de los distintos archivos en una revisión determinada, ver los cambios hechos tras importar algunos cambios desde un repositorio externo, o para situarse en un punto diferente del proyecto para crear una nueva rama a partir de él.

La orden que nos permite realizar la actualización de un repositorio es update.

$ hg update revision

Update toma como parámetro revisión el changeset al que se desea actualizar. Es posible indicar dicho changeset mediante el número de revisión, un ‘tag’, o con el changeset ID. Mercurial es capaz de reconocer un changeset ID si se le pasa una parte inequívoca de la cadena alfanumérica que lo define, sin necesidad de indicar la cadena completa.

En el ejemplo anterior, si realizamos las siguientes operaciones:

$ hg update 797b

ó

$ hg update 1

cambiaríamos la revisión que se visualiza en el directorio de trabajo a la revisión 1:797bf3bff932f8c36c9be4ec323f88fb524239ec. En la historia del proyecto, nos situaríamos en el estado del proyecto tras el envío del segundo conjunto de cambios:

Commit de Mercurial

Si se omite el parámetro de revisión en la orden update, entonces se presupone la revisión ‘tip’ (el último conjunto de cambios guardado).

En nuestro ejemplo,

$ hg update

nos llevaría de nuevo a la última revisión del proyecto:

Mercurial - update a tip

Visualización de diferencias entre revisiones

Se pueden ver las diferencias entre dos versiones:

$ hg diff -r version1 -r versión2

ó

$ hg diff -r version1:version2

, entre una versión y la versión del directorio de trabajo:

$ hg -r version1

, o entre el changeset padre del directorio de trabajo y los cambios en el directorio de trabajo:

$ hg diff

Las versiones, como en el resto de órdenes de Mercurial, se pueden indicar con el número de revisión, el Changeset ID o un tag.

Copia de repositorios y ramas (branches)

Se puede clonar un repositorio, de manera que sea posible recuperar datos de su “original” para integrar los cambios en uno u otro sentido. La orden clone es la usada para este cometido.
Esta operación es muy habitual, puesto que permite la creación de repositorios para realizar desarrollos paralelos que pueden integrarse posteriormente en el repositorio original, trasladar cambios entre uno u otro, o mantener permanentemente versiones con cometidos diferenciados. Una forma de uso frecuente es el desarrollo de funcionalidades en ramas separadas, para integrarlas en el repositorio principal una vez que la implementación de los cambios ha madurado.

La orden

$ hg clone repositorio-original repositorio-copiado

clona el repositorio ‘repositorio-original‘, haciendo una copia llamada ‘repositorio-copiado‘.

La historia de ambos proyectos se mantiene igual,
Mercurial - clonar ramas
y, además, el repositorio copiado guarda la ruta al repositorio original (default path o ruta por defecto). Enn algunas operaciones de traslado de información entre repositorios, si se omite la ruta de trabajo, se utiliza la ruta por defecto. En el siguiente apartado se presentan algunas órdenes donde esta funcionalidad resulta cómoda.

NOTA: Para diferenciar dos repositorios relacionados en nuestros ejemplos diferenciaremos sus números de revisión mediante un apóstrofe. Hemos de recordar que estos números de revisión son propios de cada repositorio, ya que simplemente indican el orden en el que se almacenó un changeset en la historia de ese repositorio. Sin embargo, dos changeset idénticos (de idéntica historia y contenidos) tienen el mismo changeset ID, aunque difieran en sus números de revisión.

Traslado de información entre repositorios (push y pull)

Se pueden trasladar las modificaciones entre repositorios mediante las órdenes push y pull.
Push integra en un repositorio remoto los conjuntos de cambios del repositorio actual que no se encuentren en él, mientras que pull realiza la operación inversa, integra en el repositorio local los cambios adicionales que contenga el repositorio remoto.
En ambas operaciones es neceario indicar la dirección o URL de destino (push) u origen (pull) de la operación.

$ hg push repositorio-destino

ó

$ hg pull repositorio-origen

Es preciso advertir que estas operaciones simplemente trasladan los cambios entre repositorios, pero no alteran el estado del directorio de trabajo. Si se actualizar el directorio de trabajo al último changeset es probable que se quiera hacer después traer cambios de otro repositorio:

$ hg update

que actualiza a tip.

En nuestros repositorios de ejemplo, si se hubiesen guardado cambios distintos en cada uno de ellos, tendríamos unos nuevos changeset 3′ y 3, el dirstate de cada uno de los repositorios se correspondería a estos nuevos changeset, y la historia de ambos repositorios quedaría así:

Mercurial - push y pull - estado inicial

Se puede apreciar cómo las tres primeras revisiones comparten su changeset ID (abreviado en el dibujo por comodidad), puesto que son conjuntos de cambios idénticos, mientras que el nuevo changeset de cada repositorio, a pesar de compartir el mismo número de revisión (3), tiene un changeset ID diferente. Esto se debe a que no son cambios idénticos.

Si trabajamos desde el repositorio B, cuyo default path apunta al repositorio desde el que fue clonado (el A), podemos traer los cambios de A hasta B simplemente usando la orden pull, y aprovechando el default path. También es posible trabajar desde A y llevar los cambios a B con la orden push e indicando la ruta a B (puesto que A no tiene un default path que apunte a B):

$ hg pull

ó

$ hg push /ruta/a/repoB

El gráfico que representa la historia de ambos proyectos quedaría así:

Mercurial - pull de A a B

En el diagrama se observa que el conjunto de cambios 3′:e48f de A se traslada a B como el changeset de número de revisión 4, manteniendo su changeset ID e48f….

Como consecuencia de la operación que hemos realizado aparece una nueva cabeza de desarrollo en el repositorio B, coincidente con el changeset 4, al compartir las revisiones 3 y 4 el mismo padre 2.

Otro resultado es que la marca tip en B pasa a referenciar al changeset 4, mientras que el dirstate en B no se modifica (representado en rojo). Es decir, no se aprecian cambios en el directorio de trabajo, mientras que la revisión tip, que antes coincidía con el número de revisión 3, pasa ahora al changeset con número de revisión 4, que es el añadido en último lugar.

Si deseásemos cambiar a la nueva cabeza, podríamos hacer simplemente:

$ hg update

ó

$ hg update 4

ó

$ hg update e48f

La primera opción nos actualiza a tip, mientras que en las dos siguientes se especifica explícitamente la revisión o el changeset ID. El resultado final es que el repositorio queda en el siguiente estado:
Mercurial - actualizar a tip en la cabeza nueva
y que haría que viésemos en el directorio de trabajo el estado del proyecto tal como se encuentra en la nueva revisión 4 del repositorio B (o la 3′ del repositorio A).

Visualización de las distintas cabezas de un proyecto

Cuando integramos los cambios de distintos repositorios mediante push o pull, hemos visto que es probable que se produzcan desarrollos paralelos que den lugar a distintas ramas de desarrollo en el proyecto.

Para localizar las distintas cabezas existentes en el repositorio utilizamos la orden heads:

$ hg heads
changeset: 3:c22f5477492b1d40d138e087485877659427c23b
tag: v1.0
user: Paco Pérez <pacoperez@susitio.com>
date: Tue Jun 23 22:55:24 2006 +0200
files: a.txt b.txt
description:
Cambios preparados en el repositorio B para…

changeset: 4:348ff3bff932f8c36c9be4ec323f88fb624239ec
user: Paco Pérez <pacoperez@susitio.com>
date: Tue Jun 23 22:36:52 2006 +0200
files: a.txt
description:
Cambios preparados en el repositorio A para…

, que nos muestra los changeset que son cabeza de una rama, y refleja las dos cabezas de nuestro ejemplo. En él acabábamos con dos cabezas (números de revisión 3 y 4) tras traer algunos cambios del repositorio A al repositorio B, por haberse producido desarrollos paralelos en ellos:

Mercurial - pull de A a B

Los changeset 3 y 4 definen dos ramas de desarrollo en el repositorio que se bifurcan en el changeset 2.

Integración de ramas divergentes (merging)

A menudo no se pretende que las ramas que se producen en un proyecto permanezcan como desarrollos paralelos de forma indefinida. Para reintegrar los cambios de una rama en otra rama es preciso realizar los siguientes pasos:

  • Indicar la revisión que se desea integrar con el directorio de trabajo mediante la orden merge.
  • Reconciliar los cambios entre las ramas haciendo los cambios necesarios (normalmente con la ayuda de un programa al efecto, por ejemplo, kdiff3, o con nuestro editor preferido).
  • Guardar el resultado con una operación de commit, en un nuevo cambio llamado merge changeset o changeset de mezcla.

La orden merge requiere como parámetro el changeset que define la revisión que queremos integrar en la rama actual del directorio de trabajo.

En nuestro ejemplo, para integrar (o mezclar) la rama con número de revisión 3 en la rama de nuestro directorio de trabajo (la 4, ya que la última vez cambiamos el dirstate a la revisión 4 mediante una operación de update) debemos realizar los siguientes pasos:

Indicamos que queremos mezclar la rama 3:

$ hg merge 3

Merge entre changeset 3 y 4

Hacemos los cambios necesarios para reconciliar los cambios al código en ambas ramas…

y hacemos un commit de mezcla:

$ hg commit -m "Merge desde la rama 3"

Merge changeset

Tras la mezcla solamente nos resta una cabeza, la correspondiente al changeset de mezcla, el 5, y que habrá de reflejarse en la salida de la orden heads:

$ hg heads
changeset: 5:676bf3bff932f8c36c9be4ec323f88fb624239ec
user: Paco Pérez <pacoperez@susitio.com>
date: Mon Jun 29 12:16:52 2006 +0200
files: a.txt b.txt
description:
Merge desde la rama 3

La etapa intermedia de reconciliación de cambios solamente puede automatizarse parcialmente. Mercurial lanza una aplicación auxiliar para facilitar ese trabajo. La aplicación utilizada es configurable, auque se recomienda el uso de kdiff3, meld o vimdiff.
De todos modos, siempre se deben supervisar los cambios hechos, puesto que el significado preciso de la integración de dos ramas es una cuestión semántica que no siempre puede coincidir con la mezcla por comparación que realizan estas herramientas. Estas permiten, sin embargo, localizar las secciones de código que entran en conflicto (por modificar las mismas zonas del proyecto) y precisan de edición manual, y además realizan una mezcla automática en las secciones en las que no se producen conflictos entre las dos revisiones implicadas, haciendo uso de la información adicional que supone saber cuál es su ancestro común (el changeset en donde se produce la ramificación).

Organización de los repositorios

Una manera bastante práctica para organizar los repositorios de un proyecto es la siguiente:

Jerarquía de repositorios en Mercurial

En esta organización podemos observar los siguientes elementos:

  • Un repositorio personal para cada desarrollador en el que cada uno sube su versión “pública” del proyecto. En el diagrama inferior se identifican como repositorios A, B, C o D. Fundamentalmente sirve como backup del trabajo personal y también para que los demás puedan ver los cambios sobre los que está trabajando cada uno. Desde él se suben (push) los cambios al repositorio de integración, al tiempo que sigue los cambios en el repositorio de integración (con pull) para realizar mezclas limpias.
  • Un repositorio de integración de cambios (crew) al que se llevan los cambios propuestos por los desarrolladores para la versión estable y desde el que se suben (push) los cambios al repositorio principal.
  • El repositorio principal, “canónico” (main), que sirve de referencia pública del proyecto. Recoge los cambios “contrastados” del repositorio de integración.

Los repositorios en las partes superiores del diagrama toman como referencia los repositorios en las zonas inferiores, y van integrando los cambios que se producen en ellos mediante operaciones pull. De esa manera, el código está cada vez más auditado a medida que se avanza en el proceso.

Estos repositorios se encuentran publicados en un servidor (o varios), pero lo más habitual es que los denominados repositorios personales sean a su vez repositorios de integración de otros repositorios locales en los que se hace el desarrollo efectivo. Así, cada desarrollador trabaja en sus repositorios locales sobre nuevas funcionalidades, corrección de errores, etc, y va actualizando (push) los cambios consolidados a su repositorio público de usuario.

Cuando una nueva funcionalidad del repositorio público personal está lista para formar parte de la siguiente versión estable se pasa (push) desde cada uno de los repositorios personales al repositorio de integración (crew), donde se va probando, y pasa a ser la base sobre la que trabajan los desarrolladores (se actualizan desde él). Es la versión en desarrollo “en pruebas”.

En un momento dado se decide lanzar una nueva versión “estable”, se corrigen solamente fallos en la versión de pruebas(crew), y, finalmente, se actualiza con ella el repositorio “estable” (main).

Ejemplo de uso en el proyecto Pascaline

Se han organizado los repositorios publicados en el servidor así:

  • un repositorio principal (main)
  • un repositorio de integración de cambios (crew)
  • tres repositorios personales (coya, ramon, pachi)

Cada uno trabaja sobre ramas locales que exporta a su repositorio personal y va integrando los cambios que se van generando en el repositorio de integración de cambios, para seguir el desarrollo que vayan haciendo los demás y poder integrar limpiamente los cambios propios en él sin generar nuevas ramas (cabezas) en dicho repositorio.

Se puede clonar el repositorio main así:

$ hg clone http://hg.rvburke.com/pascaline/main/ pascaline-main

el repositorio crew así:

$ hg clone http://hg.rvburke.com/pascaline/crew/ pascaline-crew

y el mío (pachi, o ramon, o coya):

$ hg clone http://hg.rvburke.com/pascaline/pachi/ pascaline-pachi

esto genera en nuestro sistema de archivos los directorios: pascaline-main, pascaline-crew y pascaline-pachi, que son tres repositorios de Mercurial.

para ir actualizándolo con los cambios que se vayan subiendo, simplemente se hace (dentro del directorio pascaline-main, pascaline-crew o pascaline-pachi):

$ hg pull
$ hg update

El primero trae los cambios remotos que no se encuentren ya en nuestra copia del repositorio y los guarda en el almacén de conjuntos de cambios, mientras que el segundo actualiza el estado del directorio al último cambio (‘tip’, por defecto).
hg pull no necesita aquí que se le indique el repositorio de origen porque, al clonarlo, almacena la referencia a la situación del repositorio de referencia (su dirección o su ruta en el sistema de archivos).

Uno puede trabajar en el proyecto de forma más segura haciendo otra copia local, y dejando esos repositorios como copias “limpias” del repositorio publicado en el servidor:

$ hg clone pascaline-pachi pascaline-pachi-para-trastear

Cambiamos algo y vamos guardando los pasos que queramos a medida que avanzamos en el desarrollo:

$ hg commit -m "He añadido una cosa a lo de pachi"

Esta orden (dentro de pascaline-pachi-para-trastear) guarda los cambios hechos como un nuevo changeset, por ejemplo, el 199.
(Podemos ver con hg log cuál es el último).

Para integrar los cambios en otras copias del proyecto podemos optar por hacer un parche de cada conjunto de cambios:

$ hg diff -r 199 > parche199.diff

o bien:

$ hg export 199 > parche199.mercurial

Esta última opción, export, genera más información útil para Mercurial que un simple parche con diff, y se puede integrar en otro repositorio con

$ hg import parche199.mercurial

O bien exportar a un archivo el lote cambios que no existe en el repositorio de destino. Las ordenes bundle y unbundle permiten generar e integrar esos archivos:

$ hg bundle cambios.bundle path/a/repo-destino

y (en el directorio del repositorio de destino):

$ hg unbundle cambios.bundle

Pero la forma más práctica y potente de trasladar los cambios es con push y pull.

Desde pascaline-pachi podemos traer los cambios desde pascaline-pachi-para-trastear así:

$ hg pull pascaline-pachi-para-trastear

o, desde pascaline-pachi-para-trastear, podemos llevar los cambios a pascaline-pachi:

$ hg push pascaline-pachi

en pascaline-pachi actualizamos a los últimos cambios:

$ hg update

y podemos subir los cambios al repositorio en el servidor de la misma manera, con push:

$ hg push http://hg.rvburke.com/pascaline/pachi/

ó, al usar la dirección por defecto (desde la que hemos clonado pascaline-pachi),

$ hg push

Los cambios que tenemos en el repositorio local deberían aparecer ahora en el repositorio publicado en el servidor.
El proceso es el mismo para trasladar cambios entre los directorios personales y crew, entre crew y main o entre cualesquiera otros repositorios.

…y en el próximo capítulo…

La próxima parte de esta serie de artículos tratará sobre la configuración del servidor para la publicación de repositorios, así como la configuración del acceso con ssh y claves públicas.