hgbook

view es/undo.tex @ 396:0f2170fcb79a

added the term "tracking", and translated a few paragraphs of concepts.tex
author Javier Rojas <jerojasro@devnull.li>
date Thu Nov 06 23:01:34 2008 -0500 (2008-11-06)
parents 9fdb45b994d4
children b8d9066abcea
line source
1 \chapter{Encontrar y arreglar sus equivocaciones}
2 \label{chap:undo}
4 Errar es humano, pero tratar adecuadamente las consecuencias requiere
5 un sistema de control de revisiones de primera categoría. En este
6 capítulo, discutiremos algunas técnicas que puede usar cuando
7 encuentra que hay un problema enraizado en su proyecto. Mercurial
8 tiene unas características poderosas que le ayudarán a isolar las
9 fuentes de los problemas, y a dar cuenta de ellas apropiadamente.
11 \section{Borrar la historia local}
13 \subsection{La consignación accidental}
15 Tengo el problema ocasional, pero persistente de teclear más rápido de
16 lo que pienso, que aveces resulta en consignar un conjunto de cambios
17 incompleto o simplemente malo. En mi caso, el conjunto de cambios
18 incompleto consiste en que creé un nuevo fichero fuente, pero olvidé
19 hacerle \hgcmd{add}. Un conjunto de cambios``simplemente malo'' no es
20 tan común, pero sí resulta muy molesto.
22 \subsection{Hacer rollback una transacción}
23 \label{sec:undo:rollback}
25 En la sección~\ref{sec:concepts:txn}, mencioné que Mercurial trata
26 modificación a un repositorio como una \emph{transacción}. Cada vez
27 que consigna un conjunto de cambios o lo jala de otro repositorio,
28 Mercurial recuerda lo que hizo. Puede deshacer, o hacer \emph{roll back}\ndt{El significado igual que en los
29 ambientes de sistemas manejadores de bases de datos se refiere a
30 la atomicidad e integridad al devolver un conjunto de acciones que
31 permitan dejar el repositorio en un estado consistente previo},
32 exactamente una de tales acciones usando la orden \hgcmd{rollback}.
33 (Ver en la sección~\ref{sec:undo:rollback-after-push} una anotación
34 importante acerca del uso de esta orden.)
36 A continuación una equivocación que me sucede frecuentemente:
37 consignar un cambio en el cual he creado un nuevo fichero, pero he
38 olvidado hacerle \hgcmd{add}.
39 \interaction{rollback.commit}
40 La salida de \hgcmd{status} después de la consignación confirma
41 inmediatamente este error.
42 \interaction{rollback.status}
43 La consignación capturó los cambios en el fichero \filename{a}, pero
44 no el nuevo fichero \filename{b}. Si yo publicara este conjunto de
45 cambios a un repositorio compartido con un colega, es bastante
46 probable que algo en \filename{a} se refiriera a \filename{b}, el cual
47 podría no estar presente cuando jalen mis cambios del repositorio. Me
48 convertiría el sujeto de cierta indignación.
50 Como sea, la suerte me acompaña---Encontré mi error antes de publicar
51 el conjunto de cambios. Uso la orden \hgcmd{rollback}, y Mercurial
52 hace desaparecer el último conjunto de cambios.
53 \interaction{rollback.rollback}
54 El conjunto de cambios ya no está en la historia del repositorio, y el
55 directorio de trabajo cree que el fichero \filename{a} ha sido
56 modificado. La consignación y el roll back dejaron el directorio de
57 trabajo exactamente como estaba antes de la consignación; el conjunto
58 de cambios ha sido eliminado totlamente. Ahora puedo hacer \hgcmd{add}
59 al fichero \filename{b}, y hacer de nuevo la consignación.
60 \interaction{rollback.add}
62 \subsection{Erroneamente jalado}
64 Mantener ramas de desarrollo separadas de un proyecto en distintos
65 repositorios es una práctica común con Mercurial. Su equipo de
66 desarrollo puede tener un repositorio compartido para la versión ``0.9''
67 y otra con cambios distintos para la versión ``1.0''.
69 Con este escenario, puede imaginar las consecuencias si tuviera un
70 repositorio local ``0.9'', y jalara accidentalmente los cambios del
71 repositorio compartido de la versión ``1.0'' en este. En el peor de
72 los casos, por falta de atención, es posible que publique tales
73 cambios en el árbol compartido ``0.9'', confundiendo a todo su equipo
74 de trabajo(pero no se preocupe, volveremos a este terrorífico
75 escenario posteriormente). En todo caso, es muy probable que usted se
76 de cuenta inmediatamente, dado que Mercurial mostrará el URL de donde
77 está jalando, o que vea jalando una sospechosa gran cantidad de
78 cambios en el repositorio.
80 La orden \hgcmd{rollback} excluirá eficientemente los conjuntos de
81 cambios que haya acabado de jalar. Mercurial agrupa todos los cambios
82 de un \hgcmd{pull} a una única transacción y bastará con un
83 \hgcmd{rollback} para deshacer esta equivocación.
85 \subsection{Después de publicar, un roll back es futil}
86 \label{sec:undo:rollback-after-push}
88 El valor de \hgcmd{rollback} se anula cuando ha publicado sus cambios
89 a otro repositorio. Un cambio desaparece totalmente al hacer roll back,
90 pero \emph{solamente} en el repositorio en el cual aplica
91 \hgcmd{rollback}. Debido a que un roll back elimina la historia,
92 no hay forma de que la desaparición de un cambio se propague entre
93 repositorios.
95 Si ha publicado un cambio en otro repositorio---particularmente si es
96 un repositorio público---esencialmente está ``en terreno agreste,''
97 y tendrá que reparar la equivocación de un modo distinto. Lo que
98 pasará si publica un conjunto de cambios en algún sitio, hacer
99 rollback y después volver a jalar del repositorio del cual había
100 publicado, es que el conjunto de cambios reaparecerá en su repositorio.
102 (Si está absolutamente segruro de que el conjunto de cambios al que
103 desea hacer rollback es el cambio más reciente del repositorio en el
104 cual publicó, \emph{y} sabe que nadie más pudo haber jalado de tal
105 repositorio, puede hacer rollback del conjunto de cambios allí, pero
106 es mejor no confiar en una solución de este estilo. Si lo hace, tarde
107 o temprano un conjunto de cambios logrará colarse en un repositorio
108 que usted no controle directamente(o del cual se ha olvidado), y
109 volverá a hostigarle.)
111 \subsection{Solamente hay un roll back}
113 Mercurial almacena exactamente una transacción en su bitácora de
114 transacciones; tal transacción es la más reciente de las que haya
115 ocurrido en el repositorio. Esto significa que solamente puede hacer
116 roll back a una transacción. Si espera poder hacer roll back a una
117 transacción después al antecesor, observará que no es el
118 comportamiento que obtendrá.
119 \interaction{rollback.twice}
120 Una vez que haya aplicado un rollback en una transacción a un
121 repositorio, no podrá volver a hacer rollback hasta que haga una
122 consignación o haya jalado.
124 \section{Revertir un cambio equivocado}
126 Si modifica un fichero y se da cuenta que no quería realmente cambiar
127 tal fichero, y todavía no ha consignado los cambios, la orden
128 necesaria es \hgcmd{revert}. Observa el conjunto de cambios padre del
129 directorio y restaura los contenidos del fichero al estado de tal
130 conjunto de cambios. (Es una forma larga de decirlo, usualmente
131 deshace sus modificaciones.)
133 Ilustremos como actúa la orden \hgcmd{revert} con un ejemplo
134 pequeño. Comenzaremos modificando un fichero al cual Mercurial ya está
135 siguiendo.
136 \interaction{daily.revert.modify}
137 Si no queremos ese cambio, podemos aplicar \hgcmd{revert} al fichero.
138 \interaction{daily.revert.unmodify}
139 La orden \hgcmd{revert} nos brinda un grado adicional de seguridad
140 guardando nuestro fichero modificado con la extensión \filename{.orig}.
141 \interaction{daily.revert.status}
143 Este es un resumen de casos en los cuales la orden \hgcmd{revert} es
144 de utilidad. Describiremos cada uno de ellos con más detalle en la
145 sección siguiente.
146 \begin{itemize}
147 \item Si usted modifica un fichero, lo restaurará a su estado sin
148 modificación previo.
149 \item Si usted hace \hgcmd{add} a un fichero, revertirá el estado de
150 ``adicionado'' del fichero, pero no lo tocará
151 \item Si borra un fichero sin decirle a Mercurial, restaurará el
152 fichero con sus contenidos sin modificación.
153 \item Si usa la orden \hgcmd{remove} para eliminar un fichero, deshará
154 el estado ``removido'' del fichero, y lo restaurará con sus
155 contenidos sin modificación.
156 \end{itemize}
158 \subsection{Errores al administrar ficheros}
159 \label{sec:undo:mgmt}
161 La orden \hgcmd{revert} es útil para más que ficheros modificados. Le
162 permite reversar los resultados de todas las órdenes de administración
163 de ficheros que provee Mercurial---\hgcmd{add}, \hgcmd{remove}, y las
164 demás.
166 Si usted hace \hgcmd{add} a un fichero, y no deseaba que Mercurial le
167 diera seguimiento, use \hgcmd{revert} para deshacer la adición. No se
168 preocupe; Mercurial no modificará de forma alguna el fichero.
169 Solamente lo ``desmarcará''.
170 \interaction{daily.revert.add}
172 De forma similar, Si le solicita a Mercurial hacer \hgcmd{remove} a un
173 fichero, puede usar \hgcmd{revert} para restarurarlo a los contenidos
174 que tenía la revisión padre del directorio de trabajo.
175 \interaction{daily.revert.remove}
176 Funciona de la misma manera para un fichero que usted haya eliminado
177 manualmente, sin decirle a Mercurial (recuerde que en la terminología
178 de Mercurial esta clase de fichero se llama ``faltante'').
179 \interaction{daily.revert.missing}
181 Si usted revierte un \hgcmd{copy}, el fichero a donde se copió
182 permanece en su directorio de trabajo, pero sin seguimiento. Dado que
183 una copia no afecta el fichero fuente de copiado de ninguna maner,
184 Mercurial no hace nada con este.
185 \interaction{daily.revert.copy}
187 \subsubsection{Un caso ligeramente especial:revertir un renombramiento}
189 Si hace \hgcmd{rename} a un fichero, hay un detalle que debe tener en
190 cuenta. Cuando aplica \hgcmd{revert} a un cambio de nombre, no es
191 suficiente proveer el nombre del fichero destino, como puede verlo en
192 el siguiente ejemplo.
193 \interaction{daily.revert.rename}
194 Como puede ver en la salida de \hgcmd{status}, el fichero con el nuevo
195 nombre no se identifica más como agregado, pero el fichero con el
196 nombre-\emph{inicial} se elimna! Esto es contra-intuitivo (por lo
197 menos para mí), pero por lo menos es fácil arreglarlo.
198 \interaction{daily.revert.rename-orig}
199 Por lo tanto, recuerde, para revertir un \hgcmd{rename}, debe proveer
200 \emph{ambos} nombres, la fuente y el destino.
202 % TODO: the output doesn't look like it will be removed!
204 (A propósito, si elimina un fichero, y modifica el fichero con el
205 nuevo nombre, al revertir ambos componentes del renombramiento, cuando
206 Mercurial restaure el fichero que fue eliminado como parte del
207 renombramiento, no será modificado.
208 Si necesita que las modificaciones en el archivo destino del
209 renombramiento se muestren, no olvide copiarlas encima.)
211 Estos aspectos engorrosos al revertir un renombramiento se constituyen
212 discutiblemente en un fallo de Mercurial.
214 \section{Tratar cambios consignados}
216 Considere un caso en el que ha consignado el cambio $a$, y otro cambio
217 $b$ sobre este; se ha dado cuenta que el cambio $a$ era
218 incorrecto. Mercurial le permite ``retroceder'' un conjunto de cambios
219 completo automáticamente, y construir bloques que le permitan revertir
220 parte de un conjunto de cambios a mano.
222 Antes de leer esta sección, hay algo para tener en cuenta: la orden
223 \hgcmd{backout} deshace cambios \emph{adicionando} a la historia, sin
224 modificar o borrar. Es la herramienta correcta si está arreglando
225 fallos, pero no si está tratando de deshacer algún cambio que tiene
226 consecuencias catastróficas. Para tratar con esos, vea la sección~\ref{sec:undo:aaaiiieee}.
228 \subsection{Retroceder un conjunto de cambios}
230 La orden \hgcmd{backout} le permite ``deshacer'' los efectos de todo
231 un conjunto de cambios de forma automatizada. Dado que la historia de
232 Mercurial es inmutable, esta orden \emph{no} se deshace del conjunto
233 de cambios que usted desea deshacer. En cambio, crea un nuevo
234 conjunto de cambios que \emph{reversa} el conjunto de cambios que
235 usted indique.
237 La operación de la orden \hgcmd{backout} es un poco intrincada, y lo
238 ilustraremos con algunos ejemplos. Primero crearemos un repositorio
239 con algunos cambios sencillos.
240 \interaction{backout.init}
242 La orden \hgcmd{backout} toma un ID de conjunto de cambios como su
243 argumento; el conjunto de cambios a retroceder. Normalmente
244 \hgcmd{backout} le ofrecerá un editor de texto para escribir el
245 mensaje de la consignación, para dejar un registro de por qué está
246 retrocediendo. En este ejemplo, colocamos un mensaje en la
247 consignación usando la opción \hgopt{backout}{-m} .
249 \subsection{Retroceder el conjunto de cambios punta}
251 Comenzamos retrocediendo el último conjunto de cambios que consignamos.
252 \interaction{backout.simple}
253 Puede ver que la segunda línea de \filename{myfile} ya no está
254 presente. La salida de \hgcmd{log} nos da una idea de lo que la orden
255 \hgcmd{backout} ha hecho.
256 \interaction{backout.simple.log}
257 Vea que el nuevo conjunto de cambios que \hgcmd{backout} ha creado es
258 un hijo del conjunto de cambios que retrocedimos. Es más sencillo de
259 ver en la figura~\ref{fig:undo:backout}, que presenta una vista
260 gráfica de la historia de cambios. Como puede ver, la historia es
261 bonita y lineal.
263 \begin{figure}[htb]
264 \centering
265 \grafix{undo-simple}
266 \caption{Retroceso de un cambio con la orden \hgcmd{backout}}
267 \label{fig:undo:backout}
268 \end{figure}
270 \subsection{Retroceso de un cambio que no es la punta}
272 Si desea retrocede un cambio distinto al último que ha consignado, use
273 la opción \hgopt{backout}{--merge} a la orden \hgcmd{backout}.
274 \interaction{backout.non-tip.clone}
275 Que resulta en un retroceso de un conjunto de cambios ``en un sólo
276 tiro'', una operación que resulta normalmente rápida y sencilla.
277 \interaction{backout.non-tip.backout}
279 Si ve los contenidos del fichero \filename{myfile} después de
280 finalizar el retroceso, verá que el primer y el tercer cambio están
281 presentes, pero no el segundo.
282 \interaction{backout.non-tip.cat}
284 Como lo muestra la historia gráfica en la
285 figura~\ref{fig:undo:backout-non-tip}, Mercurial realmente consigna
286 \emph{dos} cambios en estas situaciones (los nodos encerrados en una
287 caja son aquellos que Mercurial consigna automaticamente). Antes de
288 que Mercurial comience el proceso de retroceso, primero recuerda cuál
289 es el padre del directorio de trabajo. Posteriormente hace un
290 retroceso al conjunto de cambios objetivo y lo consigna como un
291 conjunto de cambios. Finalmente, fusiona con el padre anterior del
292 directorio de trabajo, y consigna el resultado de la fusión.
294 % TODO: to me it looks like mercurial doesn't commit the second merge automatically!
296 \begin{figure}[htb]
297 \centering
298 \grafix{undo-non-tip}
299 \caption{Retroceso automatizado de un cambio a algo que no es la punta con la orden \hgcmd{backout}}
300 \label{fig:undo:backout-non-tip}
301 \end{figure}
303 El resultado es que usted termina ``donde estaba'', solamente con un
304 poco de historia adicional que deshace el efecto de un conjunto de
305 cambios que usted quería evitar.
307 \subsubsection{Use siempre la opción \hgopt{backout}{--merge}}
309 De hecho, dado que la opción \hgopt{backout}{--merge} siempre hara lo
310 ``correcto'' esté o no retrocediendo el conjunto de cambios punta
311 (p.e.~no tratará de fusionar si está retrocediendo la punta, dado que
312 no es necesario), usted debería usar \emph{siempre} esta opción cuando
313 ejecuta la orden \hgcmd{backout}.
315 \subsection{Más control sobre el proceso de retroceso}
317 A pesar de que recomiendo usar siempre la opción
318 \hgopt{backout}{--merge} cuando está retrocediendo un cambio, la orden
319 \hgcmd{backout} le permite decidir cómo mezclar un retroceso de un
320 conjunto de cambios. Es muy extraño que usted necestite tomar control
321 del proceso de retroceso de forma manual, pero puede ser útil entender
322 lo que la orden \hgcmd{backout} está haciendo automáticamente para
323 usted. Para ilustrarlo, clonemos nuestro primer repositorio, pero
324 omitamos el retroceso que contiene.
326 \interaction{backout.manual.clone}
327 Como en el ejemplo anterior, consignaremos un tercer cambio, después
328 haremos retroceso de su padre, y veremos qué pasa.
329 \interaction{backout.manual.backout}
330 Nuestro nuevo conjunto de cambios es de nuevo un descendiente del
331 conjunto de cambio que retrocedimos; es por lo tanto una nueva cabeza,
332 \emph{no} un descendiente del conjunto de cambios que era la punta. La
333 orden \hgcmd{backout} fue muy explícita diciéndolo.
334 \interaction{backout.manual.log}
336 De nuevo, es más sencillo lo que pasó viendo una gráfica de la
337 historia de revisiones, en la figura~\ref{fig:undo:backout-manual}.
338 Esto nos aclara que cuando usamos \hgcmd{backout} para retroceder un
339 cambio a algo que no sea la punta, Mercurial añade una nueva cabeza al
340 repositorio (el cambio que consignó está encerrado en una caja).
342 \begin{figure}[htb]
343 \centering
344 \grafix{undo-manual}
345 \caption{Retroceso usando la orden \hgcmd{backout}}
346 \label{fig:undo:backout-manual}
347 \end{figure}
349 Después de que la orden \hgcmd{backout} ha terminado, deja un nuevo
350 conjunto de cambios de ``retroceso'' como el padre del directorio de trabajo.
351 \interaction{backout.manual.parents}
352 Ahora tenemos dos conjuntos de cambios aislados.
353 \interaction{backout.manual.heads}
355 Reflexionemos acerca de lo que esperamos ver como contenidos de
356 \filename{myfile}. El primer cambio debería estar presente, porque
357 nunca le hicimos retroceso. El segundo cambio debió desaparecer,
358 puesto que es el que retrocedimos. Dado que la gráfica de la historia
359 muestra que el tercer camlio es una cabeza separada, \emph{no}
360 esperamos ver el tercer cambio presente en \filename{myfile}.
361 \interaction{backout.manual.cat}
362 Para que el tercer cambio esté en el archivo, hacemos una fusión usual
363 de las dos cabezas.
364 \interaction{backout.manual.merge}
365 Después de eso, la historia gráfica de nuestro repositorio luce como
366 la figura~\ref{fig:undo:backout-manual-merge}.
368 \begin{figure}[htb]
369 \centering
370 \grafix{undo-manual-merge}
371 \caption{Fusión manual de un retroceso}
372 \label{fig:undo:backout-manual-merge}
373 \end{figure}
375 \subsection{Por qué \hgcmd{backout} hace lo que hace}
377 Esta es una descripción corta de cómo trabaja la orden \hgcmd{backout}.
378 \begin{enumerate}
379 \item Se asegura de que el directorio de trabajo es ``limpio'', esto
380 es, que la salida de \hgcmd{status} debería ser vacía.
381 \item Recuerda el padre actual del directorio de trabajo. A este
382 conjunto de cambio lo llamaremos \texttt{orig}
383 \item Hace el equivalente de un \hgcmd{update} para sincronizar el
384 directorio de trabajo con el conjunto de cambios que usted quiere
385 retroceder. Lo llamaremos \texttt{backout}
386 \item Encuentra el padre del conjunto de cambios. Lo llamaremos
387 \texttt{parent}.
388 \item Para cada archivo del conjunto de cambios que el
389 \texttt{retroceso} afecte, hará el equivalente a
390 \hgcmdargs{revert}{-r parent} sobre ese fichero, para restaurarlo a
391 los contenidos que tenía antes de que el conjunto de cambios fuera
392 consignado.
393 \item Se consigna el resultado como un nuevo conjunto de cambios y
394 tiene a \texttt{backout} como su padre.
395 \item Si especifica \hgopt{backout}{--merge} en la línea de comandos,
396 se fusiona con \texttt{orig}, y se consigna el resultado de la
397 fusión.
398 \end{enumerate}
400 Una vía alternativa de implementar la orden \hgcmd{backout} sería usar
401 \hgcmd{export} sobre el conjunto de cambios a retroceder como un diff
402 y después usar laa opción \cmdopt{patch}{--reverse} de la orden
403 \command{patch} para reversar el efecto del cambio sin molestar el
404 directorio de trabajo. Suena mucho más simple, pero no funcionaría
405 bien ni de cerca.
407 La razón por la cual \hgcmd{backout} hace una actualización, una
408 consignación, una fusión y otra consignación es para dar a la
409 maquinaria de fusión la mayor oportunidad de hacer un buen trabajo
410 cuando se trata con todos los cambios \emph{entre} el cambio que está
411 retrocediendo y la punta actual.
413 Si está retrocediendo un conjunto de cambios que está a unas ~100
414 atrás en su historia del proyecto, las posibilidades de que una orden
415 \command{patch} sea capaz de ser aplicada a un diff reverso,
416 claramente no son altas, porque los cambios que intervienen podrían
417 ``no coincidir con el contexto'' que \command{patch} usa para
418 determinar si puede aplicar un parche (si esto suena como cháchara,
419 vea una discusión de la orden \command{patch} en \ref{sec:mq:patch}).
420 Adicionalmente, la maquinaria de fusión de Mercurial manejará ficheros
421 y directorios renombrados, cambios de permisos, y modificaciones a
422 archivos binarios, nada de lo cual la orden \command{patch} puede manejar.
424 \section{Cambios que nunca debieron ocurrir}
425 \label{sec:undo:aaaiiieee}
427 En la mayoría de los casos, la orden \hgcmd{backout} es exactamente lo
428 que necesita para deshacer los efectos de un cambio. Deja un registro
429 permanente y exacto de lo que usted hizo, cuando se consignó el
430 conjunto de cambios original y cuando se hizo la limpieza.
432 En ocasiones particulares, puede haber consignado un cambio que no
433 debería estar de ninguna forma en el repositorio. Por ejemplo, sería
434 muy inusual, y considerado como una equivocación, consignar los
435 archivos objeto junto con el código fuente. los ficheros objeto no
436 tienen valor intrínseco y son \emph{grandes}, por lo tanto aumentan el
437 tamaño del repositorio y la cantidad de tiempo que se emplea al clonar
438 o jalar cambios.
440 Antes de discutir las opciones que tiene si consignó cambio del tipo
441 ``bolsa de papel deschable'' (el tipo que es tan malo que le gustaría
442 colocarse una bolsa de papel desechable en su cabeza), permítame
443 discutir primero unas aproximaciones que probablemente no funcionen.
445 Dado que Mercurial trata de forma acumulativa la historia---cada
446 cambio se coloca encima de todos los cambios que leo
447 preceden---usualmente usted no puede hacer que unos cambios desastros
448 desaparezcan. La única excepción es cuando usted ha acabado de
449 consignar un cambio y este no ha sido publicado o jalado en otro
450 repositorio. Ahí es cuando puede usar la orden \hgcmd{rollback} con
451 seguridad, Como detallé en la sección~\ref{sec:undo:rollback}.
453 Después de que usted haya publicado un cambio en otro repositorio, usted
454 \emph{podría} usar la orden \hgcmd{rollback} para hacer que en su copia
455 local desaparezca el cambio, pero no tendrá las consecuencias que
456 desea. El cambio estará presente en un repositorio remoto, y
457 reaparecerá en su repositorio local la próxima vez que jale
459 Si una situación como esta se presenta, y usted sabe en qué
460 repositorios su mal cambio se ha propagado, puede \emph{intentar}
461 deshacerse del conjunto de cambios de \emph{todos} los repositorios en
462 los que se pueda encontrar. Esta por supuesto, no es una solución
463 satisfactoria: si usted deja de hacerlo en un solo repositorio,
464 mientras esté eliminándolo, el cambio todavía estará ``allí afuera'',
465 y podría propagarse más tarde.
467 Si ha consignado uno o más cambios \emph{después} del cambio que desea
468 desaparecer, sus opciones son aún más reducidas. Mercurial no provee
469 una forma de ``cabar un hueco'' en la historia, dejando los conjuntos
470 de cambios intactos.
472 %Dejamos de traducir lo que viene a continuación, porque será
473 %modificado por upstream...
475 XXX This needs filling out. The \texttt{hg-replay} script in the
476 \texttt{examples} directory works, but doesn't handle merge
477 changesets. Kind of an important omission.
479 \subsection{Protect yourself from ``escaped'' changes}
481 If you've committed some changes to your local repository and they've
482 been pushed or pulled somewhere else, this isn't necessarily a
483 disaster. You can protect yourself ahead of time against some classes
484 of bad changeset. This is particularly easy if your team usually
485 pulls changes from a central repository.
487 By configuring some hooks on that repository to validate incoming
488 changesets (see chapter~\ref{chap:hook}), you can automatically
489 prevent some kinds of bad changeset from being pushed to the central
490 repository at all. With such a configuration in place, some kinds of
491 bad changeset will naturally tend to ``die out'' because they can't
492 propagate into the central repository. Better yet, this happens
493 without any need for explicit intervention.
495 For instance, an incoming change hook that verifies that a changeset
496 will actually compile can prevent people from inadvertantly ``breaking
497 the build''.
499 \section{Finding the source of a bug}
500 \label{sec:undo:bisect}
502 While it's all very well to be able to back out a changeset that
503 introduced a bug, this requires that you know which changeset to back
504 out. Mercurial provides an invaluable command, called
505 \hgcmd{bisect}, that helps you to automate this process and accomplish
506 it very efficiently.
508 The idea behind the \hgcmd{bisect} command is that a changeset has
509 introduced some change of behaviour that you can identify with a
510 simple binary test. You don't know which piece of code introduced the
511 change, but you know how to test for the presence of the bug. The
512 \hgcmd{bisect} command uses your test to direct its search for the
513 changeset that introduced the code that caused the bug.
515 Here are a few scenarios to help you understand how you might apply
516 this command.
517 \begin{itemize}
518 \item The most recent version of your software has a bug that you
519 remember wasn't present a few weeks ago, but you don't know when it
520 was introduced. Here, your binary test checks for the presence of
521 that bug.
522 \item You fixed a bug in a rush, and now it's time to close the entry
523 in your team's bug database. The bug database requires a changeset
524 ID when you close an entry, but you don't remember which changeset
525 you fixed the bug in. Once again, your binary test checks for the
526 presence of the bug.
527 \item Your software works correctly, but runs~15\% slower than the
528 last time you measured it. You want to know which changeset
529 introduced the performance regression. In this case, your binary
530 test measures the performance of your software, to see whether it's
531 ``fast'' or ``slow''.
532 \item The sizes of the components of your project that you ship
533 exploded recently, and you suspect that something changed in the way
534 you build your project.
535 \end{itemize}
537 From these examples, it should be clear that the \hgcmd{bisect}
538 command is not useful only for finding the sources of bugs. You can
539 use it to find any ``emergent property'' of a repository (anything
540 that you can't find from a simple text search of the files in the
541 tree) for which you can write a binary test.
543 We'll introduce a little bit of terminology here, just to make it
544 clear which parts of the search process are your responsibility, and
545 which are Mercurial's. A \emph{test} is something that \emph{you} run
546 when \hgcmd{bisect} chooses a changeset. A \emph{probe} is what
547 \hgcmd{bisect} runs to tell whether a revision is good. Finally,
548 we'll use the word ``bisect'', as both a noun and a verb, to stand in
549 for the phrase ``search using the \hgcmd{bisect} command.
551 One simple way to automate the searching process would be simply to
552 probe every changeset. However, this scales poorly. If it took ten
553 minutes to test a single changeset, and you had 10,000 changesets in
554 your repository, the exhaustive approach would take on average~35
555 \emph{days} to find the changeset that introduced a bug. Even if you
556 knew that the bug was introduced by one of the last 500 changesets,
557 and limited your search to those, you'd still be looking at over 40
558 hours to find the changeset that introduced your bug.
560 What the \hgcmd{bisect} command does is use its knowledge of the
561 ``shape'' of your project's revision history to perform a search in
562 time proportional to the \emph{logarithm} of the number of changesets
563 to check (the kind of search it performs is called a dichotomic
564 search). With this approach, searching through 10,000 changesets will
565 take less than three hours, even at ten minutes per test (the search
566 will require about 14 tests). Limit your search to the last hundred
567 changesets, and it will take only about an hour (roughly seven tests).
569 The \hgcmd{bisect} command is aware of the ``branchy'' nature of a
570 Mercurial project's revision history, so it has no problems dealing
571 with branches, merges, or multiple heads in a repoository. It can
572 prune entire branches of history with a single probe, which is how it
573 operates so efficiently.
575 \subsection{Using the \hgcmd{bisect} command}
577 Here's an example of \hgcmd{bisect} in action.
579 \begin{note}
580 In versions 0.9.5 and earlier of Mercurial, \hgcmd{bisect} was not a
581 core command: it was distributed with Mercurial as an extension.
582 This section describes the built-in command, not the old extension.
583 \end{note}
585 Now let's create a repository, so that we can try out the
586 \hgcmd{bisect} command in isolation.
587 \interaction{bisect.init}
588 We'll simulate a project that has a bug in it in a simple-minded way:
589 create trivial changes in a loop, and nominate one specific change
590 that will have the ``bug''. This loop creates 35 changesets, each
591 adding a single file to the repository. We'll represent our ``bug''
592 with a file that contains the text ``i have a gub''.
593 \interaction{bisect.commits}
595 The next thing that we'd like to do is figure out how to use the
596 \hgcmd{bisect} command. We can use Mercurial's normal built-in help
597 mechanism for this.
598 \interaction{bisect.help}
600 The \hgcmd{bisect} command works in steps. Each step proceeds as follows.
601 \begin{enumerate}
602 \item You run your binary test.
603 \begin{itemize}
604 \item If the test succeeded, you tell \hgcmd{bisect} by running the
605 \hgcmdargs{bisect}{good} command.
606 \item If it failed, run the \hgcmdargs{bisect}{--bad} command.
607 \end{itemize}
608 \item The command uses your information to decide which changeset to
609 test next.
610 \item It updates the working directory to that changeset, and the
611 process begins again.
612 \end{enumerate}
613 The process ends when \hgcmd{bisect} identifies a unique changeset
614 that marks the point where your test transitioned from ``succeeding''
615 to ``failing''.
617 To start the search, we must run the \hgcmdargs{bisect}{--reset} command.
618 \interaction{bisect.search.init}
620 In our case, the binary test we use is simple: we check to see if any
621 file in the repository contains the string ``i have a gub''. If it
622 does, this changeset contains the change that ``caused the bug''. By
623 convention, a changeset that has the property we're searching for is
624 ``bad'', while one that doesn't is ``good''.
626 Most of the time, the revision to which the working directory is
627 synced (usually the tip) already exhibits the problem introduced by
628 the buggy change, so we'll mark it as ``bad''.
629 \interaction{bisect.search.bad-init}
631 Our next task is to nominate a changeset that we know \emph{doesn't}
632 have the bug; the \hgcmd{bisect} command will ``bracket'' its search
633 between the first pair of good and bad changesets. In our case, we
634 know that revision~10 didn't have the bug. (I'll have more words
635 about choosing the first ``good'' changeset later.)
636 \interaction{bisect.search.good-init}
638 Notice that this command printed some output.
639 \begin{itemize}
640 \item It told us how many changesets it must consider before it can
641 identify the one that introduced the bug, and how many tests that
642 will require.
643 \item It updated the working directory to the next changeset to test,
644 and told us which changeset it's testing.
645 \end{itemize}
647 We now run our test in the working directory. We use the
648 \command{grep} command to see if our ``bad'' file is present in the
649 working directory. If it is, this revision is bad; if not, this
650 revision is good.
651 \interaction{bisect.search.step1}
653 This test looks like a perfect candidate for automation, so let's turn
654 it into a shell function.
655 \interaction{bisect.search.mytest}
656 We can now run an entire test step with a single command,
657 \texttt{mytest}.
658 \interaction{bisect.search.step2}
659 A few more invocations of our canned test step command, and we're
660 done.
661 \interaction{bisect.search.rest}
663 Even though we had~40 changesets to search through, the \hgcmd{bisect}
664 command let us find the changeset that introduced our ``bug'' with
665 only five tests. Because the number of tests that the \hgcmd{bisect}
666 command performs grows logarithmically with the number of changesets to
667 search, the advantage that it has over the ``brute force'' search
668 approach increases with every changeset you add.
670 \subsection{Cleaning up after your search}
672 When you're finished using the \hgcmd{bisect} command in a
673 repository, you can use the \hgcmdargs{bisect}{reset} command to drop
674 the information it was using to drive your search. The command
675 doesn't use much space, so it doesn't matter if you forget to run this
676 command. However, \hgcmd{bisect} won't let you start a new search in
677 that repository until you do a \hgcmdargs{bisect}{reset}.
678 \interaction{bisect.search.reset}
680 \section{Tips for finding bugs effectively}
682 \subsection{Give consistent input}
684 The \hgcmd{bisect} command requires that you correctly report the
685 result of every test you perform. If you tell it that a test failed
686 when it really succeeded, it \emph{might} be able to detect the
687 inconsistency. If it can identify an inconsistency in your reports,
688 it will tell you that a particular changeset is both good and bad.
689 However, it can't do this perfectly; it's about as likely to report
690 the wrong changeset as the source of the bug.
692 \subsection{Automate as much as possible}
694 When I started using the \hgcmd{bisect} command, I tried a few times
695 to run my tests by hand, on the command line. This is an approach
696 that I, at least, am not suited to. After a few tries, I found that I
697 was making enough mistakes that I was having to restart my searches
698 several times before finally getting correct results.
700 My initial problems with driving the \hgcmd{bisect} command by hand
701 occurred even with simple searches on small repositories; if the
702 problem you're looking for is more subtle, or the number of tests that
703 \hgcmd{bisect} must perform increases, the likelihood of operator
704 error ruining the search is much higher. Once I started automating my
705 tests, I had much better results.
707 The key to automated testing is twofold:
708 \begin{itemize}
709 \item always test for the same symptom, and
710 \item always feed consistent input to the \hgcmd{bisect} command.
711 \end{itemize}
712 In my tutorial example above, the \command{grep} command tests for the
713 symptom, and the \texttt{if} statement takes the result of this check
714 and ensures that we always feed the same input to the \hgcmd{bisect}
715 command. The \texttt{mytest} function marries these together in a
716 reproducible way, so that every test is uniform and consistent.
718 \subsection{Check your results}
720 Because the output of a \hgcmd{bisect} search is only as good as the
721 input you give it, don't take the changeset it reports as the
722 absolute truth. A simple way to cross-check its report is to manually
723 run your test at each of the following changesets:
724 \begin{itemize}
725 \item The changeset that it reports as the first bad revision. Your
726 test should still report this as bad.
727 \item The parent of that changeset (either parent, if it's a merge).
728 Your test should report this changeset as good.
729 \item A child of that changeset. Your test should report this
730 changeset as bad.
731 \end{itemize}
733 \subsection{Beware interference between bugs}
735 It's possible that your search for one bug could be disrupted by the
736 presence of another. For example, let's say your software crashes at
737 revision 100, and worked correctly at revision 50. Unknown to you,
738 someone else introduced a different crashing bug at revision 60, and
739 fixed it at revision 80. This could distort your results in one of
740 several ways.
742 It is possible that this other bug completely ``masks'' yours, which
743 is to say that it occurs before your bug has a chance to manifest
744 itself. If you can't avoid that other bug (for example, it prevents
745 your project from building), and so can't tell whether your bug is
746 present in a particular changeset, the \hgcmd{bisect} command cannot
747 help you directly. Instead, you can mark a changeset as untested by
748 running \hgcmdargs{bisect}{--skip}.
750 A different problem could arise if your test for a bug's presence is
751 not specific enough. If you check for ``my program crashes'', then
752 both your crashing bug and an unrelated crashing bug that masks it
753 will look like the same thing, and mislead \hgcmd{bisect}.
755 Another useful situation in which to use \hgcmdargs{bisect}{--skip} is
756 if you can't test a revision because your project was in a broken and
757 hence untestable state at that revision, perhaps because someone
758 checked in a change that prevented the project from building.
760 \subsection{Bracket your search lazily}
762 Choosing the first ``good'' and ``bad'' changesets that will mark the
763 end points of your search is often easy, but it bears a little
764 discussion nevertheless. From the perspective of \hgcmd{bisect}, the
765 ``newest'' changeset is conventionally ``bad'', and the older
766 changeset is ``good''.
768 If you're having trouble remembering when a suitable ``good'' change
769 was, so that you can tell \hgcmd{bisect}, you could do worse than
770 testing changesets at random. Just remember to eliminate contenders
771 that can't possibly exhibit the bug (perhaps because the feature with
772 the bug isn't present yet) and those where another problem masks the
773 bug (as I discussed above).
775 Even if you end up ``early'' by thousands of changesets or months of
776 history, you will only add a handful of tests to the total number that
777 \hgcmd{bisect} must perform, thanks to its logarithmic behaviour.
779 %%% Local Variables:
780 %%% mode: latex
781 %%% TeX-master: "00book"
782 %%% End: