Solucione los conflictos solo una vez con git rerere

Así que resolvió un conflicto en algún lugar de su repositorio y luego tropezó exactamente con el mismo (tal vez hizo otra fusión, o terminó reformulando en su lugar, o seleccionó el compromiso erróneo en otro lugar …). Y, golpe, tenías que arreglar ese mismo conflicto otra vez.

Eso apesta.

Especialmente cuando Git es tan amable que ofrece un mecanismo para ahorrarle esa tarea, al menos la mayor parte del tiempo: revivir . Aceptar, por lo que el nombre es pésimo, pero en realidad significa Re utilizar la solución con cable Re Re, ya sabes.

En este artículo, trataremos de profundizar en cómo funciona, cuáles son sus límites y cómo sacarle el mejor provecho.

El sospechoso habitual: control se funde

Una situación en la que el entrenamiento resulta muy útil es el control de fusiones.

Imagine esto: está trabajando en una sucursal de larga vida; tal vez una rama de características pesadas. Llamémoslo de larga vida . Y, naturalmente, a medida que pasa el tiempo, te vuelves cada vez más aprensivo de fusionar eventualmente esta rama en la rama principal de desarrollo (generalmente master ), porque con el paso del tiempo la espesura se complica …

Así que para aliviar algo de esa tensión y facilitar la fusión final a la que te diriges, decides realizar una fusión de control de vez en cuando: una fusión de maestro en tu propia rama, de modo que sin contaminar al maestro puedas ver qué conflictos son al acecho, y averiguar si son difíciles de arreglar.

De hecho, es útil, y para que no tengas que arreglar esto más tarde, estarías tentado de dejar esa combinación de control en el árbol una vez que hayas terminado con ella, en lugar de deshacerla con, digamos, un reinicio de git –hard ORIG_HEAD y mantén tu gráfico prístino.

A medida que pasa el tiempo, obtienes un gráfico que se ve así, pero peor:

El control se funde contaminando su gráfico histórico

Esto es feo y contamina tu historial gráfico en todas las sucursales. Después de todo, una fusión solo debería ocurrir para fusionar una rama finalizada en.

Pero si cancelas esa combinación de control una vez que hayas terminado, tendrás que volver a arreglar estos conflictos la próxima vez que realices una fusión de control, sin mencionar la fusión final hacia el maestro . Entonces, ¿qué debe hacer un desarrollador?

rescatar al rescate

Esto es exactamente para lo que es rerere . Esta característica de Git toma una huella digital de cada conflicto, y lo empareja con una huella dactilar corregida correspondiente cuando se finaliza la confirmación problemática.

Más adelante, si un conflit coincide con la primera huella dactilar, rerere utilizará automágicamente la corrección correspondiente.

Habilitando rerere

Rerere no es solo un comando, sino un comportamiento transversal de Git. Para que esté activo, necesita al menos una de las dos condiciones que debe cumplir:

  • La configuración de configuración rerere.enabled se establece en true
  • Su repositorio contiene una base de datos nueva (usted tiene un directorio .git / rr-cache )

No puedo entender una situación en la que habilitar Rerere sea ??una mala idea, por lo que te recomiendo que la habilites globalmente:

 git config --global rerere.enabled true 

Un conflicto aparece

Digamos que ahora enfrenta una divergencia de conflicto; quizás el maestro cambió su <title> en index.html de cierta manera, y de larga duración lo hizo de otra manera.

Probemos una fusión de control:

 (de larga vida) $ git merge master 

Su primer conflicto habilitado de nuevo. Observe la tercera línea.

Esto se parece a su conflicto habitual, pero preste atención a la tercera línea:

 Preimagen grabada para 'index.html' 

Esto nos dice que la historia levantó una huella dactilar de nuestro conflicto. Y, de hecho, si le preguntamos a qué archivos está prestando atención en este caso, nos dirá:

 (larga vida * + | FUSIÓN) $ git rerere status 
index.html

Si miramos en nuestro repositorio, de hecho, encontraremos el archivo de huella digital:

 $ tree .git / rr-cache 
.git / rr-cache
??? f08b1f478ffc13763d006460a3cc892fa3cc9b73
??? preimagen

Este archivo de preimagen contiene la huella digital completa del archivo y su conflicto (todo el blob , si lo desea).

Grabando la corrección

OK, entonces arreglemos este conflicto. Por ejemplo, iré con el siguiente título combinado:

 ... 
<head>
<meta charset = "utf-8">
<title> 20% más fresco y título más sólido </ title>
</ head>
...

A continuación, puedo comprobar lo rerere recordará una vez que complete la combinación:

 $ git rerere diff 
--- a / index.html
+++ b / index.html
@@ -2,11 +2,7 @@
<html>
<head>
<meta charset = "utf-8">
- <<<<<<<
- <título> 20% título más frío </ title>
- =======
- <title> Título más sólido </ title>
- >>>>>>>
+ <título> 20% más fresco y título más sólido </ title>
</ head>
<cuerpo>
<h1> Título base </ h1>

Puedo marcar esto como arreglado de la manera habitual, con un git add . Luego, gitrerere remaining me dirá qué otros archivos debería examinar (en este momento, ninguno).

En cualquier caso, para recordar de manera efectiva la solución, necesito finalizar el compromiso actual. Al ser una fusión, me corresponde a mí realizar manualmente la confirmación:

 (de larga vida + | FUSIÓN) $ git commit --no-edit 
Resolución grabada para 'index.html'
[longevidad fcd883f] Fusionar rama 'maestro' en longevidad
(de larga vida) $

Presta atención a la segunda línea:

 Resolución grabada para 'index.html' 

Y, de hecho, esa instantánea de corrección ahora es una imagen posterior en nuestro repositorio:

 $ tree .git / rr-cache 
.git / rr-cache
??? f08b1f478ffc13763d006460a3cc892fa3cc9b73
??? postimagen
??? preimagen

Así que puedo seguir adelante y deshacer esa fusión de control , porque no quiero contaminar mi historial gráfico con ella:

 (de larga vida) $ git reset --hard HEAD ^ 
HEAD ahora es b8dd02b 20% más cool title
(de larga vida) $

El conflicto vuelve a emerger

Supongamos ahora que los de larga vida y los maestros siguen avanzando. Quizás en el primero, aparece un CSS. Y en este último, aparece el mismo CSS (aunque con diferentes contenidos), junto con un archivo JS.

Llega el momento en que una nueva fusión de control parece estar en orden. Aquí vamos:

 (de larga vida) $ git merge master 
Auto-fusión style.css
CONFLICTO (agregar / agregar): combinar conflicto en style.css
Combinación automática de index.html
CONFLICTO (contenido): Combina conflicto en index.html
Preimagen grabada para 'style.css'
Se resolvió 'index.html' utilizando la resolución anterior.
La fusión automática falló; arregla los conflictos y luego compromete el resultado.
(larga vida * + | FUSIÓN) $

Tenemos un conflicto de agregar / agregar para el CSS y el conocido conflicto de index.html . Pero mira más de cerca al final:

 Preimagen grabada para 'style.css' 
Se resolvió 'index.html' utilizando la resolución anterior.

Como puede ver, el conflicto sobre index.html ya se conoce y se ha corregido automáticamente. De hecho, si le preguntas a git rerere que queda lo que pasa, te dirá que solo style.css todavía está en problemas.

Comencemos por marcar index.html como correcto, organizándolo:

 $ git add index.html 

Por cierto, si prefiere volver a auto-escenificar los archivos que resolvió (sí), puede solicitarlo: solo necesita ajustar su configuración de la siguiente manera:

 $ git config --global rerere.autoupdate true 

A partir de ahora, consideraré que tienes esta configuración activada. Como lo hicimos antes, arreglemos el conflicto restante, y luego:

 (de larga duración * + | FUSIÓN) $ git commit -a --no-edit 
Resolución grabada para 'style.css'.
[d6eea3e de larga vida] Fusionar rama 'maestro' en longevidad
(de larga vida) $

Ahora tenemos dos pares de huellas dactilares disponibles, incluida una en style.css :

 $ tree .git / rr-cache 
.git / rr-cache
??? d8cd8c78a005709a8aac404d46f23d6e82b12aee
??? ??? postimagen
??? ??? preimagen
??? f08b1f478ffc13763d006460a3cc892fa3cc9b73
??? postimagen
??? preimagen

Y podemos deshacer ese compromiso, como antes.

Para concluir, supongamos que index.html se modifica por última vez, agregando contenido cerca del final de <body> . Entonces lo cometemos.

Este fue el último compromiso necesario para una vida larga , por lo que en lugar de hacer otra fusión de control, decidimos hacer la fusión final y adecuada en el maestro :

 (maestro) $ git merge longevo 
Auto-fusión style.css
CONFLICTO (agregar / agregar): combinar conflicto en style.css
Combinación automática de index.html
CONFLICTO (contenido): Combina conflicto en index.html
Staged 'index.html' utilizando la resolución anterior.
Staged 'style.css' utilizando la resolución anterior.
La fusión automática falló; arregla los conflictos y luego compromete el resultado.
(maestro + | FUSIÓN) $

Tenga en cuenta que en lugar de "Resolvió … utilizando la resolución anterior" que teníamos antes, ahora obtenemos:

 Staged 'index.html' utilizando la resolución anterior. 
Staged 'style.css' utilizando la resolución anterior.

Esto se debe a que le pedimos a Rerere que realice la autoevaluación de los archivos completamente corregidos. Y, de hecho, mi mensaje solo menciona " +" (en escena), no "*" (modificado), lo que me lleva a pensar que no hay conflicto restante. Algo que restar restante confirma al no mostrar nada.

Por lo tanto, no necesita detenerse al ver "Falló la combinación automática" al final, esto solo significa que las estrategias de fusión regulares no fueron suficientes; pero debido a que habíamos ayudado nuevamente , podríamos seguir adelante. Sin embargo, debido a la heurística rerere no son 100% garantizado para ser relevante (el contexto podría haber cambiado …), Git se niegan a auto-finalizar una operación rerere ayudó a disminuir.

Para asegurarse de que fue arreglado adecuadamente, si tiene alguna duda, un simple git diff -staged o git show: 0: file (que es un cero, no una letra O) calmará sus miedos.

Todavía es tu trabajo completar la confirmación:

 (maestro + | FUSIÓN) $ git commit 

¿Usando Git con GitHub? ¿Quieres convertirte en un verdadero maestro de GitHub? ¡Lanzamos la primera parte de nuestra serie de entrenamiento de video GitHub, la mejor de su clase! 5 horas, 69 videos, ¡contenidos increíbles para principiantes y expertos por igual! Aprender más

Sin contexto

Debes recordar que las huellas dactilares son independientes del contexto:

  • No importa qué comando resultó en el par de huellas dactilares que se levantó ( fusión , rebase , selección de cereza , aplicación / pop de alijo , comprobación -m , etc.).
  • No importa qué comando vuelva a utilizar la corrección.
  • No importa en qué rutas estén los archivos conflictivos (lo que importa es el contenido de la instantánea).

Por otro lado, una huella dactilar solo se puede usar si se conservan los contextos inmediatos de sus diferencias, como es habitual en los conflictos de fusión. Si modificó una línea demasiado cercana a un diff en la preimagen , rerere se rehusará a considerar ese par de imagen + arreglo, y usted mismo tendrá que arreglar el nuevo contexto.

Además, si aparece un nuevo conflicto en un archivo que ya está orientado por pares de huellas dactilares para conflictos previos, el tema parece bastante estricto sobre sus reglas de aplicabilidad para las soluciones anteriores. Me resulta difícil determinar exactamente cuáles son sus umbrales de proximidad, pero bien puede ignorar las soluciones anteriores y decidir solicitar una nueva solución para todo el conjunto de conflictos en el archivo. Como de costumbre, YMMV.

¿No puedo compartir esto con otros contribuyentes?

Al igual que los hooks, la base de datos menor (el directorio .git / rr-cache ) permanece en su repositorio local: no se comparte con el flujo ascendente cuando se presiona (independientemente de las opciones y opciones de envío).

Y al igual que los ganchos, esto no significa que no pueda compartirlos con compañeros de trabajo y otros colaboradores del código si realmente lo desea (en realidad es una buena idea compartirlos). Hay varias opciones, generalmente basadas en enlaces simbólicos (enlaces simbólicos ).

Opción 1: incrustado en su directorio de trabajo

Puede dedicar absolutamente un directorio en su WD para compartir elementos que de lo contrario se mantienen locales en su repositorio, como rr-cache y hooks , por ejemplo.

Podrías crear un directorio llamado. git-system en la raíz de tu WD, en el que tienes subcarpetas. De esta forma, en su directorio .git , rr-cache sería un enlace simbólico en ../.git-system/rr-cache . En OSX / Linux / Git Bash, lo haría de la siguiente manera:

 # Crea la carpeta 
mkdir .git-system
 # Si su carpeta existe en el repositorio, muévala; 
# de lo contrario, créelo en su ubicación final
[-d .git / rr-cache] && mv .git / rr-cache .git-system / ||
mkdir .git-system / rr-cache
 # Crea el enlace simbólico 
ln -nfs ../.git-system/rr-cache

En Windows, esto se vería más como esto:

 mkdir .git-system 
 # La siguiente es una sola línea 
si existe .git rr-cache (mover .git rr-cache .git-system) else mkdir .git-system rr-cache
 mklink / d .git  rr-cache ... . git-system  rr-cache 

(Desde Windows Vista, el comando mklink le permite crear enlaces simbólicos, pero deberá ejecutarlo en un símbolo del sistema de privilegios elevados, es decir, uno se ejecutará como administrador. Su administración no es suficiente. O, su política de seguridad local) podría incluir su cuenta de usuario específica en la autorización Crear enlaces simbólicos. Porque, ya sabe, los enlaces simbólicos son para hackers malvados, ¿no? Más información en mklink aquí . Si tiene Windows XP o no quiere salir lastimado con las secuencias de comandos de Windows, simplemente ejecute el primer conjunto de comandos en el Git Bash instalado por su instalador de Git Windows).

Compartiendo sus configuraciones de repos locales, incrustadas en el directorio de trabajo. Esto requiere hacer malabarismos para mantener las cosas prolijamente separadas.

En tal situación, la idea no es incluir las nuevas huellas dactilares en la confirmación del arreglo original, manteniendo el contenido del sistema .git en su propia confirmación. Esto requiere algunos malabares con el hecho de que desea reiniciar las fusiones de control, pero conserve las huellas dactilares, solo después confirme. Una rebase de tres puntos ayuda con eso, por ejemplo:

 # 1. Asegúrate de no estar cometiendo .git-system por error 
(larga vida * + | FUSIÓN) $ git reset - .git-system
(larga vida * + | FUSIÓN) $ git commit --no-edit
 # 2. Comprometerse con el sistema .git 
(de larga duración *) $ git add .git-system
(longevo +) $ git commit -m "Arreglar las huellas dactilares para control merge"
 # 3. Reescribir el historial para conservar solo el último de los 2 commits. 
(de larga vida) $ git rebase --onto CABEZA ~ 2 CABEZA ^

Opción 2: un repositorio de intercambio local dedicado

El otro enfoque, que evita el malabarismo de los commits pero hace que compartir un proceso de dos pasos, es tener un repo (y upstream para compartir, obviamente) dedicado a compartir configuraciones que de otro modo se mantendrían localmente.

Solo cambiaría el objetivo de su enlace simbólico a algo más fijo y absoluto, idealmente un subdirectorio de su repositorio de intercambio central, algo como:

  • ~ / .git-shared-locals / your-project / rr-cache en OSX / Linux, o
  • C: Users you git-shared-locals your-project rr-cache en Windows.

Compartiendo sus configuraciones de repos locales, a través de un repositorio dedicado y separado. Sin cometer malabares, sino compartir en dos pasos.

De esa manera, no introduce ningún contenido adicional en su directorio de trabajo debido a la toma de huellas dactilares. Sin cometer malabares. Es solo que, para compartir tus huellas dactilares, también deberías ir al repositorio central para compartir, cometer esto, hacer un retiro rápido –rebase para obtener las configuraciones compartidas nuevas en el servidor y reproducir tus cosas nuevas en la parte superior de eso, luego git push para compartirlo con tus amigos.

(Esta es la segunda vez que hablamos de rebase en este artículo, si está confundido acerca de cuándo fusionar vs. rebase, y qué cosas tan extrañas como las rebases de tres puntos son, lo tenemos cubierto ).

Esto es en dos pasos, pero elimina el riesgo de errores al mezclar las huellas digitales de preimagen con arreglos, etc.

¿Querer aprender más?

Escribí varios artículos de Git , y podría estar particularmente interesado en los siguientes:

Además, si disfrutaste esta publicación, dilo: ¡lo has votado en HN ! ¡Gracias un montón!

Aunque no publicitamos mucho por el momento, sí ofrecemos capacitación de Git en inglés en toda Europa, en base a nuestro curso de capacitación Total Git probado en la batalla. Si te apetece uno, solo háznoslo saber !

(Podemos ir a EE. UU./ Canadá o a cualquier otro lugar del mundo, pero teniendo en cuenta que incurrirá en nuestros costos de viaje, a pesar de que tenemos un precio muy razonable, es probable que encuentre un trato más rentable utilizando un servicio más cercano proveedor, ya sea GitHub u otra persona. Aun así, si usted nos quiere , ¡siga el enlace de arriba y hablemos!)

Hacker Noon es cómo los hackers comienzan sus tardes. Somos parte de la familia @AMI . Ahora estamos aceptando presentaciones y estamos felices de conversar sobre oportunidades de publicidad y patrocinio .

Si disfrutaste esta historia, te recomendamos que leas nuestras últimas historias tecnológicas e historias tecnológicas de tendencia . Hasta la próxima, ¡no des por sentado las realidades del mundo!