hgbook

view es/undo.tex @ 597:e0d9eb01e4c2

Remove references to RWH.
author Bryan O'Sullivan <bos@serpentine.com>
date Thu Mar 26 23:05:28 2009 -0700 (2009-03-26)
parents 4af39acbb3cf
children
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 el historial 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 el historial 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 el historial,
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 fichero 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} al historial, 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 el historial 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 del historial de cambios. Como puede ver, el historial es
261 bonito 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 el historial gráfico 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 historial 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 del
337 historial 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 del historial
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 fichero, hacemos una fusión usual
363 de las dos cabezas.
364 \interaction{backout.manual.merge}
365 Después de eso, el historial 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 fichero 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 historial 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 ficheros 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 ficheros 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 al historial---cada
446 cambio se coloca encima de todos los cambios que le
447 preceden---usualmente usted no puede hacer que unos cambios desastrosos
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 el historial, 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{Cómo protegerse de cambios que han ``escapado''}
481 Si ha consignado cambios a su repositorio local y estos han sido
482 publicados o jalados en cualquier otro sitio, no es necesariamente un
483 desastre. Puede protegerse de antemano de ciertas clases de conjuntos
484 de cambios malos. Esto es particularmente sencillo si su equipo de
485 trabajo jala cambios de un repositorio central.
487 Al configurar algunos ganchos en el repositorio central para validar
488 conjuntos de cambios (ver capítulo~\ref{chap:hook}), puede prevenir la
489 publicación automáticamente de cierta clase de cambios malos. Con tal
490 configuración, cierta clase de conjuntos de cambios malos tenderán
491 naturalmente a``morir'' debido a que no pueden propagarse al
492 repositorio central. Esto sucederá sin necesidad de intervención
493 explícita.
495 Por ejemplo, un gancho de cambios de entrada que verifique que un
496 conjunto de cambios compila, puede prevenir que la gente ``rompa
497 la compilación'' inadvertidamente.
499 \section{Al encuentro de la fuente de un fallo}
500 \label{sec:undo:bisect}
502 Aunque es muy bueno poder retroceder el conjunto de cambios que
503 originó un fallo, se requiere que usted sepa cual conjunto de cambios
504 retroceder. Mercurial brinda una orden invaluable, llamada
505 \hgcmd{bisect}, que ayuda a automatizar este proceso y a alcanzarlo
506 muy eficientemente.
508 La idea tras la orden \hgcmd{bisect} es que el conjunto de cambios que
509 ha introducido un cambio de comportamiento pueda identificarse con una
510 prueba binaria sencilla. No tiene que saber qué pieza de código
511 introdujo el cambio, pero si requiere que sepa cómo probar la
512 existencia de un fallo. La orden \hgcmd{bisect} usa su prueba para
513 dirigir su búsqueda del conjunto de cambios que introdujo el código
514 causante del fallo.
516 A continuación un conjunto de escenarios que puede ayudarle a entender
517 cómo puede aplicar esta orden.
518 \begin{itemize}
519 \item La versión más reciente de su programa tiene un fallo que usted
520 recuerda no estaba hace unas semanas, pero no sabe cuándo fue
521 introducido. En este caso, su prueba binaria busca la presencia de
522 tal fallo.
523 \item Usted arregló un fallo en un apurto, y es hora de dar por
524 cerrado el caso en la base de datos de fallos de su equipo de
525 trabajo. La base de datos de fallos requiere el ID del conjunto de
526 cambios que permita dar por cerrado el caso, pero usted no recuerda
527 qué conjunto de cambios arregló tal fallo. De nuevo la prueba
528 binaria revisa la presencia del fallo.
529 \item Su programa funciona correctamente, pero core ~15\% más lento
530 que la última vez que lo midió. Usted desea saber qué conjunto de
531 cambios introdujo esta disminución de desempeño. En este caso su
532 prueba binaria mide el desempeño de su programa, para ver dónde es
533 ``rápido'' y dónde es ``lento''.
534 \item Los tamaños de los componentes del proyecto que usted lleva se
535 expandieron recientemente, y sospecha que algo cambio en la forma en
536 que se construye su proyecto.
537 \end{itemize}
539 Para estos ejemplos debería ser claro que la orden \hgcmd{bisect}
540 es útil no solamente para encontrar la fuente de los fallos. Puede
541 usarla para encontrar cualquier ``propiedad emergente'' de un
542 repositorio (Cualquier cosa que usted no pueda encontrar con una
543 búsqueda de texto sencilla sobre los ficheros en el árbol) para la
544 cual pueda escribir una prueba binaria.
546 A continuación introduciremos algo terminología, para aclarar qué
547 partes del proceso de búsqueda son su responsabilidad y cuáles de
548 Mercurial. Una \emph{prueba} es algo que \emph{usted} ejecuta cuando
549 \hgcmd{bisect} elige un conjunto de cambios. Un \emph{sondeo} es lo que
550 \hgcmd{bisect} ejecuta para decidir si una revisión es buena. Finalmente,
551 usaremos la palabra ``biseccionar', en frases como ``buscar con la
552 orden \hgcmd{bisect}''.
554 Una forma sencilla de automatizar el proceso de búsqueda sería probar
555 cada conjunto de cambios. Lo cual escala muy poco. Si le tomó diez
556 minutos hacer pruebas sobre un conjunto de cambios y tiene 10.000
557 conjuntos de cambios en su repositorio, esta aproximación exhaustiva
558 tomaría en promedio~35 \emph{días} para encontrar el conjunto de
559 cambios que introdujo el fallo. Incluso si supiera que el fallo se
560 introdujo en un de los últimos 500 conjuntos de cambios y limitara la
561 búsqueda a ellos, estaría tomabdi más de 40 horas para encontrar al
562 conjunto de cambios culpable.
564 La orden \hgcmd{bisect} usa su conocimiento de la ``forma'' del
565 historial de revisiones de su proyecto para hacer una búsqueda
566 proporcional al \emph{logaritmo} del número de conjunto de cambios a
567 revisar (el tipo de búsqueda que realiza se llama búsqueda
568 binaria). Con esta aproximación, el buscar entre 10.000 conjuntos de
569 cambios tomará menos de 3 horas, incluso a diez minutos por prueba (La
570 búsqueda requerirá cerca de 14 pruebas). Al limitar la búsqueda a la
571 última centena de conjuntos de cambios, tomará a lo sumo una
572 hora (Apenas unas 7 pruebas).
574 La orden \hgcmd{bisect} tiene en cuenta la naturaleza ``ramificada''
575 del historial de revisiones del proyecto con Mercurial, así que no
576 hay problemas al tratar con ramas, fusiones o cabezas múltiples en un
577 repositorio. Puede evitar ramas enteras de historial con un solo
578 sondeo.
580 \subsection{Uso de la orden \hgcmd{bisect}}
582 A continuación un ejemplo de \hgcmd{bisect} en acción.
584 \begin{note}
585 En las versiones 0.9.5 y anteriores de Mercurial, \hgcmd{bisect} no
586 era una orden incluída en la distribución principal: se ofrecía como
587 una extensión de Mercurial. Esta sección describe la orden embebida
588 y no la extensión anterior.
589 \end{note}
591 Creamos un repostorio para probar el comando \hgcmd{bisect} de forma
592 aislada
593 \interaction{bisect.init}
594 Simularemos de forma sencilla un proyecto con un fallo: haremos
595 cambios triviales en un ciclo, e indicaremos que un cambio específico
596 sea el ``fallo''. Este ciclo crea 35 conjuntos de cambios, cada uno
597 añade un único fichero al repositorio. Representaremos nuestro ``fallo''
598 con un fichero que contiene el texto ``tengo un gub''.
599 \interaction{bisect.commits}
601 A continuación observaremos cómo usar la orden \hgcmd{bisect}. Podemos
602 usar el mecanismo de ayuda embebida que trae Mercurial.
603 \interaction{bisect.help}
605 La orden \hgcmd{bisect} trabaja en etapas, de la siguiente forma:
606 \begin{enumerate}
607 \item Usted ejecuta una prueba binaria.
608 \begin{itemize}
609 \item Si la prueba es exitosa, usted se lo indicará a \hgcmd{bisect}
610 ejecutando la orden \hgcmdargs{bisect}{good}.
611 \item Si falla, ejecutará la orden \hgcmdargs{bisect}{--bad}.
612 \end{itemize}
613 \item La orden usa su información para decidir qué conjuntos de
614 cambios deben probarse a continuación.
615 \item Actualiza el directorio de trabajo a tal conjunto de cambios y
616 el proceso se lleva a cabo de nuevo.
617 \end{enumerate}
618 El proceso termina cuando \hgcmd{bisect} identifica un único conjunto
619 de cambios que marca el punto donde se encontró la transición de
620 ``exitoso'' a ``fallido''.
622 Para comenzar la búsqueda, es indispensable ejecutar la orden
623 \hgcmdargs{bisect}{--reset}.
624 \interaction{bisect.search.init}
626 En nuestro caso, la prueba binaria es sencilla: revisamos si el
627 fichero en el repositorio contiene la cadena ``tengo un gub''. Si la
628 tiene, este conjunto de cambios contiene aquel que ``causó el fallo''.
629 Por convención, un conjunto de cambios que tiene la propiedad que
630 estamos buscando es ``malo'', mientras que el otro que no la tiene es
631 ``bueno''.
633 En la mayoría de casos, la revisión del directorio actual (usualmente
634 la punta) exhibe el problema introducido por el cambio con el fallo,
635 por lo tanto la marcaremos como ``mala''.
636 \interaction{bisect.search.bad-init}
638 Nuestra próxima tarea es nominar al conjunto de cambios que sabemos
639 \emph{no} tiene el fallo; la orden \hgcmd{bisect} ``acotará'' su
640 búsqueda entre el primer par de conjuntos de cambios buenos y malos.
641 En nuestro caso, sabemos que la revisión~10 no tenía el fallo. (Más
642 adelante diré un poco más acerca de la elección del conjunto de
643 cambios ``bueno''.)
644 \interaction{bisect.search.good-init}
646 Note que esta orden mostró algo.
647 \begin{itemize}
648 \item Nos dijo cuántos conjuntos de cambios debe considerar antes de
649 que pueda identifica aquel que introdujo el fallo, y cuántas pruebas
650 se requerirán.
651 \item Actualizó el directorio de trabajo al siguiente conjunto de
652 cambios, y nos dijo qué conjunto de cambios está evaluando.
653 \end{itemize}
655 Ahora ejecutamos nuestra prueba en el directorio de trabajo. Usamos la
656 orden \command{grep} para ver si nuestro fichero ``malo'' está
657 presente en el directorio de trabajo. Si lo está, esta revisión es
658 mala; si no esta revisión es buena.
659 \interaction{bisect.search.step1}
661 Esta prueba luce como candidata perfecta para automatizarse, por lo
662 tanto la convertimos en una función de interfaz de comandos.
663 \interaction{bisect.search.mytest}
664 Ahora podemos ejecutar un paso entero de pruebas con un solo comando,
665 \texttt{mytest}.
666 \interaction{bisect.search.step2}
667 Unas invocaciones más de nuestra prueba, y hemos terminado.
668 \interaction{bisect.search.rest}
670 Aunque teníamos unos~40 conjuntos de cambios en los cuales buscar, la
671 orden \hgcmd{bisect} nos permitió encontrar el conjunto de cambios que
672 introdujo el ``fallo'' con sólo cinco pruebas. Porque el número de
673 pruebas que la orden \hgcmd{bisect} ejecuta crece logarítmicamente con
674 la cantidad de conjuntos de cambios a buscar, la ventaja que esto
675 tiene frente a la búsqueda por``fuerza bruta'' crece con cada
676 conjunto de cambios que usted adicione.
678 \subsection{Limpieza después de la búsqueda}
680 Cuando haya terminado de usar la orden \hgcmd{bisect} en un
681 repositorio, puede usar la orden \hgcmdargs{bisect}{reset} para
682 deshacerse de la información que se estaba usando para lograr la
683 búsqueda. Lar orden no usa mucho espacio, así que no hay problema si
684 olvida ejecutar la orden. En todo caso, \hgcmd{bisect} no le
685 permitirá comenzar una nueva búsqueda sobre el repositorio hasta que
686 no aplique \hgcmdargs{bisect}{reset}.
687 \interaction{bisect.search.reset}
689 \section{Consejos para encontrar fallos efectivamente}
691 \subsection{Dar una entrada consistente}
693 La orden \hgcmd{bisect} requiere que usted ofrezca un reporte correcto
694 del resultado de cada prueba que aplique. Si usted le dice que una
695 prueba falla cuando en realidad era acertada, \emph{podría} detectar
696 la inconsistencia. Si puede identificar una inconsistencia en sus
697 reportes, le dirá que un conjunto de cambios particular es a la vez
698 bueno y malo. Aunque puede no hacerlo; estaría tratando de reportar
699 un conjunto de cambios como el responsable de un fallo aunque no lo
700 sea.
702 \subsection{Automatizar tanto como se pueda}
704 Cuando comencé a usar la orden \hgcmd{bisect}, intenté ejecutar
705 algunas veces las pruebas a mano desde la línea de comandos. Es una
706 aproximación a la cual no esta acostumbrado. Después de algunos
707 intentos, me di cuenta que estaba cometiendo tantas equivocaciones que
708 tenía que comenzar de nuevo con mis búsquedas varias veces antes de
709 llegar a los resultados deseados.
711 Mi problema inicial al dirigir a la orden \hgcmd{bisect} manualmente
712 ocurrieron incluso con búsquedas en repositorios pequeños; si el
713 problema que está buscando es más sutil, o el número de pruebas que
714 \hgcmd{bisect} debe aplicar, la posibilidad de errar es mucho más
715 alta. Una vez que comencé a automatizar mis pruebas, obtuve mejores
716 resultados.
718 La clave para las pruebas automatizadas se puede resumir en:
719 \begin{itemize}
720 \item pruebe siempre buscando el mismo síntoma y
721 \item ofrezca siempre datos consistentes a la orden \hgcmd{bisect}.
722 \end{itemize}
723 En mi tutorial de ejemplo anterior, la orden \command{grep} busca el
724 síntoma, y la construcción \texttt{if} toma el resultado de esta
725 prueba y verifica que siempre alimentamos con los mismos datos a la
726 orden \hgcmd{bisect}. La función \texttt{mytest} los une de una forma
727 reproducible, logrando que cada prueba sea uniforme y consistente.
729 \subsection{Verificar los resultados}
731 Dado que la salida de la búsqueda de \hgcmd{bisect} es tan buena como
732 los datos ofrecidos por usted, no confíe en esto como si fuera la
733 verdad absoluta. Una forma sencilla de asegurarse es ejecutar
734 manualmente su prueba a cada uno de los siguientes conjuntos de
735 cambios:
736 \begin{itemize}
737 \item El conjunto de cambios que se reportó como la primera versión
738 erronea. Su prueba debería dar un reporte de fallo.
739 \item El conjunto de cambios padre (cada padre, si es una fusión).
740 Su prueba debería reportar este(os) conjunto(s) de cambios como
741 bueno(s).
742 \item Un hijo del conjunto de cambios. Su prueba debería reportar al
743 conjunto de cambios hijo como malo.
744 \end{itemize}
746 \subsection{Tener en cuenta la interferencia entre fallos}
748 Es posible que su búsqueda de un fallo pueda viciarse por la presencia
749 de otro. Por ejemplo, digamos que su programa se revienta en la
750 revisión 100, y que funcionó correctamente en la revisión 50. Sin su
751 conocimiento, alguien introdujo un fallo con consecuencias grandes en
752 la revisión 60, y lo arregló en la revisión 80. Sus resultados
753 estarían distorcionados de una o muchas formas.
755 Es posible que este fallo ``enmascare'' completamente al suyo, y que
756 podría haberse revelado antes de que su propio fallo haya tenido
757 oportunidad de manifestarse. Si no puede saltar el otro fallo (por
758 ejemplo, este evita que su proyecto se arme o compile), y de esta
759 forma no se pueda revisar si su fallo esté presente en un conjunto
760 particular de cambios, la orden \hgcmd{bisect} no podrá ayudarle
761 directamente. En cambio, puede marcar este conjunto de cambios como
762 al ejecutar \hgcmdargs{bisect}{--skip}.
764 Un problema distinto podría surgir si su prueba de la presencia de un
765 fallo no es suficientemente específica. Si usted busca ``mi programa
766 se revienta'', entonces tanto su fallo como el otro fallo sin relación
767 que terminan presentando síntomas distintos, podría terminar
768 confundiendo a \hgcmd{bisect}.
770 Otra situación en la cual sería de mucha utilidad emplear a
771 \hgcmdargs{bisect}{--skip} surge cuando usted no puede probar una
772 revisión porque su proyecto estaba en una situación de rompimiento y
773 por lo tanto en un estado en el cual era imposible hacer la prueba en
774 esa revisión, tal vez porque alguien consignó un cambio que hacía
775 imposible la construcción del proyecto.
777 \subsection{Acotar la búsqueda perezosamente}
779 Elegir los primeros ``buenos'' y ``malos'' conjuntos de cambios que
780 marcarán los límites de su búsqueda en general es sencillo, pero vale
781 la pena discutirlo. Desde la perspectiva de \hgcmd{bisect}, el
782 conjunto de cambios ``más nuevo'' por convención es el ``malo'', y el
783 otro conjunto de cambios es el ``bueno''.
785 Si no recuerda cuál podría ser el cambio ``bueno'', para informar a
786 \hgcmd{bisect}, podría hacer pruebas aleatorias en el peor de los
787 casos. Pero recuerde eliminar aquellos conjuntos de cambios que
788 podrían no exhibir el fallo (tal vez porque la característica donde se
789 presenta el fallo todavía no está presente) y aquellos en los cuales
790 otro fallo puede enmascararlo (como se discutió anteriormente).
792 Incluso si termina ``muy atrás'' por miles de conjuntos de cambios o
793 meses de historial, solamente estaŕa adicionando unas pruebas contadas
794 para \hgcmd{bisect}, gracias al comportamiento logarítmico.
796 %%% Local Variables:
797 %%% mode: latex
798 %%% TeX-master: "00book"
799 %%% End: