igor@345: \chapter{Mercurial día a día} igor@345: \label{chap:daily} igor@345: igor@345: \section{Cómo indicarle a Mercurial qué archivos seguir} igor@345: igor@345: Mercurial no trabaja con archivos en su repositorio a menos que usted igor@345: explícitamente se lo indique. La orden \hgcmd{status} le mostrará igor@345: cuáles archivos son desconocidos para Mercurial; emplea un igor@345: ``\texttt{?}'' para mostrar tales archivos. igor@345: igor@345: Para indicarle a Mercurial que tenga en cuenta un archivo, emplee la igor@345: orden \hgcmd{add}. Una vez que haya adicionado el archivo, la línea igor@345: referente al archivo al aplicar la orden \hgcmd{status} para tal igor@345: archivo cambia de ``\texttt{?}'' a ``\texttt{A}''. igor@345: \interaction{daily.files.add} igor@345: igor@345: Después de invocar \hgcmd{commit}, los archivos que haya adicionado igor@345: antes de consignar no se listarán en la salida de \hgcmd{status}. La igor@345: razón para esto es que \hgcmd{status} solamente le muestra aquellos igor@345: archivos ``interesantes''---los que usted haya modificado o a aquellos igor@345: sobre los que usted haya indicado a Mercurial hacerles algo---de forma igor@345: predeterminada. Si tiene un repositorio que contiene miles de igor@345: archivos, inusualmente deseará saber cuáles de ellos están siendo igor@345: seguidos por Mercurial, pero que no han cambiado. (De todas maneras, igor@345: puede obtener tal información; más adelante hablaremos de ello.) igor@345: igor@345: igor@345: Cuando usted añade un archivo, Mercurial no hace nada con el inmediatamente. igor@345: A cambio, tomará una instantánea del estado del archivo la próxima vez igor@345: que usted consigne. Continuará haciendo seguimiento a los cambios que igor@345: haga sobre el archivo cada vez que consigne, hasta que usted lo elimine. igor@345: igor@345: \subsection{Nombramiento explicíto e implícito de archivos} igor@345: igor@345: Mercurial tiene un comportamiento útil en el cual si a una orden, igor@345: le pasa el nombre de un directorio, todas las órdenes lo tratarán como igor@345: ``Deseo operar en cada archivo de este directorio y sus igor@345: subdirectorios''. igor@345: \interaction{daily.files.add-dir} igor@345: Tenga en cuenta que en este ejemplo Mercurial imprimió los nombres de igor@345: los archivos que se adicionaron, mientras que no lo hizo en el ejemplo igor@345: anterior cuando adicionamos el archivo con nombre \filename{a}. igor@345: igor@345: En el último caso hicimos explícito el nombre del archivo que igor@345: deseábamos adicionar en la línea de órdenes, y Mercurial asume en igor@345: tales casos que usted sabe lo que está haciendo y no imprime igor@345: información alguna. igor@345: igor@345: Cuando hacemos \emph{implícitos} los nombres de los archivos dando el igor@345: nombre de un directorio, Mercurial efectua un paso extra al imprimir igor@345: el nombre de cada archivo con el que va a hacer algo. Esto para igor@345: aclarar lo que está sucediendo, y reducir en lo posible una sorpresa igor@345: silenciosa pero fatal. Este comportamiento es común a la mayoría de igor@345: órdenes en Mercurial. igor@345: igor@345: \subsection{Nota al margen:Mercurial trata archivos, no directorios} igor@345: igor@345: Mercurial no da seguimiento a la información de los directorios. En igor@345: lugar de eso tiene en cuenta las rutas de los archivos. Antes de igor@345: crear un archivo, primero crea todos los directorios que hagan falta igor@345: para completar la ruta del archivo. Después de borrar un archivo, igor@345: borra todos los directorios vacíos que estuvieran en la ruta del igor@345: archivo borrado. Suena como una diferencia trivial, pero tiene una igor@345: consecuencia práctica menor: no es posible representar un directorio igor@345: completamente vacío en Mercurial. igor@345: igor@345: Los directorios vacíos son inusualmente útiles, hay soluciones igor@345: alternativas no intrusivas que puede emplear para obtener el efecto igor@345: apropiado. Los desarrolladores de Mercurial pensaron que la igor@345: complejidad necesaria para administrar directorios vacíos no valía la igor@345: pena frente al beneficio limitado que esta característica podría traer. igor@345: igor@345: Si necesita un directorio vacío en su repositorio, hay algunas formas igor@345: de lograrlo. Una es crear un directorio, después hacer \hgcmd{add} a igor@345: un archivo ``escondido'' dentro de ese directorio. En sistemas tipo igor@345: Unix, cualquier archivo cuyo nombre comience con un punto igor@345: (``\texttt{.}'') se trata como escondido por la mayoría de igor@345: herramientas GUI. Esta aproximación se ilustra en la figura~\ref{ex:daily:hidden}. igor@345: igor@345: \begin{figure}[ht] igor@345: \interaction{daily.files.hidden} igor@345: \caption{Simular un directorio vacío con un archivo escondido} igor@345: \label{ex:daily:hidden} igor@345: \end{figure} igor@345: igor@345: Otra forma de abordar la necesidad de un archivo vacío es crear igor@345: simplemente uno en sus guiones de construcción antes de ser necesarios. igor@345: igor@353: \section{Cómo dejar de hacer seguimiento a un archivo} igor@353: igor@353: Si decide que un archivo no pertenece a su repositorio, use la orden igor@353: \hgcmd{remove}; se borrará el archivo y le indicará a Mercurial que igor@353: deje de hacerle seguimiento. Los archivos eliminados se representan igor@353: con ``\texttt{R}'' al usar \hgcmd{status}. igor@345: \interaction{daily.files.remove} igor@345: igor@353: Después de hacer \hgcmd{remove} a un archivo, Mercurial dejará de igor@353: hacer seguimiento al mismo, incluso si recrea el archivo con el mismo igor@353: nombre en su directorio de trabajo. Si decide recrear un archivo con igor@353: el mismo nombre y desea que Mercurial le haga seguimiento, basta con igor@353: hacerle \hgcmd{add}. Mercurial sabrá que el archivo recientemente igor@353: adicionado no está relacionado con el archivo anterior que tenía el igor@353: mismo nombre. igor@353: igor@353: \subsection{Al eliminar un archivo no se afecta su historia} igor@353: igor@353: Es preciso tener en cuenta que al eliminar un archivo se tiene igor@353: dos efectos solamente. igor@345: \begin{itemize} igor@353: \item Se elimina la versión actual del fichero del directorio de igor@353: trabajo. igor@353: \item Mercurial deja de hacer seguimiento a los cambios del fichero igor@353: desde la próxima consignación. igor@345: \end{itemize} igor@353: Al eliminar un fichero \emph{no} se altera de ninguna manera la igor@353: \emph{historia} del mismo. igor@353: igor@353: Si actualiza su directorio de trabajo a un conjunto de cambios en el igor@353: cual esl archivo que eliminó aún era tenido en cuenta, reaparecerá en igor@353: el directorio de trabajo, con los contenidos que este tenía cuando se igor@353: consignó tal conjunto de cambios. Si usted actualiza el directorio de igor@353: trabajo a un conjunto de cambios posterior en el cual el archivo había igor@353: sido eliminado, Mercurial lo eliminará de nuevo del directorio de igor@353: trabajo. igor@345: igor@354: \subsection{Archivos perdidos} igor@345: igor@353: Mercurial considera como \emph{perdido} un archivo que usted borró, igor@353: pero para el que no se usó \hgcmd{remove}. Los archivos perdidos se igor@353: representan con ``\texttt{!}'' al visualizar \hgcmd{status}. igor@353: Las órdenes de Mercurial generalmente no harán nada con los archivos igor@353: perdidos. igor@345: \interaction{daily.files.missing} igor@345: igor@353: Si su repositorio contiene un archivo que \hgcmd{status} reporta como igor@353: perdido, y desea que el mismo se vaya, se puede usar igor@353: \hgcmdargs{remove}{\hgopt{remove}{--after}} posteriormente para igor@353: indicarle a Mercurial que usted deseaba borrar tal archivo. igor@345: \interaction{daily.files.remove-after} igor@345: igor@353: Por otro lado, si borró un fichero perdido por accidente, puede usar igor@353: \hgcmdargs{revert}{\emph{nombre de fichero}} para recuperar el igor@353: fichero. Reaparecerá sin modificaciones. igor@345: \interaction{daily.files.recover-missing} igor@345: igor@353: \subsection{Nota al margen: ¿Por qué decirle explícitamente a Mercurial igor@353: que elimine un archivo?} igor@353: igor@353: Es posible que se haya preguntado por qué Mercurial exige que usted le igor@353: indique explícitamente que está borrando un archivo. Al principio del igor@353: desarrollo de Mercurial, este permitía que usted borrara el archivo igor@353: sin más; Mercurial se daría cuanta de la ausencia del archivo igor@353: automáticamente después de la ejecución de \hgcmd{commit}, y dejaba de igor@353: hacer seguimiento al archivo. En la práctica, resultaba muy sencillo igor@353: borrar un archivo accidentalmente sin darse cuenta. igor@353: igor@353: \subsection{Atajo útil---agregar y eliminar archivos en un solo paso} igor@353: igor@353: Mercurial ofrece una orden combinada, \hgcmd{addremove}, que agrega igor@353: los archivos que no tienen seguimiento y marca los archivos faltantes igor@353: como eliminados. igor@345: \interaction{daily.files.addremove} igor@353: La orden \hgcmd{commit} su puede usar con la opción \hgopt{commit}{-A} igor@353: que aplica el agregar-eliminar, seguido inmediatamente de una igor@353: consignación. igor@345: \interaction{daily.files.commit-addremove} igor@345: igor@345: \section{Copying files} igor@345: igor@345: Mercurial provides a \hgcmd{copy} command that lets you make a new igor@345: copy of a file. When you copy a file using this command, Mercurial igor@345: makes a record of the fact that the new file is a copy of the original igor@345: file. It treats these copied files specially when you merge your work igor@345: with someone else's. igor@345: igor@345: \subsection{The results of copying during a merge} igor@345: igor@345: What happens during a merge is that changes ``follow'' a copy. To igor@345: best illustrate what this means, let's create an example. We'll start igor@345: with the usual tiny repository that contains a single file. igor@345: \interaction{daily.copy.init} igor@345: We need to do some work in parallel, so that we'll have something to igor@345: merge. So let's clone our repository. igor@345: \interaction{daily.copy.clone} igor@345: Back in our initial repository, let's use the \hgcmd{copy} command to igor@345: make a copy of the first file we created. igor@345: \interaction{daily.copy.copy} igor@345: igor@345: If we look at the output of the \hgcmd{status} command afterwards, the igor@345: copied file looks just like a normal added file. igor@345: \interaction{daily.copy.status} igor@345: But if we pass the \hgopt{status}{-C} option to \hgcmd{status}, it igor@345: prints another line of output: this is the file that our newly-added igor@345: file was copied \emph{from}. igor@345: \interaction{daily.copy.status-copy} igor@345: igor@345: Now, back in the repository we cloned, let's make a change in igor@345: parallel. We'll add a line of content to the original file that we igor@345: created. igor@345: \interaction{daily.copy.other} igor@345: Now we have a modified \filename{file} in this repository. When we igor@345: pull the changes from the first repository, and merge the two heads, igor@345: Mercurial will propagate the changes that we made locally to igor@345: \filename{file} into its copy, \filename{new-file}. igor@345: \interaction{daily.copy.merge} igor@345: igor@345: \subsection{Why should changes follow copies?} igor@345: \label{sec:daily:why-copy} igor@345: igor@345: This behaviour, of changes to a file propagating out to copies of the igor@345: file, might seem esoteric, but in most cases it's highly desirable. igor@345: igor@345: First of all, remember that this propagation \emph{only} happens when igor@345: you merge. So if you \hgcmd{copy} a file, and subsequently modify the igor@345: original file during the normal course of your work, nothing will igor@345: happen. igor@345: igor@345: The second thing to know is that modifications will only propagate igor@345: across a copy as long as the repository that you're pulling changes igor@345: from \emph{doesn't know} about the copy. igor@345: igor@345: The reason that Mercurial does this is as follows. Let's say I make igor@345: an important bug fix in a source file, and commit my changes. igor@345: Meanwhile, you've decided to \hgcmd{copy} the file in your repository, igor@345: without knowing about the bug or having seen the fix, and you have igor@345: started hacking on your copy of the file. igor@345: igor@345: If you pulled and merged my changes, and Mercurial \emph{didn't} igor@345: propagate changes across copies, your source file would now contain igor@345: the bug, and unless you remembered to propagate the bug fix by hand, igor@345: the bug would \emph{remain} in your copy of the file. igor@345: igor@345: By automatically propagating the change that fixed the bug from the igor@345: original file to the copy, Mercurial prevents this class of problem. igor@345: To my knowledge, Mercurial is the \emph{only} revision control system igor@345: that propagates changes across copies like this. igor@345: igor@345: Once your change history has a record that the copy and subsequent igor@345: merge occurred, there's usually no further need to propagate changes igor@345: from the original file to the copied file, and that's why Mercurial igor@345: only propagates changes across copies until this point, and no igor@345: further. igor@345: igor@345: \subsection{How to make changes \emph{not} follow a copy} igor@345: igor@345: If, for some reason, you decide that this business of automatically igor@345: propagating changes across copies is not for you, simply use your igor@345: system's normal file copy command (on Unix-like systems, that's igor@345: \command{cp}) to make a copy of a file, then \hgcmd{add} the new copy igor@345: by hand. Before you do so, though, please do reread igor@345: section~\ref{sec:daily:why-copy}, and make an informed decision that igor@345: this behaviour is not appropriate to your specific case. igor@345: igor@345: \subsection{Behaviour of the \hgcmd{copy} command} igor@345: igor@345: When you use the \hgcmd{copy} command, Mercurial makes a copy of each igor@345: source file as it currently stands in the working directory. This igor@345: means that if you make some modifications to a file, then \hgcmd{copy} igor@345: it without first having committed those changes, the new copy will igor@345: also contain the modifications you have made up until that point. (I igor@345: find this behaviour a little counterintuitive, which is why I mention igor@345: it here.) igor@345: igor@345: The \hgcmd{copy} command acts similarly to the Unix \command{cp} igor@345: command (you can use the \hgcmd{cp} alias if you prefer). The last igor@345: argument is the \emph{destination}, and all prior arguments are igor@345: \emph{sources}. If you pass it a single file as the source, and the igor@345: destination does not exist, it creates a new file with that name. igor@345: \interaction{daily.copy.simple} igor@345: If the destination is a directory, Mercurial copies its sources into igor@345: that directory. igor@345: \interaction{daily.copy.dir-dest} igor@345: Copying a directory is recursive, and preserves the directory igor@345: structure of the source. igor@345: \interaction{daily.copy.dir-src} igor@345: If the source and destination are both directories, the source tree is igor@345: recreated in the destination directory. igor@345: \interaction{daily.copy.dir-src-dest} igor@345: igor@345: As with the \hgcmd{rename} command, if you copy a file manually and igor@345: then want Mercurial to know that you've copied the file, simply use igor@345: the \hgopt{copy}{--after} option to \hgcmd{copy}. igor@345: \interaction{daily.copy.after} igor@345: igor@345: \section{Renaming files} igor@345: igor@345: It's rather more common to need to rename a file than to make a copy igor@345: of it. The reason I discussed the \hgcmd{copy} command before talking igor@345: about renaming files is that Mercurial treats a rename in essentially igor@345: the same way as a copy. Therefore, knowing what Mercurial does when igor@345: you copy a file tells you what to expect when you rename a file. igor@345: igor@345: When you use the \hgcmd{rename} command, Mercurial makes a copy of igor@345: each source file, then deletes it and marks the file as removed. igor@345: \interaction{daily.rename.rename} igor@345: The \hgcmd{status} command shows the newly copied file as added, and igor@345: the copied-from file as removed. igor@345: \interaction{daily.rename.status} igor@345: As with the results of a \hgcmd{copy}, we must use the igor@345: \hgopt{status}{-C} option to \hgcmd{status} to see that the added file igor@345: is really being tracked by Mercurial as a copy of the original, now igor@345: removed, file. igor@345: \interaction{daily.rename.status-copy} igor@345: igor@345: As with \hgcmd{remove} and \hgcmd{copy}, you can tell Mercurial about igor@345: a rename after the fact using the \hgopt{rename}{--after} option. In igor@345: most other respects, the behaviour of the \hgcmd{rename} command, and igor@345: the options it accepts, are similar to the \hgcmd{copy} command. igor@345: igor@345: \subsection{Renaming files and merging changes} igor@345: igor@345: Since Mercurial's rename is implemented as copy-and-remove, the same igor@345: propagation of changes happens when you merge after a rename as after igor@345: a copy. igor@345: igor@345: If I modify a file, and you rename it to a new name, and then we merge igor@345: our respective changes, my modifications to the file under its igor@345: original name will be propagated into the file under its new name. igor@345: (This is something you might expect to ``simply work,'' but not all igor@345: revision control systems actually do this.) igor@345: igor@345: Whereas having changes follow a copy is a feature where you can igor@345: perhaps nod and say ``yes, that might be useful,'' it should be clear igor@345: that having them follow a rename is definitely important. Without igor@345: this facility, it would simply be too easy for changes to become igor@345: orphaned when files are renamed. igor@345: igor@345: \subsection{Divergent renames and merging} igor@345: igor@345: The case of diverging names occurs when two developers start with a igor@345: file---let's call it \filename{foo}---in their respective igor@345: repositories. igor@345: igor@345: \interaction{rename.divergent.clone} igor@345: Anne renames the file to \filename{bar}. igor@345: \interaction{rename.divergent.rename.anne} igor@345: Meanwhile, Bob renames it to \filename{quux}. igor@345: \interaction{rename.divergent.rename.bob} igor@345: igor@345: I like to think of this as a conflict because each developer has igor@345: expressed different intentions about what the file ought to be named. igor@345: igor@345: What do you think should happen when they merge their work? igor@345: Mercurial's actual behaviour is that it always preserves \emph{both} igor@345: names when it merges changesets that contain divergent renames. igor@345: \interaction{rename.divergent.merge} igor@345: igor@345: Notice that Mercurial does warn about the divergent renames, but it igor@345: leaves it up to you to do something about the divergence after the merge. igor@345: igor@345: \subsection{Convergent renames and merging} igor@345: igor@345: Another kind of rename conflict occurs when two people choose to igor@345: rename different \emph{source} files to the same \emph{destination}. igor@345: In this case, Mercurial runs its normal merge machinery, and lets you igor@345: guide it to a suitable resolution. igor@345: igor@345: \subsection{Other name-related corner cases} igor@345: igor@345: Mercurial has a longstanding bug in which it fails to handle a merge igor@345: where one side has a file with a given name, while another has a igor@345: directory with the same name. This is documented as~\bug{29}. igor@345: \interaction{issue29.go} igor@345: igor@345: \section{Recovering from mistakes} igor@345: igor@345: Mercurial has some useful commands that will help you to recover from igor@345: some common mistakes. igor@345: igor@345: The \hgcmd{revert} command lets you undo changes that you have made to igor@345: your working directory. For example, if you \hgcmd{add} a file by igor@345: accident, just run \hgcmd{revert} with the name of the file you added, igor@345: and while the file won't be touched in any way, it won't be tracked igor@345: for adding by Mercurial any longer, either. You can also use igor@345: \hgcmd{revert} to get rid of erroneous changes to a file. igor@345: igor@345: It's useful to remember that the \hgcmd{revert} command is useful for igor@345: changes that you have not yet committed. Once you've committed a igor@345: change, if you decide it was a mistake, you can still do something igor@345: about it, though your options may be more limited. igor@345: igor@345: For more information about the \hgcmd{revert} command, and details igor@345: about how to deal with changes you have already committed, see igor@345: chapter~\ref{chap:undo}. igor@345: igor@345: %%% Local Variables: igor@345: %%% mode: latex igor@345: %%% TeX-master: "00book" igor@345: %%% End: