
jerojasro@381: \chapter{Una gira de Mercurial: fusionar trabajo}
jerojasro@336: \label{chap:tour-merge}
jerojasro@336: 
jerojasro@383: Hasta ahora hemos cubierto cómo clonar un repositorio, hacer cambios,
jerojasro@383: y jalar o empujar dichos cambios de un repositorio a otro. Nuestro
jerojasro@383: siguiente paso es \emph{fusionar} cambios de repositorios separados.
jerojasro@383: 
jerojasro@383: % TODO cambié streams por líneas. check please
jerojasro@383: \section{Fusionar líneas de trabajo}
jerojasro@383: 
jerojasro@383: Fusionar es una parte fundamental de trabajar con una herramienta 
jerojasro@383: de control distribuido de versiones.
jerojasro@336: \begin{itemize}
jerojasro@383: \item Alicia y Roberto tienen cada uno una copia personal del
jerojasro@383:     repositorio de un proyecto en el que están trabajando. Alicia
jerojasro@383:     arregla un fallo en su repositorio; Roberto añade una nueva
jerojasro@383:     característica en el suyo. Ambos desean que el repositorio
jerojasro@383:     compartido contenga el arreglo del fallo y la nueva
jerojasro@383:     característica.
jerojasro@383: \item Frecuentemente trabajo en varias tareas diferentes en un mismo
jerojasro@383:     proyecto al mismo tiempo, cada una aislada convenientemente de las
jerojasro@383:     otras en su propio repositorio. Trabajar de esta manera significa
jerojasro@383:     que a menudo debo fusionar una parte de mi propio trabajo con
jerojasro@383:     otra.
jerojasro@336: \end{itemize}
jerojasro@336: 
jerojasro@383: Como fusionar es una operación tan necesaria y común, Mercurial la
jerojasro@383: facilita. Revisemos el proceso. Empezaremos clonando (otro)
jerojasro@383: % TODO poner interrogante de apertura
jerojasro@383: repositorio (ve lo seguido que aparecen?) y haciendo un cambio en él.
jerojasro@336: \interaction{tour.merge.clone}
jerojasro@383: Ahora deberíamos tener dos copias de \filename{hello.c} con contenidos
jerojasro@383: diferentes.  El historial de los dos repositorios diverge ahora, como
jerojasro@383: se ilustra en la figura~\ref{fig:tour-merge:sep-repos}.
jerojasro@336: \interaction{tour.merge.cat}
jerojasro@336: 
jerojasro@336: \begin{figure}[ht]
jerojasro@336:   \centering
jerojasro@336:   \grafix{tour-merge-sep-repos}
jerojasro@383:   \caption{Historial reciente divergente de los repositorios
jerojasro@383:       \dirname{my-hello} y \dirname{my-new-hello}}
jerojasro@336:   \label{fig:tour-merge:sep-repos}
jerojasro@336: \end{figure}
jerojasro@336: 
jerojasro@383: Ya sabemos que jalar los cambios desde nuestro repositorio
jerojasro@383: \dirname{my-hello} no tendrá efecto en el directorio de trabajo.
jerojasro@336: \interaction{tour.merge.pull}
jerojasro@384: Sin embargo, el comando \hgcmd{pull} dice algo acerca de
jerojasro@384: ``frentes''\ndt{El autor se refiere a \emph{heads} aquí.}.  
jerojasro@384: 
jerojasro@384: \subsection{Conjuntos de cambios de frentes}
jerojasro@384: 
jerojasro@384: Un frente es un cambio que no tiene descendientes, o hijos, como
jerojasro@384: también se les conoce. La revisión de punta es, por tanto, un frente,
jerojasro@384: porque la revisión más reciente en un repositorio no tiene ningún
jerojasro@384: % TODO cambio en la redacción de la frase, pero espero que conserve el
jerojasro@384: % sentido. Querido human@, apruebe o corrija :D
jerojasro@384: hijo. Sin embargo, un repositorio puede contener más de un frente.
jerojasro@336: 
jerojasro@336: \begin{figure}[ht]
jerojasro@336:   \centering
jerojasro@336:   \grafix{tour-merge-pull}
jerojasro@384:   \caption{Contenidos del repositorio después de jalar
jerojasro@384:       \dirname{my-hello} a \dirname{my-new-hello}}
jerojasro@336:   \label{fig:tour-merge:pull}
jerojasro@336: \end{figure}
jerojasro@336: 
jerojasro@384: En la figura~\ref{fig:tour-merge:pull} usted puede ver el efecto que
jerojasro@384: tiene jalar los cambios de \dirname{my-hello} a \dirname{my-new-hello}.
jerojasro@384: El historial que ya existía en \dirname{my-new-hello} se mantiene
jerojasro@384: intacto, pero fue añadida una nueva revisión. Refiriéndonos a la
jerojasro@384: figura~\ref{fig:tour-merge:sep-repos}, podemos ver que el \emph{ID del
jerojasro@384: conjunto de cambios} se mantiene igual en el nuevo repositorio, pero
jerojasro@384: el \emph{número de revisión} ha cambiado.  (Incidentalmente, éste es un
jerojasro@384: buen ejemplo de porqué no es seguro usar números de revisión cuando se
jerojasro@384: habla de conjuntos de cambios).  Podemos ver los frentes en un
jerojasro@384: repositorio usando el comando \hgcmd{heads}\ndt{Frentes.}.
jerojasro@336: \interaction{tour.merge.heads}
jerojasro@336: 
jerojasro@385: \subsection{Hacer la fusión}
jerojasro@385: 
jerojasro@385: % TODO poner interrogante de apertura
jerojasro@385: Qué pasa si tratamos de usar el comando usual, \hgcmd{update}, para
jerojasro@385: actualizar el nuevo frente?
jerojasro@336: \interaction{tour.merge.update}
jerojasro@385: Mercurial nos indica que el comando \hgcmd{update} no hará la fusión;
jerojasro@385: no actualizará el directorio de trabajo cuando considera que lo que
jerojasro@385: deseamos hacer es una fusión, a menos que lo obliguemos a hacerlo.
jerojasro@385: En vez de \hgcmd{update}, usamos el comando \hgcmd{merge} para hacer
jerojasro@385: la fusión entre los dos frentes.
jerojasro@336: \interaction{tour.merge.merge}
jerojasro@336: 
jerojasro@336: \begin{figure}[ht]
jerojasro@336:   \centering
jerojasro@336:   \grafix{tour-merge-merge}
jerojasro@385:   \caption{Directorio de trabajo y repositorio durante la fusión, y
jerojasro@385:   consignación consecuente}
jerojasro@336:   \label{fig:tour-merge:merge}
jerojasro@336: \end{figure}
jerojasro@336: 
jerojasro@385: Esto actualiza el directorio de trabajo, de tal forma que contenga los
jerojasro@385: cambios de \emph{ambos} frentes, lo que se ve reflejado tanto en la
jerojasro@385: salida de \hgcmd{parents} como en los contenidos de \filename{hello.c}.
jerojasro@336: \interaction{tour.merge.parents}
jerojasro@336: 
jerojasro@385: \subsection{Consignar los resultados de la fusión}
jerojasro@336: 
jerojasro@390: Siempre que hacemos una fusión, \hgcmd{parents} mostrará dos padres
jerojasro@390: hasta que consignemos (\hgcmd{commit}) los resultados de la fusión.
jerojasro@336: \interaction{tour.merge.commit}
jerojasro@390: Ahora tenemos una nueva revisión de punta; note que tiene \emph{los
jerojasro@390: dos} frentes anteriores como sus padres. Estos son las mismas
jerojasro@390: revisiones que mostró previamente el comando \hgcmd{parents}.
jerojasro@336: \interaction{tour.merge.tip}
jerojasro@390: En la figura~\ref{fig:tour-merge:merge} usted puede apreciar una
jerojasro@390: representación de lo que pasa en el directorio de trabajo durante la
jerojasro@390: fusión cuando se hace la consignación. Durante la fusión, el
jerojasro@390: directorio de trabajo tiene dos conjuntos de cambios como sus padres,
jerojasro@390: y éstos se vuelven los padres del nuevo conjunto de cambios.
jerojasro@390: 
jerojasro@390: \section{Fusionar cambios con conflictos}
jerojasro@390: 
jerojasro@390: La mayoría de las fusiones son algo simple, pero a veces usted se
jerojasro@390: encontrará fusionando cambios donde más de uno de ellos afecta las
jerojasro@390: mismas secciones de los mismos ficheros. A menos que ambas
jerojasro@390: modificaciones sean idénticas, el resultado es un \emph{conflicto}, en
jerojasro@390: donde usted debe decidir cómo reconciliar ambos cambios y producir un
jerojasro@390: resultado coherente.
jerojasro@336: 
jerojasro@336: \begin{figure}[ht]
jerojasro@336:   \centering
jerojasro@336:   \grafix{tour-merge-conflict}
jerojasro@390:   \caption{Cambios con conflictos a un documento}
jerojasro@336:   \label{fig:tour-merge:conflict}
jerojasro@336: \end{figure}
jerojasro@336: 
jerojasro@390: La figura~\ref{fig:tour-merge:conflict} ilustra un ejemplo con dos
jerojasro@390: cambios generando conflictos en un documento. Empezamos con una sola
jerojasro@390: versión de el fichero; luego hicimos algunos cambios; mientras tanto,
jerojasro@390: alguien más  hizo cambios diferentes en el mismo texto. Lo que debemos
jerojasro@390: hacer para resolver el conflicto causado por ambos cambios es decidir
jerojasro@390: cómo debe quedar finalmente el fichero.
jerojasro@390: 
jerojasro@390: Mercurial no tiene ninguna utilidad integrada para manejar conflictos.
jerojasro@390: En vez de eso, ejecuta un programa externo llamado \command{hgmerge}.
jerojasro@390: Es un guión de línea de comandos que es instalado junto con Mercurial;
jerojasro@390: usted puede modificarlo para que se comporte como usted lo desee. Por
jerojasro@390: defecto, lo que hace es tratar de encontrar una de varias herramientas
jerojasro@390: para fusionar que es probable que estén instaladas en su sistema.
jerojasro@390: Primero se intenta con unas herramientas para fusionar cambios
jerojasro@390: automáticamente; si esto no tiene éxito (porque la fusión demanda
jerojasro@390: una guía humana) o dichas herramientas no están presentes, el guión
jerojasro@390: intenta con herramientas gráficas para fusionar.
jerojasro@390: 
jerojasro@390: También es posible hacer que Mercurial ejecute otro programa o guión
jerojasro@390: en vez de \command{hgmerge}, definiendo la variable de entorno
jerojasro@390: \envar{HGMERGE} con el nombre del programa de su preferencia.
jerojasro@390: 
jerojasro@390: \subsection{Usar una herramienta gráfica para fusión}
jerojasro@390: 
jerojasro@390: Mi herramienta favorita para hacer fusiones es \command{kdiff3}, y la
jerojasro@390: usaré para describir las características comunes de las herramientas
jerojasro@390: gráficas para hacer fusiones. Puede ver una captura de pantalla de
jerojasro@390: \command{kdiff3} ejecutándose, en la
jerojasro@390: figura~\ref{fig:tour-merge:kdiff3}.  El tipo de fusión que la
jerojasro@390: herramienta hace se conoce como \emph{fusión de tres vías}, porque hay
jerojasro@390: tres versiones diferentes del archivo en que estamos interesados.
jerojasro@390: Debido a esto la herramienta divide la parte superior de la ventana en
jerojasro@390: tres paneles.
jerojasro@336: \begin{itemize}
jerojasro@390: \item A la izquierda está la revisión \emph{base} del fichero, p.ej.~la
jerojasro@390:     versión más reciente de la que descienden las dos versiones que
jerojasro@390:     estamos tratando de fusionar.
jerojasro@390: \item En la mitad está ``nuestra'' versión del fichero, con las
jerojasro@390:     modificaciones que hemos hecho.
jerojasro@390: \item A la derecha está la versión del fichero de ``ellos'', la que
jerojasro@390:     forma parte del conjunto de cambios que estamos tratando de
jerojasro@390:     fusionar.
jerojasro@336: \end{itemize}
jerojasro@390: En el panel inferior se encuentra el \emph{resultado} actual de la
jerojasro@390: fusión. Nuestra tarea es reemplazar todo el texto rojo, que muestra
jerojasro@390: los conflictos sin resolver, con una fusión adecuada de ``nuestra''
jerojasro@390: versión del fichero y la de ``ellos''.
jerojasro@390: 
jerojasro@390: Los cuatro paneles están \emph{enlazados}; si avanzamos vertical o
jerojasro@390: horizontalmente en cualquiera de ellos, los otros son actualizados
jerojasro@390: para mostrar las secciones correspondientes del fichero que tengan
jerojasro@390: asociado.
jerojasro@390: 
jerojasro@390: \begin{figure}[ht]
jerojasro@390:   \centering
jerojasro@390:   \grafix[width=\textwidth]{kdiff3}
jerojasro@390:   \caption{Usando \command{kdiff3} para fusionar versiones de un
jerojasro@390:   fichero}
jerojasro@336:   \label{fig:tour-merge:kdiff3}
jerojasro@336: \end{figure}
jerojasro@336: 
jerojasro@390: En cada conflicto del fichero podemos escoger resolverlo usando
jerojasro@390: cualquier combinación del texto de la revisión base, la nuestra, o la
jerojasro@390: de ellos. También podemos editar manualmente el fichero en que queda
jerojasro@390: la fusión, si es necesario hacer cambios adicionales.
jerojasro@390: 
jerojasro@390: Hay \emph{muchas} herramientas para fusionar ficheros disponibles. Se
jerojasro@390: diferencian en las plataformas para las que están disponibles, y en
jerojasro@390: sus fortalezas y debilidades particulares. La mayoría están afinadas
jerojasro@390: para fusionar texto plano, mientras que otras están pensadas para
jerojasro@390: formatos de archivos especializados (generalmente XML).
jerojasro@336: 
jerojasro@336: \subsection{A worked example}
jerojasro@336: 
jerojasro@336: In this example, we will reproduce the file modification history of
jerojasro@336: figure~\ref{fig:tour-merge:conflict} above.  Let's begin by creating a
jerojasro@336: repository with a base version of our document.
jerojasro@336: \interaction{tour-merge-conflict.wife}
jerojasro@336: We'll clone the repository and make a change to the file.
jerojasro@336: \interaction{tour-merge-conflict.cousin}
jerojasro@336: And another clone, to simulate someone else making a change to the
jerojasro@336: file.  (This hints at the idea that it's not all that unusual to merge
jerojasro@336: with yourself when you isolate tasks in separate repositories, and
jerojasro@336: indeed to find and resolve conflicts while doing so.)
jerojasro@336: \interaction{tour-merge-conflict.son}
jerojasro@336: Having created two different versions of the file, we'll set up an
jerojasro@336: environment suitable for running our merge.
jerojasro@336: \interaction{tour-merge-conflict.pull}
jerojasro@336: 
jerojasro@336: In this example, I won't use Mercurial's normal \command{hgmerge}
jerojasro@336: program to do the merge, because it would drop my nice automated
jerojasro@336: example-running tool into a graphical user interface.  Instead, I'll
jerojasro@336: set \envar{HGMERGE} to tell Mercurial to use the non-interactive
jerojasro@336: \command{merge} command.  This is bundled with many Unix-like systems.
jerojasro@336: If you're following this example on your computer, don't bother
jerojasro@336: setting \envar{HGMERGE}.
jerojasro@336: \interaction{tour-merge-conflict.merge}
jerojasro@336: Because \command{merge} can't resolve the conflicting changes, it
jerojasro@336: leaves \emph{merge markers} inside the file that has conflicts,
jerojasro@336: indicating which lines have conflicts, and whether they came from our
jerojasro@336: version of the file or theirs.
jerojasro@336: 
jerojasro@336: Mercurial can tell from the way \command{merge} exits that it wasn't
jerojasro@336: able to merge successfully, so it tells us what commands we'll need to
jerojasro@336: run if we want to redo the merging operation.  This could be useful
jerojasro@336: if, for example, we were running a graphical merge tool and quit
jerojasro@336: because we were confused or realised we had made a mistake.
jerojasro@336: 
jerojasro@336: If automatic or manual merges fail, there's nothing to prevent us from
jerojasro@336: ``fixing up'' the affected files ourselves, and committing the results
jerojasro@336: of our merge:
jerojasro@336: \interaction{tour-merge-conflict.commit}
jerojasro@336: 
jerojasro@336: \section{Simplifying the pull-merge-commit sequence}
jerojasro@336: \label{sec:tour-merge:fetch}
jerojasro@336: 
jerojasro@336: The process of merging changes as outlined above is straightforward,
jerojasro@336: but requires running three commands in sequence.
jerojasro@336: \begin{codesample2}
jerojasro@336:   hg pull
jerojasro@336:   hg merge
jerojasro@336:   hg commit -m 'Merged remote changes'
jerojasro@336: \end{codesample2}
jerojasro@336: In the case of the final commit, you also need to enter a commit
jerojasro@336: message, which is almost always going to be a piece of uninteresting
jerojasro@336: ``boilerplate'' text.
jerojasro@336: 
jerojasro@336: It would be nice to reduce the number of steps needed, if this were
jerojasro@336: possible.  Indeed, Mercurial is distributed with an extension called
jerojasro@336: \hgext{fetch} that does just this.
jerojasro@336: 
jerojasro@336: Mercurial provides a flexible extension mechanism that lets people
jerojasro@336: extend its functionality, while keeping the core of Mercurial small
jerojasro@336: and easy to deal with.  Some extensions add new commands that you can
jerojasro@336: use from the command line, while others work ``behind the scenes,''
jerojasro@336: for example adding capabilities to the server.
jerojasro@336: 
jerojasro@336: The \hgext{fetch} extension adds a new command called, not
jerojasro@336: surprisingly, \hgcmd{fetch}.  This extension acts as a combination of
jerojasro@336: \hgcmd{pull}, \hgcmd{update} and \hgcmd{merge}.  It begins by pulling
jerojasro@336: changes from another repository into the current repository.  If it
jerojasro@336: finds that the changes added a new head to the repository, it begins a
jerojasro@336: merge, then commits the result of the merge with an
jerojasro@336: automatically-generated commit message.  If no new heads were added,
jerojasro@336: it updates the working directory to the new tip changeset.
jerojasro@336: 
jerojasro@336: Enabling the \hgext{fetch} extension is easy.  Edit your
jerojasro@336: \sfilename{.hgrc}, and either go to the \rcsection{extensions} section
jerojasro@336: or create an \rcsection{extensions} section.  Then add a line that
jerojasro@336: simply reads ``\Verb+fetch +''.
jerojasro@336: \begin{codesample2}
jerojasro@336:   [extensions]
jerojasro@336:   fetch =
jerojasro@336: \end{codesample2}
jerojasro@336: (Normally, on the right-hand side of the ``\texttt{=}'' would appear
jerojasro@336: the location of the extension, but since the \hgext{fetch} extension
jerojasro@336: is in the standard distribution, Mercurial knows where to search for
jerojasro@336: it.)
jerojasro@336: 
jerojasro@336: %%% Local Variables: 
jerojasro@336: %%% mode: latex
jerojasro@336: %%% TeX-master: "00book"
jerojasro@336: %%% End: 




