Elija la estrategia de combinación Git para archivos específicos ("nuestro", "mío", "suyo")

207

Estoy en medio de un rebase después de a git pull --rebase. Tengo algunos archivos que tienen conflictos de fusión. ¿Cómo puedo aceptar "sus" cambios o "mis" cambios para archivos específicos?

$ git status
# Not currently on any branch.
# You are currently rebasing.
#   (fix conflicts and then run "git rebase --continue")
#   (use "git rebase --skip" to skip this patch)
#   (use "git rebase --abort" to check out the original branch)
#
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:  CorrectlyMergedFile
#
# Unmerged paths:
#   (use "git reset HEAD <file>..." to unstage)
#   (use "git add <file>..." to mark resolution)
#
#       both modified: FileWhereIWantToAcceptTheirChanges
#       both modified: FileWhereIWantToAcceptMyChanges

Normalmente solo abro el archivo o una herramienta de combinación y acepto manualmente todos los cambios "sus" o "mis". Sin embargo, sospecho que me falta un comando git conveniente.

Además, tenga en cuenta que solo podré elegir una estrategia de fusión para cada archivo cuando vea qué archivos golpean conflictos y posiblemente cuáles son los conflictos.

Steven Wexler
fuente
@AbeVoelker No creo que eso resuelva mi problema. Quiero seleccionar una estrategia de fusión para archivos específicos. Además, tenga en cuenta que solo sabré qué combinación de estrategias usar cuando esté en mi rebase y veré qué archivos han tenido conflictos y cuáles son.
Steven Wexler
Edité esta pregunta para que sea más genérica: stackoverflow.com/questions/278081/… . ¿Quizás podamos cerrar esta pregunta como un duplicado de eso? ¿Es eso apropiado?
@TheShadow Eso me parece razonable.
Steven Wexler
No estaba seguro de si era apropiado cambiar el título de la otra pregunta a lo que hice, porque eliminé la parte sobre la resolución de archivos binarios. Restablecí la otra pregunta a lo que era anteriormente, por lo que esta pregunta actual todavía agrega valor.

Respuestas:

251

Para cada archivo en conflicto que obtenga, puede especificar

git checkout --ours -- <paths>
# or
git checkout --theirs -- <paths>

De los git checkoutdocumentos

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

--ours
--theirs
Cuando revise las rutas desde el índice, revise 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 desproteger dicha entrada del índice, la operación de desprotección fallará y no se desprotegerá 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.


fuente
9
¿Es posible aceptar theires para todos los archivos que quedan con numeración?
aslakjo
41
@aslakjo git rebase -s recursive -X <ours/theirs>o git merge -s recursive -X <ours/theirs>. Tenga en cuenta que para un rebase, "lo nuestro" y "lo suyo" se invierten de lo que son durante una fusión. Probablemente también podrías usar un archivo / shell glob, como git checkout --theirs -- *.txt.
2
¡Muchas gracias, @Cupcake, la reversión inesperada de ours/theirsrebase me estaba volviendo loco! (Tiene sentido ahora que pienso en cómo funciona realmente un rebase, pero no del todo intuitivo).
Dan Lenski
2
@DanLenski rebase en general es solo una herramienta realmente difícil de entender para las personas al principio, pero una vez que entiendes cómo funciona, puedes hacer todo tipo de cosas realmente poderosas con ella.
1
@VincentSels en realidad, necesitas enmascarar el carácter *, de lo contrario, el shell intentará expandirlo. así que en tu caso git checkout --outs -- "**/*.csproj"harás lo que quieres decir. Lo mismo es cierto, por ejemplo, para git lfs track "*.jpg". Si tiene algunos archivos jpg en su CWD, sin las comillas, solo estos serán rastreados.
eFloh
117

A pesar de que esta pregunta es respondida, brinda un ejemplo de lo que significa "suyo" y "nuestro" en el caso de git rebase vs merge. Ver este enlace

Git Rebase
theirs es en realidad la rama actual en el caso de rebase . Por lo tanto, el siguiente conjunto de comandos en realidad está aceptando los cambios actuales de su rama en la rama remota.

# see current branch
$ git branch
... 
* branch-a
# rebase preferring current branch changes during conflicts
$ git rebase -X theirs branch-b

Git Merge
Para fusionar , el significado de theirsy oursse invierte. Por lo tanto, para obtener el mismo efecto durante una fusión , es decir, mantener los cambios de rama actuales ( ours) sobre la rama remota que se está fusionando ( theirs).

# assuming branch-a is our current version
$ git merge -X ours branch-b  # <- ours: branch-a, theirs: branch-b
Abe
fuente
2
bueno, esta es una distinción bastante importante! gracias por aclararlo.
verboze el
26

Tenga en cuenta que git checkout --ours|--theirsva a sobrescribir los archivos por completo , ya sea por la elección theirso la oursversión, que podría ser o no ser lo que quiere hacer (si tiene cualquier cambio no conflictivas que vienen desde el otro lado, se perderán).

Si, por el contrario, desea realizar una fusión tripartita en el archivo y solo resuelve los trozos en conflicto utilizando --ours|--theirs, mientras mantiene a los trozos no conflictivos de ambos lados en su lugar, puede recurrir a git merge-file; ver detalles en esta respuesta .

jakub.g
fuente
1
Con respecto a los "cambios no conflictivos" que se perderán, ¿esto se refiere solo a los archivos donde hay cambios no conflictivos en líneas específicas en otro lugar del mismo archivo, o todos los cambios de todos los archivos en historiales alineados?
ktamlyn
2
@ktamlyn por "cambios no conflictivos" quise decir cambios en el mismo archivo. Por ejemplo, hay dos trozos (partes) cambiados example.txten la oursversión, uno está en conflicto (también cambiado en la theirsrevisión), otro no está en conflicto. Si lo hace git checkout --theirs example.txt, leerá ciegamente todo el archivo en la theirsrevisión y se perderá la parte no conflictiva del diff.
jakub.g
1
¡Gracias! Esta fue una aclaración necesaria para mí, a pesar de que "cambios en el mismo archivo" tiene más sentido en este contexto.
ktamlyn
Esta debería ser la respuesta aceptada, bueno, aunque en realidad no da una respuesta, pero señala un problema importante en la otra solución propuesta.
tomasyany
1
Si desea volver al archivo en conflicto original, puede ejecutarlo git checkout --merge <path>.
Andrew Keeton