Git Pull: Ignorar cambios locales

GitGitBeginner
Practicar Ahora

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

Este tutorial ofrece una guía integral sobre el comando "git pull --ignore-unmerged", que te permite priorizar los cambios remotos sobre tus cambios locales en un repositorio de Git. Ya sea que estés trabajando en un proyecto con un equipo o necesites sincronizar rápidamente tu código local con el repositorio remoto, este tutorial te ayudará a entender los casos de uso, los beneficios y los posibles riesgos de utilizar este comando.

En este laboratorio (LabEx), aprenderás cómo configurar un repositorio de Git, crear cambios conflictivos y utilizar el comando git pull --ignore-unmerged para resolver conflictos. También explorarás enfoques alternativos para manejar conflictos en un flujo de trabajo de Git.

Configuración de un repositorio de Git

Antes de explorar los comandos de git pull, configuremos un simple repositorio de Git con el que trabajar. Esto te proporcionará un entorno práctico para entender cómo Git maneja los cambios y los conflictos.

Crear un nuevo repositorio

Primero, creemos un nuevo directorio para nuestro repositorio de Git. Abre tu terminal y ejecuta los siguientes comandos:

cd ~/project
mkdir git-pull-demo
cd git-pull-demo

Ahora, inicializa un repositorio de Git en este directorio:

git init

Deberías ver una salida similar a esta:

Initialized empty Git repository in /home/labex/project/git-pull-demo/.git/

Configurar la información del usuario de Git

Para realizar commits, Git necesita conocer tu identidad. Configura tu nombre de usuario y tu correo electrónico con los siguientes comandos:

git config --local user.name "Learner"
git config --local user.email "learner@example.com"

Crear y hacer commit de archivos iniciales

Creemos algunos archivos de muestra con los que trabajar. Primero, crea un simple archivo de texto:

echo "## Git Pull Demo" > README.md
echo "This is the first line of the file." > file1.txt

Ahora, agrega estos archivos al área de staging y realiza tu primer commit:

git add README.md file1.txt
git commit -m "Initial commit"

La salida debería verse así:

[main (root-commit) xxxxxxx] Initial commit
 2 files changed, 2 insertions(+)
 create mode 100644 README.md
 create mode 100644 file1.txt

¡Felicidades! Has creado con éxito un repositorio de Git con un commit inicial. Veamos el estado de nuestro repositorio:

git status

Deberías ver:

On branch main
nothing to commit, working tree clean

Esto indica que todos tus cambios han sido confirmados. Ahora tienes un repositorio de Git funcional con el que trabajar en los siguientes pasos.

Simulación de un repositorio remoto

Para entender cómo funciona git pull, necesitamos simular un repositorio remoto. En un escenario del mundo real, este sería un repositorio alojado en plataformas como GitHub, GitLab o Bitbucket. Para este laboratorio (LabEx), crearemos un directorio local que actuará como nuestro repositorio "remoto".

Crear un repositorio "remoto"

Creemos un repositorio bare (sin directorio de trabajo) que actuará como nuestro remoto:

cd ~/project
mkdir remote-repo.git
cd remote-repo.git
git init --bare

Deberías ver:

Initialized empty Git repository in /home/labex/project/remote-repo.git/

Un repositorio bare es un repositorio de Git que no tiene directorio de trabajo. Está diseñado para ser un repositorio central al que se pueden enviar (push) y recibir (pull) cambios.

Conectar tu repositorio local al remoto

Ahora, regresa a tu repositorio local y agrega el remoto:

cd ~/project/git-pull-demo
git remote add origin ~/project/remote-repo.git

Enviar tus cambios al remoto

Envía tus cambios locales al repositorio remoto:

git push -u origin main

La salida debería verse así:

Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 2 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (4/4), 279 bytes | 279.00 KiB/s, done.
Total 4 (delta 0), reused 0 (delta 0)
To /home/labex/project/remote-repo.git
 * [new branch]      main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.

Este comando envía tu rama local main al repositorio remoto y configura el seguimiento entre tus ramas locales y remotas con la bandera -u.

Verificar la conexión

Para verificar que tu repositorio local está correctamente conectado al remoto, ejecuta:

git remote -v

Deberías ver:

origin  /home/labex/project/remote-repo.git (fetch)
origin  /home/labex/project/remote-repo.git (push)

Esto muestra que tu repositorio local está conectado al repositorio remoto con el nombre "origin".

Ahora que hemos configurado nuestros repositorios local y remoto, podemos continuar para entender cómo manejar conflictos y usar el comando git pull --ignore-unmerged.

Creación de cambios conflictivos

En este paso, crearemos un escenario en el que los cambios en el repositorio remoto entren en conflicto con tus cambios locales. Esto nos ayudará a entender cómo Git maneja los conflictos y por qué el comando git pull --ignore-unmerged puede ser útil.

Crear una nueva clonación del repositorio

Primero, creemos una segunda clonación de nuestro repositorio para simular que un miembro del equipo está realizando cambios:

cd ~/project
git clone remote-repo.git team-member-repo
cd team-member-repo

Deberías ver:

Cloning into 'team-member-repo'...
done.

Realizar cambios en el repositorio del "miembro del equipo"

Ahora, modifiquemos file1.txt en este repositorio:

echo "This line was added by a team member." >> file1.txt
git add file1.txt
git commit -m "Team member added a line"
git push origin main

Deberías ver:

[main xxxxxxx] Team member added a line
 1 file changed, 1 insertion(+)
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 2 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 325 bytes | 325.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To /home/labex/project/remote-repo.git
   xxxxxxx..xxxxxxx  main -> main

Realizar cambios conflictivos en tu repositorio original

Ahora, regresa a tu repositorio original y realiza un cambio diferente en el mismo archivo:

cd ~/project/git-pull-demo
echo "This line was added locally." >> file1.txt
git add file1.txt
git commit -m "Added a line locally"

Deberías ver:

[main xxxxxxx] Added a line locally
 1 file changed, 1 insertion(+)

Intentar extraer (pull) los cambios

Ahora, intenta extraer los cambios del repositorio remoto:

git pull origin main

Dado que has realizado cambios en el mismo archivo que tu "miembro del equipo", Git reportará un conflicto:

From /home/labex/project/remote-repo
 * branch            main       -> FETCH_HEAD
Auto-merging file1.txt
CONFLICT (content): Merge conflict in file1.txt
Automatic merge failed; fix conflicts and then commit the result.

Ver el conflicto

Examinemos el archivo con el conflicto:

cat file1.txt

Deberías ver algo como:

This is the first line of the file.
<<<<<<< HEAD
This line was added locally.
=======
This line was added by a team member.
>>>>>>> xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Git ha marcado las secciones conflictivas con <<<<<<< HEAD, ======= y >>>>>>>. La sección antes de ======= es tu cambio local, y la sección después es el cambio remoto.

Este es un escenario típico de conflicto de fusión (merge conflict). En el siguiente paso, usaremos la opción git pull --ignore-unmerged para resolver este conflicto.

Uso de Git Pull con la opción --ignore-unmerged

Ahora que hemos creado un conflicto entre nuestros repositorios local y remoto, exploremos cómo usar la opción git pull --ignore-unmerged para resolverlo.

Comprender la opción --ignore-unmerged

La opción --ignore-unmerged le dice a Git que priorice los cambios remotos sobre tus cambios locales cuando hay conflictos. Esto puede ser útil en situaciones en las que sabes que los cambios remotos son más importantes que tus cambios locales.

Abortar la fusión (merge) actual

Antes de poder usar la opción --ignore-unmerged, necesitamos abortar la fusión actual en progreso:

cd ~/project/git-pull-demo
git merge --abort

Este comando restaurará tu directorio de trabajo al estado anterior al intento de fusión. Verifiquemos el contenido del archivo:

cat file1.txt

Ahora deberías ver solo tus cambios locales:

This is the first line of the file.
This line was added locally.

Uso de la opción --ignore-unmerged

Ahora, usemos la opción git pull --ignore-unmerged:

git pull --ignore-unmerged origin main

Puedes notar que Git todavía reporta un conflicto:

From /home/labex/project/remote-repo
 * branch            main       -> FETCH_HEAD
Auto-merging file1.txt
CONFLICT (content): Merge conflict in file1.txt
Automatic merge failed; fix conflicts and then commit the result.

Esto se debe a que la opción --ignore-unmerged funciona de manera un poco diferente a lo que su nombre sugiere. No resuelve directamente los conflictos ignorando tus cambios locales. En lugar de eso, permite que Git continúe con una fusión incluso cuando hay entradas no fusionadas.

Comprender lo que realmente sucedió

La forma correcta de priorizar los cambios remotos sobre los cambios locales es usar la opción --strategy-option theirs:

git reset --hard ## Advertencia: Esto descartará todos los cambios no confirmados
git pull -X theirs origin main

La salida debería verse así:

From /home/labex/project/remote-repo
 * branch            main       -> FETCH_HEAD
Updating xxxxxxx..xxxxxxx
Fast-forward
 file1.txt | 1 +
 1 file changed, 1 insertion(+)

Este comando le dice a Git que resuelva automáticamente los conflictos prefiriendo los cambios remotos ("theirs") sobre tus cambios locales ("ours").

Veamos el contenido del archivo ahora:

cat file1.txt

Deberías ver:

This is the first line of the file.
This line was added by a team member.

Como puedes ver, el cambio remoto se ha priorizado sobre tu cambio local. La opción --strategy-option theirs es una forma más directa de lograr lo que muchas personas creen incorrectamente que hace --ignore-unmerged.

Cuándo usar --ignore-unmerged

La opción --ignore-unmerged es en realidad más útil en casos en los que quieres extraer (pull) actualizaciones para archivos que no tienen conflictos, mientras dejas los archivos conflictivos sin fusionar para resolverlos manualmente más tarde.

Para demostrar esto adecuadamente, creemos otro escenario:

## Agregar un nuevo archivo localmente
echo "This is a new local file." > local_file.txt
git add local_file.txt
git commit -m "Added local_file.txt"

## Crear un cambio en el repositorio del miembro del equipo
cd ~/project/team-member-repo
echo "This is a second line by team member." >> file1.txt
echo "This is a new remote file." > remote_file.txt
git add file1.txt remote_file.txt
git commit -m "Team member made more changes"
git push origin main

## Volver a tu repositorio
cd ~/project/git-pull-demo
## Hacer un cambio diferente en file1.txt
echo "This is another local change." >> file1.txt
git add file1.txt
git commit -m "Made another local change"

Ahora, cuando intentas extraer (pull), obtendrás un conflicto:

git pull origin main

Salida:

From /home/labex/project/remote-repo
 * branch            main       -> FETCH_HEAD
Auto-merging file1.txt
CONFLICT (content): Merge conflict in file1.txt
Automatic merge failed; fix conflicts and then commit the result.

Abortemos la fusión y probemos con --ignore-unmerged:

git merge --abort
git pull --ignore-unmerged origin main

Esto todavía puede mostrar conflictos, pero te permitirá obtener todos los cambios no conflictivos (como remote_file.txt) mientras dejas el archivo conflictivo (file1.txt) para que lo resuelvas manualmente.

Enfoques alternativos para manejar conflictos

Si bien los comandos git pull --ignore-unmerged y git pull -X theirs pueden ser útiles en escenarios específicos, hay varios otros enfoques para manejar conflictos con los que debes estar familiarizado. Estos enfoques te dan más control sobre el proceso de fusión (merge) y pueden ser más seguros en muchas situaciones.

1. Resolver conflictos manualmente

El enfoque más común y seguro es resolver los conflictos manualmente. Creemos un escenario de conflicto limpio y resolvámoslo manualmente:

cd ~/project/git-pull-demo
git reset --hard HEAD~1 ## Retroceder un commit

Deberías ver:

HEAD is now at xxxxxxx Added local_file.txt

Ahora, haz un cambio en file1.txt:

echo "This is a different local change." >> file1.txt
git add file1.txt
git commit -m "Made a different local change"

Ahora, extrae (pull) del repositorio remoto:

git pull origin main

Verás un conflicto:

From /home/labex/project/remote-repo
 * branch            main       -> FETCH_HEAD
Auto-merging file1.txt
CONFLICT (content): Merge conflict in file1.txt
Automatic merge failed; fix conflicts and then commit the result.

Edita el archivo para resolver el conflicto usando nano:

nano file1.txt

En el editor nano, puedes ver los marcadores de conflicto. Edita el archivo para mantener ambos cambios o realiza otras modificaciones según sea necesario. Por ejemplo, es posible que desees que se vea así:

This is the first line of the file.
This line was added by a team member.
This is a second line by team member.
This is a different local change.

Guarda el archivo (Ctrl+O, luego Enter) y sal del editor nano (Ctrl+X).

Ahora, completa el proceso de fusión:

git add file1.txt
git commit -m "Manually resolved conflict"

Deberías ver:

[main xxxxxxx] Manually resolved conflict

2. Usar git stash

Otro enfoque es usar git stash para guardar temporalmente tus cambios locales, extraer los cambios remotos y luego volver a aplicar tus cambios:

## Haz un nuevo cambio en file1.txt
echo "This is yet another local change." >> file1.txt

## Usa git stash para guardar tus cambios locales
git stash

## Extrae los cambios remotos
git pull origin main

## Vuelve a aplicar tus cambios locales
git stash pop

Si hay conflictos cuando ejecutas git stash pop, Git te lo hará saber y podrás resolverlos manualmente.

3. Crear una rama de característica (feature branch)

Un tercer enfoque es crear una rama de característica para tus cambios locales:

## Crea y cambia a una nueva rama
git checkout -b feature-branch

## Haz tus cambios
echo "This is a change in the feature branch." >> file1.txt
git add file1.txt
git commit -m "Made a change in feature branch"

## Cambia de nuevo a la rama principal (main)
git checkout main

## Extrae los cambios remotos
git pull origin main

## Fusiona tu rama de característica
git merge feature-branch

Si hay conflictos durante la fusión, Git te permitirá resolverlos manualmente antes de completar la fusión.

4. Usar herramientas de fusión (merge tools)

Git también admite varias herramientas de fusión que pueden hacer el proceso de resolución de conflictos más visual e intuitivo. Puedes configurar Git para que use la herramienta de fusión que prefieras con:

git config --global merge.tool <tool-name>

Cuando encuentres conflictos, puedes ejecutar:

git mergetool

Esto abrirá la herramienta de fusión configurada, que te ayudará a resolver los conflictos.

Cada uno de estos enfoques tiene sus ventajas y casos de uso. El mejor enfoque depende de tu situación específica y tus preferencias.

Resumen

En este laboratorio (lab), has aprendido sobre los mecanismos de resolución de conflictos de Git y, específicamente, has explorado el comando git pull --ignore-unmerged. Has adquirido experiencia práctica en:

  1. Configurar un repositorio de Git y conectarlo a un repositorio remoto
  2. Crear y simular cambios conflictivos entre repositorios locales y remotos
  3. Comprender lo que hace el comando git pull --ignore-unmerged y sus limitaciones
  4. Usar el comando más efectivo git pull -X theirs para priorizar los cambios remotos
  5. Explorar enfoques alternativos para manejar conflictos, incluyendo:
    • Resolución manual de conflictos
    • Uso de git stash
    • Creación de ramas de característica (feature branches)
    • Utilización de herramientas de fusión (merge tools)

La principal lección es que, si bien comandos como git pull --ignore-unmerged y git pull -X theirs pueden ser útiles en escenarios específicos, deben usarse con cautela. En la mayoría de los casos, resolver los conflictos manualmente te da más control y ayuda a garantizar que no se pierdan accidentalmente cambios importantes.

Al entender estos conceptos y comandos de Git, ahora estás mejor preparado para manejar conflictos de código en entornos de desarrollo colaborativo, lo que hace que tu flujo de trabajo con Git sea más eficiente y menos propenso a errores.