Resolver conflictos de fusión de Git a favor de sus cambios durante un tirón

1227

¿Cómo resuelvo un conflicto de fusión de git a favor de los cambios retirados?

Básicamente, necesito eliminar todos los cambios conflictivos de un árbol de trabajo sin tener que pasar por todos los conflictos con un git mergetooltiempo manteniendo todos los cambios libres de conflictos. Preferiblemente haciendo esto mientras tira, no después.

sanmai
fuente
3
posible duplicado de git merge -s our, what about "
2
Duplicado de git pull desde remoto ... ¿puedo forzarlo a sobrescribir en lugar de informar conflictos? Puedes ver la misma solución allí.
Dan Dascalescu
3
@DanDascalescu La respuesta aceptada no responde a estas preguntas, por lo que claramente no es un duplicado. Además, esa otra pregunta es bastante ambigua: es muy difícil saber qué se hace. En general, no puedo estar de acuerdo contigo. ¿Cuál es tu punto en esto?
sanmai
2
@sanmai Tienes dos respuestas y aceptaste una de ellas. ¿Puede explicar mejor lo que espera en una respuesta y cuántos detalles más desea aquí?
Edward Thomson
2
@EdwardThomson bueno, en realidad estaba pensando dar esta reputación por la primera respuesta, pero si me preguntas, podría esperar y ver si surge una mejor respuesta
sanmai

Respuestas:

1220
git pull -s recursive -X theirs <remoterepo or other repo>

O, simplemente, para el repositorio predeterminado:

git pull -X theirs

Si ya estás en estado de conflicto ...

git checkout --theirs path/to/file
Pascal Fares
fuente
40
Tenga en cuenta que -s recursiveaquí es redundante, ya que esa es la estrategia de fusión predeterminada. Entonces podría simplificarlo a git pull -X theirs, que es básicamente equivalente a git pull --strategy-option theirs.
55
Si hago esto, termino en el MERGINGestado. Entonces puedo git merge --aborte intentarlo de nuevo, pero cada vez que termino ocurre una fusión. ... Sé que una rebase fue empujada a mi río arriba, así que ¿quizás eso está causando esto?
Benjohn
22
Tenga cuidado con el git checkout --theirs path/to/file. Lo usé durante el rebase y obtuve resultados inesperados. Explicación encontrada en el documento: tenga en cuenta que durante git rebase y git pull --rebase, el nuestro y el suyo pueden aparecer intercambiados; --ours proporciona la versión de la rama en la que se vuelven a basar los cambios, mientras que --theirs le da la versión de la rama que contiene el trabajo que se está volviendo a crear.
Vuk Djapic
10
Tenga en cuenta que la git checkout --theirs/--ours pathpágina de manual indica que funciona para rutas no fusionadas . Entonces, si no hubo conflicto en la ruta, ya está fusionado, este comando no hará nada. Esto podría ocasionar problemas cuando desee, por ejemplo, la versión 'de ellos' de una subcarpeta completa. Entonces, en tal caso, sería más seguro hacer git checkout MERGE_HEAD patho usar commit hash.
fsw
44
git pull -X theirscrea un commit de fusión si hay conflictos (por ejemplo, si otro committer se ejecutó git push -fen el control remoto). Si no desea fusionar confirmaciones, ejecute en su lugar git fetch && git reset --hard origin/master.
Dan Dascalescu el
985

Puede usar la opción de estrategia "suya" recursiva :

git merge --strategy-option theirs

Del hombre :

ours
    This option forces conflicting hunks to be auto-resolved cleanly by 
    favoring our version. Changes from the other tree that do not 
    conflict with our side are reflected to the merge result.

    This should not be confused with the ours merge strategy, which does 
    not even look at what the other tree contains at all. It discards 
    everything the other tree did, declaring our history contains all that
    happened in it.

theirs
    This is opposite of ours.

Nota: como dice la página de manual, la opción de estrategia de fusión "nuestra" es muy diferente de la estrategia de fusión "nuestra" .

Ikke
fuente
Aquí hay una explicación más detallada: lostechies.com/joshuaflanagan/2010/01/29/…
mPrinC
227
También git checkout --theirspara operar en un solo archivo en conflicto
dvd
48
Esto no funciona si ya está en el estado de resolución de conflictos. En ese caso, creo que la mejor manera de resolver es git checkout <ref to theirs> -- the/conflicted.file; y luego git addsus cambios.
ThorSummoner
54
@ThorSummoner En ese caso, hay un pago git: su ruta / de / archivo. De esa manera, no tiene que buscar manualmente el hash correcto.
Ikke
8
@ Ikke Eso debería ser básicamente su propia respuesta (y la respuesta aceptada en eso) si me preguntas.
ThorSummoner
474

Si ya está en estado de conflicto y desea aceptar todos los suyos:

git checkout --theirs .
git add .

Si quieres hacer lo contrario:

git checkout --ours .
git add .

Esto es bastante drástico, así que asegúrate de que realmente quieres borrar todo así antes de hacerlo.

mucho que aprender
fuente
47
o no use .y especifique los archivos en lugar del punto que desea pagar. menos "drástico" y exactamente lo que quieres hacer, presumiblemente.
manroe
10
esto no funciona si el archivo se ha eliminado de la otra rama: '<file>' no tiene su versión
Japster24
3
Votaría más si pudiera, sigo volviendo a esta respuesta de vez en cuando.
tarikki
66
Utilice en su git add -ulugar para omitir archivos que no están bajo control de versiones.
Sudipta Basak
3
Caso hipotético, tres cambios en un archivo, uno conflictivo, dos sin conflicto, ¿esta solución aplicaría cambios no conflictivos y resolvería el cambio conflictivo al nuestro? ¿O tomaría solo nuestra versión ignorando los cambios no conflictivos de la suya?
pedromarce
222

Bien, imagina el escenario en el que estaba:

Intentas un merge, o tal vez un cherry-pick, y te detienen con

$ git cherry-pick 1023e24
error: could not apply 1023e24... [Commit Message]
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'

Ahora, ve el archivo en conflicto y realmente no desea conservar sus cambios. En mi caso anterior, el archivo estaba en conflicto solo con una nueva línea que mi IDE había agregado automáticamente. Para deshacer sus cambios y aceptar los de ellos, la forma más fácil es:

git checkout --theirs path/to/the/conflicted_file.php
git add path/to/the/conflicted_file.php

Lo contrario de esto (para sobrescribir la versión entrante con su versión) es

git checkout --ours path/to/the/conflicted_file.php
git add path/to/the/conflicted_file.php

Sorprendentemente, no pude encontrar esta respuesta muy fácilmente en la red.

Theodore R. Smith
fuente
15
Tenga en cuenta que, si se realiza un intervalo git statusentre checkouty add, el archivo aún se muestra como "ambos modificados".
obispo
¿Sabes si hay una manera de hacer esto para todos los archivos que están en estado de conflicto? Si es así, sería una buena extensión para su respuesta.
Drew Noakes
2
Hago esto: git reset --hard y luego git pull [remote server name] [branch name] -Xtheirs(deshace la fusión y luego coloca las cosas nuevas encima de mis cosas), no estoy seguro de si esto es lo que quieres.
Ssaltman
38

Las git pull -X theirsrespuestas pueden crear una confirmación de fusión fea o emitir un

error: sus cambios locales en los siguientes archivos se sobrescribirán mediante fusión:

Si simplemente desea ignorar cualquier modificación local a los archivos desde el repositorio, por ejemplo, en un cliente que siempre debe ser un espejo de un origen, ejecute esto (reemplace mastercon la rama que desee):

git fetch && git reset --hard origin/master

¿Como funciona? git fetchlo hace git pullpero sin fusionarse . Luego git reset --hardhace que su árbol de trabajo coincida con el último commit. Todos sus cambios locales a los archivos en el repositorio se descartarán , pero los nuevos archivos locales se dejarán solos.

Dan Dascalescu
fuente
1
+1 - git fetch && git reset --hard {remote}/{branch}fue lo que resolvió mi problema. Necesitaba deshacerme por completo de mis propios cambios a favor del estado "de ellos" de una rama, pero se git pull -X theirsatragantó con algunos archivos movidos / renombrados. ¡Gracias!
Ivaylo Slavov
23

Después de git merge, si tienes conflictos y quieres tu o sus

git checkout --theirs .
git checkout --ours .
Mohit Kanojia
fuente
¿Cómo haría esto sobre una base conflictiva? Lo anterior funciona a nivel de archivo, eliminando cualquier fragmento no conflictivo que pueda tener un archivo conflictivo.
Jani
21

Para resolver todos los conflictos con la versión en una rama en particular:

git diff --name-only --diff-filter=U | xargs git checkout ${branchName}

Entonces, si ya está en el estado de fusión y desea mantener la versión maestra de los archivos en conflicto:

git diff --name-only --diff-filter=U | xargs git checkout master
Ariel Alvarez
fuente
Y para las personas en ventanas sin acceso a tubos xargs, ¿cómo se traduce esto?
tsemer
¿No te saltearías tus cambios por completo? ¿Incluso aquellos que no están en estado de conflicto?
Valentin Heinitz
Esto es lo que terminé haciendo. Desafortunadamente, posteriormente se requiere un comando git cherry-pick --continue o un git commit --allow-emptycomando para confirmar estos cambios, y parece que no hay ningún sistema detrás del cual se requiera el comando, lo que hace que la automatización de este sea un problema. Actualmente estoy resolviendo esto probando la existencia de un .git/COMMIT_EDITMSGarchivo, pero eso parece hacky y frágil, y todavía no estoy convencido de que siempre funcione.
Konrad Rudolph,
Esto es bueno, significa que si resuelve manualmente (y lo hace git add), puede resolver el resto a través de esto. git checkout --ours/ git checkout --theirses útil también.
Rcoup
18

Por favor, no es que a veces esto no funcione :

git checkout --nuestra ruta / a / archivo

o

git checkout - su ruta / a / archivo

En cambio, hice esto, asumiendo que HEAD es nuestro y MERGE_HEAD es de ellos.

git checkout HEAD -- path/to/file

o:

git checkout MERGE_HEAD -- path/to/file

Después de hacer esto y estamos bien:

git add .

Si desea comprender más, vea la maravillosa publicación de torek aquí: git checkout --ours no elimina archivos de la lista de archivos no fusionados

Nicolas D
fuente
12

Usuarios de IDE VS Code (Git integrado):

Si desea aceptar todos los cambios entrantes en el archivo de conflicto , realice los siguientes pasos.

1. Go to command palette - Ctrl + Shift + P
2. Select the option - Merge Conflict: Accept All Incoming

Del mismo modo, puede hacerlo para otras opciones como Aceptar todo, Aceptar todo actual, etc.

SridharKritha
fuente
2
Parece que eso solo funciona para un solo archivo, no todos los archivos con conflictos.
Yoryo
1

Tenía una next-versionrama de larga duración con toneladas de eliminaciones en archivos que habían cambiado develop, archivos que se habían agregado en diferentes lugares en ambas ramas, etc.

Quería next-versionincorporar todo el contenido de la rama develop, todo en una enorme confirmación de fusión.

La combinación de los comandos anteriores que funcionó para mí fue:

git merge -X theirs next-version
# lots of files left that were modified on develop but deleted on next-version
git checkout next-version .
# files removed, now add the deletions to the commit
git add .
# still have files that were added on develop; in my case they are all in web/
git rm -r web

No es una respuesta nueva, solo combina partes de muchas respuestas, en parte para asegurar que podría necesitar todas estas respuestas.

Gordon
fuente
1

Si ya está en estado de conflicto, y no desea pagar la ruta una por una. Puedes intentar

git merge --abort
git pull -X theirs
Lee Chee Kiam
fuente
-1

de https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging

Esto básicamente hará una fusión falsa. Grabará una nueva confirmación de fusión con ambas ramas como padres, pero ni siquiera mirará la rama en la que se está fusionando. Simplemente registrará como resultado de la fusión el código exacto en su rama actual.

$ git merge -s ours mundo

Fusión realizada por la estrategia 'nuestra'.

$ git diff HEAD HEAD~

Puede ver que no hay diferencia entre la rama en la que estábamos y el resultado de la fusión.

Esto a menudo puede ser útil para básicamente engañar a Git para que piense que una rama ya está fusionada cuando se fusiona más adelante. Por ejemplo, supongamos que se bifurcó de una rama de lanzamiento y ha realizado un trabajo sobre ella que querrá fusionar nuevamente en su rama maestra en algún momento. Mientras tanto, algunas correcciones de errores en el master deben ser transferidas a su rama de lanzamiento. Puede fusionar la rama de corrección de errores en la rama de lanzamiento y también fusionar la nuestra en la rama maestra (a pesar de que la solución ya está allí), de modo que cuando luego vuelva a fusionar la rama de lanzamiento, no haya conflictos de la corrección de errores.

Una situación que he encontrado útil si quiero que master refleje los cambios de una nueva rama de tema. He notado que -Xtheirs no se fusiona sin conflictos en algunas circunstancias ... por ejemplo

$ git merge -Xtheirs topicFoo 

CONFLICT (modify/delete): js/search.js deleted in HEAD and modified in topicFoo. Version topicFoo of js/search.js left in tree.

En este caso la solución que encontré fue

$ git checkout topicFoo

de topicFoo, primero fusionarse en master usando la estrategia -s our, esto creará la confirmación falsa que es solo el estado de topicFoo. $ git merge -s nuestro maestro

compruebe la confirmación de fusión creada

$ git log

ahora revisa la rama maestra

$ git checkout master

fusionar la rama del tema nuevamente, pero esta vez use la estrategia recursiva -Xtheirs, esto ahora le presentará una rama maestra con el estado de topicFoo.

$ git merge -X theirs topicFoo
Amos Folarin
fuente