Resolver un conflicto de Git con archivos binarios

464

He estado usando Git en Windows (msysgit) para rastrear los cambios de algunos trabajos de diseño que he estado haciendo.

Hoy he estado trabajando en una PC diferente (con repositorio remoto brian) y ahora estoy tratando de fusionar las ediciones realizadas hoy en mi versión local regular en mi computadora portátil.

En mi computadora portátil, solía git pull brian masterllevar los cambios a mi versión local. Todo estaba bien, aparte del documento principal de InDesign, esto se muestra como un conflicto.

La versión para PC ( brian) es la última que quiero conservar, pero no sé qué comandos le dice al repositorio que use esta.

Intenté copiar directamente el archivo en mi computadora portátil, pero esto parece interrumpir todo el proceso de fusión.

¿Alguien puede señalarme en la dirección correcta?

Kevin Wilson
fuente

Respuestas:

854

git checkoutacepta una --oursu --theirsopción para casos como este. Entonces, si tiene un conflicto de fusión y sabe que solo desea el archivo de la rama en la que se está fusionando, puede hacer lo siguiente:

$ git checkout --theirs -- path/to/conflicted-file.txt

para usar esa versión del archivo. Del mismo modo, si sabe que desea su versión (no la que se está fusionando), puede usar

$ git checkout --ours -- path/to/conflicted-file.txt
mipadi
fuente
47
Tuve que ejecutar 'git reset HEAD path / to / conflictted-file.txt' en el archivo antes de usar --ours, de lo contrario, parecía no tener ningún efecto.
Zitrax
66
@Zitrax ¿Difundió el archivo después de ejecutarlo git checkout --ours? La página del manual sugiere (en mi humilde opinión) que el pago --ours / - suyo eliminará el cambio de la lista "ambos modificados, necesitan fusionarse" y lo agregará al índice, y creo que eso no es correcto. Creo que deberás correr git adddespués del pago.
Tim Keating
15
Nota: aún desea hacer "git add conflictlict-file.txt " y "git commit". Prácticamente, cuando lo probé, el mensaje de confirmación se rellenó previamente con una nota sobre el conflicto.
Edward Falk
2
la redacción de "la rama en la que se está fusionando" está peligrosamente cerca de "la rama en la que se está fusionando", creo que simplemente abandonar la preposición sería mejor: "la rama en la que se está fusionando", lo que también reflejaría el comando git (es decir git merge branch_name)
andrybak
13
Un par de puntos importantes que siempre faltan en las explicaciones de este tema. Al hacer un rebase en lugar de fusionar, se intercambia el significado de --theiry --ours, es decir, su rama == actualmente desprotegida y - nuestra es la rama, generalmente una rama remota o la especificación de ruta que está intentando fusionar en la actual rama. La [space]--[space]opción desambigua a la especificación de ruta entre el nombre de rama y la especificación de ruta que ambos existen con el mismo nombre (por ejemplo, un nombre de rama existente es "abc" y existe un directorio llamado "abc").
BoiseBaked
147

Debe resolver el conflicto manualmente (copiando el archivo) y luego confirmar el archivo (no importa si lo copió o usó la versión local) de esta manera

git commit -a -m "Fix merge conflict in test.foo"

Git normalmente se confirma automáticamente después de la fusión, pero cuando detecta conflictos que no puede resolver por sí solo, aplica todos los parches que resolvió y deja el resto para que lo resuelva y confirme manualmente. La página de manual de Git Merge , el curso intensivo de Git-SVN o esta entrada de blog pueden arrojar algo de luz sobre cómo se supone que debe funcionar.

Editar: vea la publicación a continuación, en realidad no tiene que copiar los archivos usted mismo, pero puede usar

git checkout --ours -- path/to/file.txt
git checkout --theirs -- path/to/file.txt

para seleccionar la versión del archivo que desea. Copiar / editar el archivo solo será necesario si desea una combinación de ambas versiones.

Por favor marque la respuesta mipadis como la correcta.

VolkA
fuente
1
Gracias por eso. No estaba seguro de si había algún tipo de forma integrada para marcar un archivo como "correcto". ¡Explica por qué no pude encontrar el comando inexistente!
Kevin Wilson
Sí, eso es un poco intuitivo - algo así como la determinación de Git sería bueno, pero también sería un paso adicional ...
Volka
120

También puede superar este problema con

git mergetool

lo que causa gitcrear copias locales del binario en conflicto y generar su editor predeterminado en ellas:

  • {conflicted}.HEAD
  • {conflicted}
  • {conflicted}.REMOTE

Obviamente, no puede editar archivos binarios en un editor de texto. En su lugar, copie el nuevo {conflicted}.REMOTEarchivo {conflicted}sin cerrar el editor. Luego, cuando cierre, el editor gitverá que la copia de trabajo no decorada ha cambiado y su conflicto de fusión se resuelve de la manera habitual.

RobM
fuente
8
Si los archivos son grandes o no quiere arriesgarse a abrir binarios en un editor de texto, puede presionar ctrl + c en el indicador mergetool (" Hit return to start merge resolution tool") y git dejará los archivos adicionales en su lugar. Luego puede modificarlos o fusionarlos en una herramienta externa (útil para formatos de documentos binarios como LibreOffice / OpenOffice / MSWord) y guardar el resultado nuevamente en el nombre de archivo original. Para informar a git que el conflicto se ha resuelto, git addel nombre de archivo original y luego puede finalizar la confirmación de fusión.
Felix
18

Para resolver manteniendo la versión en su rama actual (ignore la versión de la rama en la que se está fusionando), simplemente agregue y confirme el archivo:

git commit -a

Para resolver sobrescribiendo la versión en su rama actual con la versión de la rama en la que se está fusionando, primero debe recuperar esa versión en su directorio de trabajo y luego agregarla / confirmarla:

git checkout otherbranch theconflictedfile
git commit -a

Explicado con más detalle.

Joshua Flanagan
fuente
1
Prefiero esta variante sobre la respuesta aceptada, porque es más intuitiva, especialmente teniendo en cuenta que el significado de esos "- nuestros" y "- sus" se intercambia en caso de rebase.
Antony Hatchkins
11

La respuesta de mipadi no funcionó para mí, tenía que hacer esto:

git checkout --nuestra ruta / a / file.bin

o, para mantener la versión fusionada en:

git checkout: su ruta / to / file.bin

entonces

git agregar ruta / a / archivo.bin

Y luego pude volver a hacer "git mergetool" y continuar con el siguiente conflicto.

kris
fuente
6

De los git checkoutdocumentos

git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...

--ours
--theirs
Cuando revise las rutas desde el índice, vea la etapa # 2 ( ours) o # 3 (theirs ) para las rutas no fusionadas.

El índice puede contener entradas no fusionadas debido a una fusión fallida previa. De forma predeterminada, si intenta retirar dicha entrada del índice, la operación de pago fallará y no se extraerá nada. El uso -fignorará estas entradas no fusionadas. El contenido de un lado específico de la fusión se puede extraer del índice utilizando --ourso --theirs. Con -m, los cambios realizados en el archivo de árbol de trabajo se pueden descartar para volver a crear el resultado de fusión en conflicto original.

usuario456814
fuente
4

Encontré un problema similar (queriendo extraer un commit que incluyera algunos archivos binarios que causaban conflictos cuando se fusionaban), pero encontré una solución diferente que se puede hacer completamente usando git (es decir, no tener que copiar manualmente los archivos). Pensé que lo incluiría aquí, así que al menos puedo recordarlo la próxima vez que lo necesite. :) Los pasos se ven así:

% git fetch

Esto obtiene los últimos commit (s) del repositorio remoto (es posible que deba especificar un nombre de rama remoto, dependiendo de su configuración), pero no intenta fusionarlos. Registra el commit en FETCH_HEAD

% git checkout FETCH_HEAD stuff/to/update

Esto toma la copia de los archivos binarios que quiero y sobrescribe lo que está en el árbol de trabajo con la versión obtenida de la rama remota. git no intenta hacer ninguna fusión, por lo que terminas con una copia exacta del archivo binario desde la rama remota. Una vez hecho esto, puede agregar / confirmar la nueva copia como de costumbre.

Brian Webster
fuente
4

Este procedimiento es para resolver conflictos de archivos binarios después de haber enviado una solicitud de extracción a Github:

  1. Entonces, en Github, descubrió que su solicitud de extracción tiene un conflicto en un archivo binario.
  2. Ahora regrese a la misma rama git en su computadora local.
  3. Usted (a) vuelve a crear / reconstruir este archivo binario nuevamente, y (b) compromete el archivo binario resultante a esta misma rama git.
  4. Luego empujas esta misma rama git nuevamente a Github.

En Github, en su solicitud de extracción, el conflicto debería desaparecer.

david m lee
fuente
Este es exactamente el procedimiento que necesito
Huifang Feng
2

Si el binario es algo más que un dll o algo que se puede editar directamente archivo como una imagen, o un archivo de mezcla (y no necesita desechar / seleccionar un archivo u otro), una fusión real sería algo así como:

Sugiero buscar una herramienta diff orientada a lo que es su archivo binario, por ejemplo, hay algunos gratuitos para archivos de imagen, por ejemplo

y compararlos

Si no hay una herramienta de diferencia para comparar sus archivos, entonces si tiene el generador original del archivo bin (es decir, existe un editor para él ... como blender 3d, puede inspeccionar manualmente esos archivos, también ver los registros y preguntarle a la otra persona qué debe incluir) y hacer una salida de los archivos con https://git-scm.com/book/es/v2/Git-Tools-Advanced-Merging#_manual_remerge

$ git show :1:hello.blend > hello.common.blend $ git show :2:hello.blend > hello.ours.blend $ git show :3:hello.blend > hello.theirs.blend

tyoc213
fuente
1

Me he encontrado con dos estrategias para administrar la diferencia / fusión de archivos binarios con Git en Windows.

  1. Tortoise git le permite configurar herramientas de diferencias / fusión para diferentes tipos de archivos en función de sus extensiones de archivo. Ver 2.35.4.3. Configuración avanzada de diferencias / fusión http://tortoisegit.org/docs/tortoisegit/tgit-dug-settings.html . Esta estrategia, por supuesto, se basa en las herramientas adecuadas de diferenciación / fusión disponibles.

  2. Usando los atributos de git puede especificar una herramienta / comando para convertir su archivo binario en texto y luego dejar que su herramienta predeterminada de fusión / fusión haga lo suyo. Ver http://git-scm.com/book/it/v2/Customizing-Git-Git-Attributes . El artículo incluso da un ejemplo del uso de metadatos para diferenciar imágenes.

Obtuve ambas estrategias para trabajar con archivos binarios de modelos de software, pero utilizamos tortuga git ya que la configuración fue fácil.

BoJohDoh
fuente
0

Uso la aplicación Git Workflow para Excel: https://www.xltrail.com/blog/git-workflow-for-excel para resolver la mayoría de los problemas de fusión relacionados con mis archivos binarios. Esta aplicación de código abierto me ayuda a resolver problemas de manera productiva sin perder demasiado tiempo y me permite elegir la versión correcta del archivo sin ninguna confusión.

Siddhartha Thota
fuente
0

mi caso parece un error ... usando git 2.21.0

Hice un tirón ... se quejó de archivos binarios:

warning: Cannot merge binary files: <path>
Auto-merging <path>
CONFLICT (content): Merge conflict in <path>
Automatic merge failed; fix conflicts and then commit the result.

Y luego, nada en ninguna de las respuestas aquí dio como resultado ningún resultado que tuviera sentido.

Si miro qué archivo tengo ahora ... es el que edité. Si yo tampoco:

git checkout --theirs -- <path>
git checkout --ours -- <path>

Me sale:

Updated 0 paths from the index

y todavía tengo mi versión del archivo. Si firmo y luego finalizo la compra, en su lugar dirá 1, pero aún así me da mi versión del archivo.

git mergetool dice

No files need merging

y el estado de git dice

    All conflicts fixed but you are still merging.
    (use "git commit" to conclude merge)

Una opción es deshacer el commit ... pero tuve mala suerte y tuve muchos commits, y este malo fue el primero. No quiero perder el tiempo repitiendo eso.

para resolver esta locura:

Acabo de correr

git commit

que pierde la versión remota y probablemente desperdicia algo de espacio almacenando un archivo binario adicional ... luego

git checkout <commit where the remote version exists> <path>

lo que me devuelve la versión remota

luego editó el archivo nuevamente ... y luego confirmó y presionó, lo que nuevamente significa desperdiciar espacio con otra copia del archivo binario.

Peter
fuente
En mi caso, después de intentarlo git checkout --ours <path>he recibido Updated 0 paths from the index . Lo arreglé con el git add <path>comando, que hace lo mismo.
Andriy