Lección 23 · Recuperación
Resolver conflictos de fusión y cambio de base
Resuelva el mismo titular en competencia en una fusión y en una rebase, vea por qué "nuestro" y "de ellos" se intercambian, guarde un resultado combinado deliberado y finalice cada operación sin perder la idea de ninguna de las personas.
- Nivel: Intermedio
- 13 minutos de lectura
- 7 minutos de vídeo
- Actualizado
- Antes de esta lección: Fusionar ramas con historia divergente, Cambiar la base del trabajo inédito sobre una nueva base
Progreso guardado en este navegador.
La reproducción carga el vídeo de YouTube (modo de privacidad mejorada).
lo que aprenderás
- Lea un conflicto real: la base, el bando actual y el bando entrante.
- Explique por qué "nuestro" y "de ellos" intercambian entre una fusión y una rebase.
- Escriba una resolución deliberada y luego márquela resuelta.
- Continuar la operación y comprobar que no queda nada a medio hacer.
Antes de empezar
Dos compañeros cambiaron la misma línea de la página. El conflict/sara, Sara cambió el encabezado principal a "Revisar cambios con confianza". El conflict/omar, Omar cambió la misma línea a "Comprender cada cambio guardado". Ambas ramas comienzan desde la confirmación M, donde el encabezado era "Vea su trabajo con claridad", y cada rama tiene exactamente una confirmación. Haces dos copias idénticas de esta divergencia: una para la fusión (gittree-conflict-merge) y otra para la rebase (gittree-conflict-rebase). En ambos, conflict/sara está desprotegido y el árbol de trabajo está limpio. No se está ejecutando ninguna fusión ni rebase.
Todo es local y en el plan gratuito (GitTree te pide que inicies sesión): sin cuenta de alojamiento, sin proveedor, sin Internet. Toda identidad es ficticia (ejemplo.com). Nunca ejecute esta lección en un proyecto real.
Realice los cambios en GitTree o con los comandos nativos de Git, no ambos en la misma copia. Leer el resultado siempre es seguro. Las etiquetas del menú provienen de las propias cadenas de GitTree 2.0 y los comandos nativos se ejecutaron con Git 2.43 en copias desechables. Los pasos GitTree no se ejecutaron en macOS, Windows o Linux.
Efectos de concepto y estado.
Un conflicto de contenido significa que Git no puede elegir un resultado por sí solo: ambas partes cambiaron las mismas líneas de manera diferente. Git se detiene y mantiene tres versiones del archivo en el índice: la etapa 1 es la base común, la etapa 2 es "nuestra" y la etapa 3 es "de ellos". También escribe marcadores de conflicto en el archivo de su árbol de trabajo. Eliminar los marcadores en un editor no resuelve nada para Git: el archivo se resuelve solo cuando guarda el resultado y lo prepara, lo que devuelve la etapa 0.
"Nuestras" y "de ellos" son posiciones, no personas. En una fusión estás en la rama de Sara, por lo que la nuestra es la versión de Sara (el lado actual) y la de ellos es la de Omar (el lado entrante). En una rebase de Sara en Omar, Git primero se mueve a la rama de Omar y luego reproduce la confirmación de Sara, por lo que la nuestra es la versión de Omar (la rama en la que estás rebasando) y la de ellos es la versión de Sara. GitTree imprime el rol al lado de cada nombre para que no tengas que recordar: "(actual)" y "(entrante)" en una combinación, "(rebase en)" y "(tu compromiso)" en una rebase.
El resultado correcto rara vez es de un lado. Aquí la resolución que se pretende es “Revisar cada cambio con confianza”, ni la línea de Sara ni la de Omar. Mantenga cada dos líneas de la página exactamente como estaba. Marcar el archivo resuelto prepara el resultado; continuar es un paso independiente que finaliza el compromiso de fusión o recrea el compromiso de Sara en el de Omar.
Mientras la operación está detenida, la rama está donde la dejó la operación y el archivo está en conflicto. Nada llega a un servidor.
Prepare el estado exacto del proyecto
Haz una divergencia y luego cópiala dos veces. Comience con una copia normal separada del proyecto tal como lo dejó la lección 18 y deje su gittree-features original intacto. Las versiones de la página se encuentran a continuación: FUSIONADA es la base compartida, SARA y OMAR son las dos versiones en competencia y RESUELTA es el resultado que guardará.
Entradas de archivos completas
Guarde solo en la fase que se menciona a continuación. Estos son cuerpos UTF-8/LF completos con una nueva línea final; Nunca pegues vallas Markdown. Los archivos ejecutables sin cambios heredan la entrada nombrada. Las versiones en variantes separadas no deben sobrescribir el original.
index.html — FUSIONADO
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GitTree Features — course demo</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="site-header">
<a href="#main">GitTree Features</a>
</header>
<main id="main" tabindex="-1">
<section class="hero" aria-labelledby="hero-title">
<p class="eyebrow">GitTree Learn demo project</p>
<h1 id="hero-title">See your work clearly.</h1>
<p id="hero-copy">Choose one change, then check what Git saved.</p>
</section>
<section class="features" aria-labelledby="features-title">
<h2 id="features-title">Follow your work</h2>
<div class="cards">
<article class="feature-card">
<h3>History</h3>
<p>Read commits and branches together.</p>
</article>
<article class="feature-card">
<h3>Changes</h3>
<p>Review the exact content selected for a commit.</p>
</article>
<article class="feature-card">
<h3>Recovery</h3>
<p>Inspect the scope of a recovery point before using it.</p>
</article>
</div>
</section>
<section aria-labelledby="plans-title">
<h2 id="plans-title">Choose the workflow you need</h2>
<div class="cards">
<article class="feature-card">
<h3>Local Git</h3>
<p>Local Git workflows work without signing in.</p>
</article>
<article class="feature-card">
<h3>Connected workflows</h3>
<p>Provider integrations and Nour require Pro or an applicable trial.</p>
</article>
</div>
</section>
</main>
<footer><p>Built by a fictional team for GitTree Learn. Review one change at a time.</p></footer>
<script type="module" src="site.js"></script>
</body>
</html>index.html — SARA
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GitTree Features — course demo</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="site-header">
<a href="#main">GitTree Features</a>
</header>
<main id="main" tabindex="-1">
<section class="hero" aria-labelledby="hero-title">
<p class="eyebrow">GitTree Learn demo project</p>
<h1 id="hero-title">Review changes with confidence.</h1>
<p id="hero-copy">Choose one change, then check what Git saved.</p>
</section>
<section class="features" aria-labelledby="features-title">
<h2 id="features-title">Follow your work</h2>
<div class="cards">
<article class="feature-card">
<h3>History</h3>
<p>Read commits and branches together.</p>
</article>
<article class="feature-card">
<h3>Changes</h3>
<p>Review the exact content selected for a commit.</p>
</article>
<article class="feature-card">
<h3>Recovery</h3>
<p>Inspect the scope of a recovery point before using it.</p>
</article>
</div>
</section>
<section aria-labelledby="plans-title">
<h2 id="plans-title">Choose the workflow you need</h2>
<div class="cards">
<article class="feature-card">
<h3>Local Git</h3>
<p>Local Git workflows work without signing in.</p>
</article>
<article class="feature-card">
<h3>Connected workflows</h3>
<p>Provider integrations and Nour require Pro or an applicable trial.</p>
</article>
</div>
</section>
</main>
<footer><p>Built by a fictional team for GitTree Learn. Review one change at a time.</p></footer>
<script type="module" src="site.js"></script>
</body>
</html>index.html — OMAR
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GitTree Features — course demo</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="site-header">
<a href="#main">GitTree Features</a>
</header>
<main id="main" tabindex="-1">
<section class="hero" aria-labelledby="hero-title">
<p class="eyebrow">GitTree Learn demo project</p>
<h1 id="hero-title">Understand each saved change.</h1>
<p id="hero-copy">Choose one change, then check what Git saved.</p>
</section>
<section class="features" aria-labelledby="features-title">
<h2 id="features-title">Follow your work</h2>
<div class="cards">
<article class="feature-card">
<h3>History</h3>
<p>Read commits and branches together.</p>
</article>
<article class="feature-card">
<h3>Changes</h3>
<p>Review the exact content selected for a commit.</p>
</article>
<article class="feature-card">
<h3>Recovery</h3>
<p>Inspect the scope of a recovery point before using it.</p>
</article>
</div>
</section>
<section aria-labelledby="plans-title">
<h2 id="plans-title">Choose the workflow you need</h2>
<div class="cards">
<article class="feature-card">
<h3>Local Git</h3>
<p>Local Git workflows work without signing in.</p>
</article>
<article class="feature-card">
<h3>Connected workflows</h3>
<p>Provider integrations and Nour require Pro or an applicable trial.</p>
</article>
</div>
</section>
</main>
<footer><p>Built by a fictional team for GitTree Learn. Review one change at a time.</p></footer>
<script type="module" src="site.js"></script>
</body>
</html>index.html — RESUELTO
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GitTree Features — course demo</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="site-header">
<a href="#main">GitTree Features</a>
</header>
<main id="main" tabindex="-1">
<section class="hero" aria-labelledby="hero-title">
<p class="eyebrow">GitTree Learn demo project</p>
<h1 id="hero-title">Review each change with confidence.</h1>
<p id="hero-copy">Choose one change, then check what Git saved.</p>
</section>
<section class="features" aria-labelledby="features-title">
<h2 id="features-title">Follow your work</h2>
<div class="cards">
<article class="feature-card">
<h3>History</h3>
<p>Read commits and branches together.</p>
</article>
<article class="feature-card">
<h3>Changes</h3>
<p>Review the exact content selected for a commit.</p>
</article>
<article class="feature-card">
<h3>Recovery</h3>
<p>Inspect the scope of a recovery point before using it.</p>
</article>
</div>
</section>
<section aria-labelledby="plans-title">
<h2 id="plans-title">Choose the workflow you need</h2>
<div class="cards">
<article class="feature-card">
<h3>Local Git</h3>
<p>Local Git workflows work without signing in.</p>
</article>
<article class="feature-card">
<h3>Connected workflows</h3>
<p>Provider integrations and Nour require Pro or an applicable trial.</p>
</article>
</div>
</section>
</main>
<footer><p>Built by a fictional team for GitTree Learn. Review one change at a time.</p></footer>
<script type="module" src="site.js"></script>
</body>
</html>En GitTree
Abra la paleta con Comando+Mayús+P (Ctrl+Mayús+P en Ubuntu). Las acciones en una rama con nombre utilizan el menú contextual de esa rama.
- Construya las dos copias como se muestra en la siguiente sección. Abra gittree-conflict-merge, con
conflict/saradesprotegido. - Haga clic derecho en
conflict/omary elija Merge conflict/omar into conflict/sara. En Record it as elige Always a merge commit. El cuadro de diálogo advierte "Se detendrá con un conflicto en 1 archivo"; elija Merge. La fusión se detiene, que es el resultado esperado. - El banner dice "Fusionando conflicto/omar en conflicto/sara" con "1 conflicto" y Continue aún no está disponible: "Resolver los 1 conflictos primero". Elija Resolve.
- Abra
index.htmldesde Conflicted files. Lea los dos lados, conflict/sara (current) y conflict/omar (incoming), y use Show Base para leer el Base (common ancestor). - Elija Edit Output, reemplace el encabezado conflictivo con
Review each change with confidence.y mantenga cada dos líneas. Luego elija Save and Mark Resolved. No basta con borrar los marcadores y cerrar el archivo. - De vuelta en el banner, elija Continue. Si se ofrece un mensaje, conservar el propuesto. Espere a que finalice la fusión: la nueva confirmación tiene dos padres.
- Abra gittree-conflict-rebase, con
conflict/saradesprotegido. Haga clic derecho enconflict/omary elija Rebase conflict/sara onto conflict/omar. Deje desactivadas las opciones de Options for this rebase y luego elija Rebase conflict/sara. Se detiene con un conflicto. - Elija Resolve y abra
index.html. Los bandos ahora son conflict/omar (rebasing onto) y conflict/sara (your commit): los roles se intercambiaron. Haz lo mismo Edit Output → Save and Mark Resolved, luego Continue. - Verifique ambas copias: el archivo es RESUELTO, no queda ningún archivo en conflicto y no se muestra ningún banner. Mantenga los dos resultados separados y no presione.
Para cada confirmación ordinaria del curso: Summary es el asunto indicado, Description está vacío y las opciones Amend Previous Commit, Skip Hooks, Add Signed-off-by, Different Author, Push After Commit y Allow Empty Commit permanecen desactivadas.
en la terminal
En una copia limpia separada del resultado de la lección 18:
git switch --create conflict/sara
BASE_SHA="$(git rev-parse HEAD)"Guarde SARA como index.html y luego:
git add -- index.html
git -c user.name="Sara Lindqvist" -c user.email=sara@example.com commit --quiet -m "feat: Sara clarifies the hero"
git switch --quiet --create conflict/omar "$BASE_SHA"Guarde OMAR como index.html y luego:
git add -- index.html
git -c user.name="Omar Haddad" -c user.email=omar@example.com commit --quiet -m "feat: Omar explains the hero"
git switch --quiet conflict/saraBASE_SHA es M, antes de cualquier confirmación competitiva. Haga dos copias limpias de esta divergencia, una para la fusión y otra para la rebase (cd .. && cp -R gittree-features gittree-conflict-merge && cp -R gittree-features gittree-conflict-rebase). En la copia combinada:
git merge --no-ff --no-edit conflict/omar
git ls-files --unmerged
git show :2:index.html
git show :3:index.htmlLa fusión se detiene con el código de salida 1 y git ls-files --unmerged enumera tres entradas, etapas 1, 2 y 3. git show :2:index.html es la versión de Sara (la nuestra) y :3: es la de Omar (la de ellos); :1: es la base. Guarde RESUELTO como index.html y luego:
git add -- index.html
git -c core.editor=true merge --continue
git ls-files --unmerged
git status --shortLos dos últimos comandos no imprimen nada. En la copia rebase intacta:
git rebase conflict/omar
git show :2:index.html
git show :3:index.htmlLa rebase se detiene. Ahora :2: es la versión de Omar y :3: es la de Sara: se intercambiaron los roles. Guarde RESUELTO como index.html, luego:
git add -- index.html
git -c core.editor=true rebase --continue
git ls-files --unmerged
git status --shortAmbos archivos ahora son RESUELTOS y no hay nada sin fusionar. core.editor=true solo acepta el mensaje de confirmación existente para este comando; no cambia la configuración de su editor. Para dejar una operación detenida sin resolver, use git merge --abort o git rebase --abort.
Resultado
Where you end: la copia fusionada tiene una nueva confirmación con dos padres y el encabezado combinado; la copia rebase tiene el compromiso de Sara recreado en el de Omar con el mismo encabezado combinado. En ambos, index.html es igual a RESUELTO, no queda ninguna entrada de conflicto, la operación finaliza y el estado es limpio.
Errores comunes
- Asumir "nuestro" siempre significa tu propia característica. Significa el lado en el que se encuentra Git, y eso cambia con la operación.
- Tomando un lado al por mayor ("Take All") antes de leer ambas versiones y el resto del archivo.
- Eliminando los marcadores de conflicto pero nunca guardando y marcando el archivo resuelto.
- Repetir una fusión o rebase que ya finalizó.
Si algo sale mal
Si una detención parece incorrecta, Abort… del banner restaura el estado desde el que comenzó la operación y elimina las resoluciones realizadas hasta el momento; GitTree mantiene primero una instantánea de recuperación. Si el archivo cambió mientras lo editaba, use las opciones Compare y Use as Output en lugar de forzar un guardado anterior. Guarde una copia de su borrador antes de reemplazarlo.
Comprueba tu comprensión
Responda cada pregunta y luego lea por qué. Las preguntas marcadas como "Obligatorias" cuentan para completar la lección.
0 de 6 correcto
Responda correctamente las preguntas requeridas para completar la lección.
Comprobado en este navegador.
Practica
Pruebe los roles de etapa para ambas operaciones con git show :2:index.html y git show :3:index.html, luego guarde el mismo archivo RESUELTO y finalice cada operación. Predice lo que quedaría en la página si tomaras a ciegas "lo nuestro" en ambas copias.
Su propia confirmación: el sitio no puede ver su computadora.
Para completar la lección, responde correctamente a las preguntas requeridas y confirma el ejercicio práctico.
Resumen
- Los roles de nosotros y de ellos dependen de la operación.
- Guarde y marque resuelto primero, luego continúe.
- Verifique todo el archivo y el estado de la operación posteriormente.
Relacionado
Términos del glosario introducidos
Conflicto — تعارض; base—أساس; el nuestro—نسختنا; de ellos—نسختهم; resolver — حلّ.
Transcripción del vídeo
La narración del vídeo, cue a cue.
Mostrar la transcripción
- Un conflicto no es un error. es un pregunta que solo tú puedes responder.
- Dos personas cambiaron la misma línea del mismo archivo.
- Sara escribió un título. Omar escribió otro. Ambos partieron de la misma página.
- Git no puede adivinar qué línea gana, por lo que se detiene y te pregunta.
- Primero, construye las sucursales de Sara y Omar, y dos ejemplares idénticos.
- En la primera copia nos fusionamos. En el segundo, rebasemos.
- Abra la copia combinada, en la sucursal de Sara.
- Haga clic derecho en la rama de Omar y elija su Comando de fusión.
- El diálogo ya avisa: esto se detendrá con un conflicto en un archivo.
- Elija Siempre una confirmación de fusión, luego Fusionar una vez. Se detiene, como se esperaba.
- La pancarta muestra un conflicto. Continuar es Aún no está disponible.
- Elija Resolver y abra index.html.
- Dos lados: la sucursal de Sara está vigente, El de Omar está llegando.
- Show Base revela el ancestro común, el página antes de cualquier cambio.
- Ahora edite la salida. Reemplace el título con una línea deliberada.
- Guardar y marcar como resuelto. Sólo ahora Git trate el archivo como resuelto.
- De vuelta en el banner, elija Continuar. el fusionar termina.
- El nuevo compromiso tiene dos padres, y el título combinado.
- Ahora la copia rebase, también en Sara's rama.
- Haga clic derecho en la rama de Omar y vuelva a establecer la base. La rama de Sara sobre él.
- Deje las opciones desactivadas y vuelva a establecer la base una vez. eso se detiene con un conflicto.
- Mira las etiquetas. Ahora la sucursal de Omar es en el que nos rebasamos.
- El compromiso de Sara es el que se repite. Los roles se han intercambiado.
- Misma resolución: editar salida, luego guardar y Marcar resuelto, luego Continuar.
- El compromiso de Sara se recrea además de El de Omar, con el mismo título.
- En la terminal, enumere las entradas no fusionadas de una fusión detenida.
- La segunda etapa es nuestra: el rumbo de Sara. etapa tres es de ellos: el de Omar.
- En una rebase parada, etapas dos y tres son al revés.
- Después de la corrección, no se elimina nada y el estado está vacío.
- La sugerencia de la copia fusionada tiene dos padres; el La sugerencia de rebase copy tiene una.
- Cambiar la entrada: eliminar los marcadores y guarde, pero no marque resuelto.
- Git todavía ve tres etapas, así que Continuar permanece no disponible.
- ¿Atascado? Abortar devuelve la rama a donde comenzó la operación.
- GitTree guarda primero una instantánea de recuperación, por lo que incluso un aborto es seguro.
- Nunca tomes todo de un lado delante de ti. Lea ambas versiones.
- Práctica: demuestra los roles escénicos en ambos. copias, luego termine ambas.
- A continuación, continúe, omita o cancele una operación eso se ha detenido.