Cómo comprobar si un commit de Git es un ancestro de otro

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

En este laboratorio, aprenderás cómo determinar si un commit de Git es ancestro de otro. Comprender las relaciones de parentesco entre los commits es fundamental para navegar y comprender la historia de tu proyecto.

Exploraremos el comando git merge-base --is-ancestor, una herramienta poderosa para este propósito. Además, utilizaremos git log para visualizar la historia de los commits y rastrear la ascendencia, y probaremos el comando con commits que no son ancestros para consolidar tu comprensión. Al final de este laboratorio, serás proficiente en identificar relaciones de parentesco dentro de tu repositorio de Git.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL git(("Git")) -.-> git/SetupandConfigGroup(["Setup and Config"]) git(("Git")) -.-> git/BasicOperationsGroup(["Basic Operations"]) git(("Git")) -.-> git/BranchManagementGroup(["Branch Management"]) git/SetupandConfigGroup -.-> git/init("Initialize Repo") git/BasicOperationsGroup -.-> git/add("Stage Files") git/BasicOperationsGroup -.-> git/commit("Create Commit") git/BranchManagementGroup -.-> git/branch("Handle Branches") git/BranchManagementGroup -.-> git/checkout("Switch Branches") git/BranchManagementGroup -.-> git/log("Show Commits") subgraph Lab Skills git/init -.-> lab-560057{{"Cómo comprobar si un commit de Git es un ancestro de otro"}} git/add -.-> lab-560057{{"Cómo comprobar si un commit de Git es un ancestro de otro"}} git/commit -.-> lab-560057{{"Cómo comprobar si un commit de Git es un ancestro de otro"}} git/branch -.-> lab-560057{{"Cómo comprobar si un commit de Git es un ancestro de otro"}} git/checkout -.-> lab-560057{{"Cómo comprobar si un commit de Git es un ancestro de otro"}} git/log -.-> lab-560057{{"Cómo comprobar si un commit de Git es un ancestro de otro"}} end

Usar git merge-base --is-ancestor

En este paso, aprenderemos cómo usar el comando git merge-base --is-ancestor para determinar si un commit es ancestro de otro. Este es un concepto fundamental para entender la historia y las relaciones entre diferentes versiones de tu proyecto en Git.

Primero, creemos un repositorio de Git simple y hagamos algunos commits para establecer una historia. Navega a tu directorio de proyecto si aún no estás allí:

cd ~/project

Ahora, crea un nuevo directorio para este laboratorio e inicializa un repositorio de Git dentro de él:

mkdir git-ancestor-lab
cd git-ancestor-lab
git init

Deberías ver una salida similar a esta:

Initialized empty Git repository in /home/labex/project/git-ancestor-lab/.git/

A continuación, creemos nuestro primer archivo y lo confirmemos:

echo "Initial content" > file1.txt
git add file1.txt
git commit -m "Add file1 with initial content"

Verás una salida que confirme el commit:

[master (root-commit) <commit-hash>] Add file1 with initial content
 1 file changed, 1 insertion(+)
 create mode 100644 file1.txt

Ahora, hagamos otro commit. Modifica el archivo y confirma los cambios:

echo "More content" >> file1.txt
git add file1.txt
git commit -m "Add more content to file1"

Verás una salida que confirme el segundo commit:

[master <commit-hash>] Add more content to file1
 1 file changed, 1 insertion(+)

Ahora tenemos una historia simple con dos commits. Veamos el registro para ver los hashes de los commits:

git log --oneline

La salida se verá algo así (tus hashes de commit serán diferentes):

<commit-hash-2> (HEAD -> master) Add more content to file1
<commit-hash-1> Add file1 with initial content

En esta salida, <commit-hash-1> es el hash del primer commit y <commit-hash-2> es el hash del segundo commit. El segundo commit es un descendiente directo del primer commit. Esto significa que el primer commit es un ancestro del segundo commit.

El comando git merge-base --is-ancestor <ancestor-commit> <descendant-commit> comprueba si el primer commit es un ancestro del segundo commit. Si lo es, el comando finaliza con un estado de 0 (éxito). Si no lo es, finaliza con un estado de 1 (fracaso).

Probemos esto. Reemplaza <commit-hash-1> y <commit-hash-2> con los hashes reales de la salida de git log --oneline.

git merge-base --is-ancestor <commit-hash-1> <commit-hash-2>
echo $?

El comando echo $? imprime el estado de salida del comando anterior. Dado que <commit-hash-1> es un ancestro de <commit-hash-2>, el comando git merge-base debe tener éxito y la salida de echo $? debe ser 0.

Comprender la ascendencia es crucial para muchas operaciones de Git, como la fusión (merge) y la rebase, ya que ayuda a Git a determinar la historia común entre diferentes ramas o commits.

Ejecutar git log para rastrear la ascendencia

En este paso, utilizaremos el comando git log para visualizar la historia de los commits y comprender más claramente el concepto de ascendencia. El comando git log es una herramienta poderosa para explorar la historia de tu repositorio.

Navega al directorio de tu repositorio si aún no estás allí:

cd ~/project/git-ancestor-lab

Ya tenemos dos commits en nuestro repositorio. Veamos el registro nuevamente, esta vez utilizando el formato predeterminado:

git log

La salida mostrará los detalles de cada commit, incluyendo el hash del commit, el autor, la fecha y el mensaje del commit. Los commits se enumeran en orden cronológico inverso (el más reciente primero).

commit <commit-hash-2> (HEAD -> master)
Author: Jane Doe <[email protected]>
Date:   <Date and Time>

    Add more content to file1

commit <commit-hash-1>
Author: Jane Doe <[email protected]>
Date:   <Date and Time>

    Add file1 with initial content

En esta salida, puedes ver que el segundo commit (<commit-hash-2>) apunta hacia el primer commit (<commit-hash-1>). Así es como Git rastrea la historia. Cada commit (excepto el inicial) tiene un commit padre, y esta relación padre-hijo define la ascendencia.

El comando git log esencialmente recorre hacia atrás esta cadena de padres, comenzando desde el commit actual (indicado por HEAD -> master).

Agreguemos otro commit para hacer la historia un poco más larga:

echo "Final content" >> file1.txt
git add file1.txt
git commit -m "Add final content to file1"

Ahora, ejecuta git log --oneline nuevamente para ver la historia actualizada:

git log --oneline

La salida mostrará tres commits:

<commit-hash-3> (HEAD -> master) Add final content to file1
<commit-hash-2> Add more content to file1
<commit-hash-1> Add file1 with initial content

Aquí, <commit-hash-3> es el commit más reciente, <commit-hash-2> es su padre y <commit-hash-1> es el padre de <commit-hash-2>. Esto significa que <commit-hash-1> es un ancestro tanto de <commit-hash-2> como de <commit-hash-3>. Del mismo modo, <commit-hash-2> es un ancestro de <commit-hash-3>.

Podemos usar git merge-base --is-ancestor para verificar estas relaciones. Reemplaza los marcadores de posición con los hashes reales de tus commits.

git merge-base --is-ancestor <commit-hash-1> <commit-hash-3>
echo $?

Esto debería mostrar 0 porque el primer commit es un ancestro del tercer commit.

git merge-base --is-ancestor <commit-hash-2> <commit-hash-3>
echo $?

Esto también debería mostrar 0 porque el segundo commit es un ancestro del tercer commit.

Usar git log te ayuda a visualizar el gráfico de commits y comprender las relaciones padre-hijo, lo cual está directamente relacionado con el concepto de ascendencia que verifica git merge-base --is-ancestor.

Probar commits que no son ancestros

En los pasos anteriores, usamos git merge-base --is-ancestor para confirmar que los commits anteriores eran ancestros de los commits posteriores en la misma rama. Ahora, exploremos qué sucede cuando probamos commits que no son ancestros el uno del otro.

Navega al directorio de tu repositorio:

cd ~/project/git-ancestor-lab

Actualmente tenemos una sola rama (master) con tres commits. Para probar relaciones de no-ascendencia, necesitamos crear una nueva rama y hacer un commit en esa rama. Esto creará una historia divergente.

Primero, creemos una nueva rama llamada feature:

git branch feature

Este comando crea un nuevo puntero de rama llamado feature que apunta al mismo commit que master (nuestro commit más reciente, <commit-hash-3>).

Ahora, cambiemos a la rama feature:

git checkout feature

Deberías ver una salida que indique que has cambiado de rama:

Switched to branch 'feature'

Ahora estamos en la rama feature. Hagamos un nuevo commit en esta rama. Crea un nuevo archivo:

echo "Feature content" > file2.txt
git add file2.txt
git commit -m "Add file2 on feature branch"

Verás una salida que confirme el commit en la rama feature:

[feature <commit-hash-4>] Add file2 on feature branch
 1 file changed, 1 insertion(+)
 create mode 100644 file2.txt

Ahora, veamos la historia usando git log --oneline --all --graph. La bandera --all muestra los commits de todas las ramas y --graph dibuja una representación basada en texto de la historia de los commits.

git log --oneline --all --graph

La salida mostrará una historia con ramificaciones. Puede verse algo así (los hashes de los commits variarán):

* <commit-hash-4> (HEAD -> feature) Add file2 on feature branch
* <commit-hash-3> (master) Add final content to file1
* <commit-hash-2> Add more content to file1
* <commit-hash-1> Add file1 with initial content

En este gráfico, <commit-hash-4> es el commit más reciente en la rama feature y <commit-hash-3> es el commit más reciente en la rama master. Estos dos commits no son ancestros el uno del otro. Comparten un ancestro común, que es <commit-hash-3> (el commit donde se creó la rama feature).

Usemos git merge-base --is-ancestor para probar la relación entre <commit-hash-4> y <commit-hash-3>. Reemplaza los marcadores de posición con los hashes reales de tus commits.

git merge-base --is-ancestor <commit-hash-4> <commit-hash-3>
echo $?

Este comando comprueba si <commit-hash-4> es un ancestro de <commit-hash-3>. Según nuestro gráfico, no lo es. Por lo tanto, el comando debe finalizar con un estado de 1.

Ahora, probemos al revés: ¿es <commit-hash-3> un ancestro de <commit-hash-4>?

git merge-base --is-ancestor <commit-hash-3> <commit-hash-4>
echo $?

Este comando comprueba si <commit-hash-3> es un ancestro de <commit-hash-4>. Mirando el gráfico, el padre de <commit-hash-4> es <commit-hash-3>. Entonces, <commit-hash-3> es un ancestro de <commit-hash-4>. El comando debe finalizar con un estado de 0.

Esto demuestra cómo se puede usar git merge-base --is-ancestor para comprobar programáticamente la relación entre cualquier par de commits en la historia de tu repositorio, incluso en diferentes ramas.

Resumen

En este laboratorio, aprendimos cómo usar el comando git merge-base --is-ancestor para comprobar si un commit de Git es un ancestro de otro. Comenzamos creando un repositorio de Git simple y realizando algunos commits para establecer una historia. Luego, usamos git log --oneline para ver la historia de los commits e identificar los hashes de los commits. Este paso fundamental es crucial para entender las relaciones entre diferentes versiones de un proyecto en Git.