2.2 Un conflicto
Veamos lo que sucede cuando hay un conflicto. Hagamos checkout de
example9/branchB y mezclemos example9/branchA:
Listing 2.9:Mezclando$ git merge example9/branchA Auto-merging example.py CONFLICT (content): Merge conflict in example.py Automatic merge failed; fix conflicts and then commit the result. $ git status On branch example9/branchB You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Changes to be committed: modified: module.py Unmerged paths: (use "git add <file>..." to mark resolution) both modified: example.py $ git ls-tree -r HEAD 100644 blob 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f .gitignore 100755 blob 500616dc70f4847f244d29d827a192b7fa03de93 example.py 100644 blob 2d1fe2ea52267ab6e75cca853c393fc6929a0e45 module.py $ git ls-files -s 100644 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f 0 .gitignore 100755 b0a7eae10629dec61246f86c08f2432f0e276675 1 example.py 100755 500616dc70f4847f244d29d827a192b7fa03de93 2 example.py 100755 ad957360597fb9bd3e83d4bfa869f6e19b7fbf2b 3 example.py 100644 475f980e6c6e24f8fc4a144e498fa1c1c59da370 0 module.py
Podemos ver que example.py aparece en Unmerged paths, y module.py
está listado en Changes to be committed. .gitignore no sale listado en git
status. .gitignore no ha cambiado entre HEAD, index y lo que está en el
árbol de trabajo así que no hay nada que reportar sobre él. module.py
cambió como parte del proceso de mezcla sin conflictos y por eso está presente
tanto en HEAD como en el index con un id different. El archivo que está
actualmente en el árbol de trabajo es justo como está en el index y por eso sale
listado en Changes to be committed. Lo interesante es con respecto a
example.py. En vez de tener un solo ítem del archivo en el index, hay 3 y cada
instancia tiene un index stage diferente del 1 al 3. Cuando hay un conflicto de
contenido en un archivo (como en este caso), git va a guardar 3 versiones del
archivo en el index. Stage número 1 es el archivo como está en el ancestro
común .
Stage número 2 es el archivo como está en HEAD. Stage número 3 es el archivo
como está en la otra rama. Vean por sí mismos:
Listing 2.10:Verificando los ids de example.py en las diferentes versiones$ git ls-tree $( git merge-base HEAD MERGE_HEAD ) example.py 100755 blob b0a7eae10629dec61246f86c08f2432f0e276675 example.py $ git ls-tree HEAD example.py 100755 blob 500616dc70f4847f244d29d827a192b7fa03de93 example.py $ git ls-tree MERGE_HEAD example.py 100755 blob ad957360597fb9bd3e83d4bfa869f6e19b7fbf2b example.py
Stage número 0, como vimos antes, significa que el archivo no tiene cambios o
que fue agregado al index.
Resolvamos el conflicto como habíamos hecho antes (lo que significa editar
ambos archivos) y entonces veamos la salida de comandos git:
Listing 2.11:git status luego de modificar los archivos$ git status On branch example9/branchB You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Changes to be committed: modified: module.py Unmerged paths: (use "git add <file>..." to mark resolution) both modified: example.py Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: module.py $ git ls-tree -r HEAD 100644 blob 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f .gitignore 100755 blob 500616dc70f4847f244d29d827a192b7fa03de93 example.py 100644 blob 2d1fe2ea52267ab6e75cca853c393fc6929a0e45 module.py $ git ls-files -s 100644 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f 0 .gitignore 100755 b0a7eae10629dec61246f86c08f2432f0e276675 1 example.py 100755 500616dc70f4847f244d29d827a192b7fa03de93 2 example.py 100755 ad957360597fb9bd3e83d4bfa869f6e19b7fbf2b 3 example.py 100644 475f980e6c6e24f8fc4a144e498fa1c1c59da370 0 module.py
Aunque los ids de los objetos en index y HEAD no han cambiado, el contenido
de los archivos cambió en el árbol de trabajo. Dado que module.py tiene
un id diferente entre index y HEAD, git lo muestra en Changes to be
committed. Dado que el contenido del archivo en el árbol de trabajo es
diferente de index, también se lista en Changes not staged for commit.
example.py no ha sido agregado al index, así que para git sigue con
conflictosy mantiene las 3 versiones en el index y se lista en Unmerged
paths.
Agreguemos module.py primero y veamos qué sucede:
Listing 2.12:Luego de agregar module.py$ git add module.py $ git status On branch example9/branchB You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Changes to be committed: modified: module.py Unmerged paths: (use "git add <file>..." to mark resolution) both modified: example.py $ git ls-tree -r HEAD 100644 blob 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f .gitignore 100755 blob 500616dc70f4847f244d29d827a192b7fa03de93 example.py 100644 blob 2d1fe2ea52267ab6e75cca853c393fc6929a0e45 module.py $ git ls-files -s 100644 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f 0 .gitignore 100755 b0a7eae10629dec61246f86c08f2432f0e276675 1 example.py 100755 500616dc70f4847f244d29d827a192b7fa03de93 2 example.py 100755 ad957360597fb9bd3e83d4bfa869f6e19b7fbf2b 3 example.py 100644 42004985f8888627d3985174325a235401568e0b 0 module.py
Para este archivo, se comporta como sucedía antes cuando no había conflictos.
Los ids para este archivo son diferentes are entre HEAD e index y por eso sale
listado en Changes to be committed. El archivo en el árbol de trabajo es
como está en el index ahora y por eso git no tiene más nada que reportar sobre
él. example.py sigue con conflictos y por eso no hay cambios en cuanto a lo que
veíamos previamente.
Ahora agreguemos example.py:
Listing 2.13:Luego de agregar example.py$ git add example.py $ git status On branch example10/branchB All conflicts fixed but you are still merging. (use "git commit" to conclude merge) Changes to be committed: modified: example.py modified: module.py $ git ls-tree -r HEAD 100644 blob 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f .gitignore 100755 blob 500616dc70f4847f244d29d827a192b7fa03de93 example.py 100644 blob 2d1fe2ea52267ab6e75cca853c393fc6929a0e45 module.py $ git ls-files -s 100644 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f 0 .gitignore 100755 ad957360597fb9bd3e83d4bfa869f6e19b7fbf2b 0 example.py 100644 42004985f8888627d3985174325a235401568e0b 0 module.py
Ahora que el archivo que (originalmente) tenía conflictos ha sido agregado,
tenemos un solo ítem para él en el index. Dado que los ids no son los mismos
entre HEAD e index, git lo reporta en Changed to be committed y dado que el
contenido del archivo en el árbol de trabajo es como en el index, git no tiene
más nada que decir sobre él. Creemos una nueva revisión en este momento y
veamos qué sucede.
Listing 2.14:git commit$ git commit -m "A new revision" [example9/branchB 9f80666] A new revision $ git status On branch example9/branchB nothing to commit, working tree clean $ git ls-tree -r HEAD 100644 blob 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f .gitignore 100755 blob ad957360597fb9bd3e83d4bfa869f6e19b7fbf2b example.py 100644 blob 42004985f8888627d3985174325a235401568e0b module.py $ git ls-files -s 100644 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f 0 .gitignore 100755 ad957360597fb9bd3e83d4bfa869f6e19b7fbf2b 0 example.py 100644 42004985f8888627d3985174325a235401568e0b 0 module.py
Como sucedió anteriormente cuando no había conflictos, cuando se crea una
nueva revisión, los ids en HEAD son actualizados a los mismos ids del
index .
Dado que index y HEAD tienen los mismos ids, no hay nada listado en Changes
to be committed y dado que no hay diferencias entre el index y el arbol de
trabajo, no hay más nada que reportar.
Si se detienen a pensarlo, aparte de los 3 items listados en index mientras
el archivo tenía conflictos, no hay otras diferencias en cuanto a lo que
se guardó en index o en las revisiones. Dentro de todo, git no guarda
ninguna información sobre los archivos que tuvieron conflictos cuando se crea
una revisión. Simplemente crea una nueva revisión con sus múltiples
padres, los archivos y sus contenidos (finales) justo como en cualquier otra
revisión:
Listing 2.15:Verificando la información de la revisión$ git cat-file -p HEAD tree 396032b1546d75672f3a85c13a858d3b187d2046 parent 3cd9cfd24b13fa2381c5cc8009275b961ea7a26b parent dfde76c316ff0a070ddc7560f86b7279b73ed807 author Developer A <dev.a@localhost> 1592110970 -0600 committer Developer A <dev.a@localhost> 1592111469 -0600 A new revision $ git cat-file -p HEAD^{tree} 100644 blob 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f .gitignore 100755 blob ad957360597fb9bd3e83d4bfa869f6e19b7fbf2b example.py 100644 blob 42004985f8888627d3985174325a235401568e0b module.py
Copyright 2020 Edmundo Carmona Antoranz