¿Cómo puedo descartar cambios remotos y marcar un archivo como "resuelto"?

197

Tengo algunos archivos locales, los extraigo de una rama remota y hay conflictos. Sé que me gustaría mantener mis cambios locales e ignorar los cambios remotos que causan conflictos. ¿Hay algún comando que pueda usar para decir "marcar todos los conflictos como resueltos, usar local"?

Tom DeMille
fuente
1
La respuesta a continuación me ha sido súper esclarecedora. Hay un par de puntos sutiles que realmente me aclaran las cosas, recomiendo a los usuarios no expertos de GIT que lean todos los comentarios debajo de la publicación a continuación, ¡y gracias Brian!
Tom DeMille

Respuestas:

332

git checkouttiene la --oursopción de verificar la versión del archivo que tenía localmente (en oposición a --theirscuál es la versión que introdujo). Puedes pasar .a git checkoutdecirle que revise todo en el árbol. Luego, debe marcar los conflictos como resueltos, lo que puede hacer git addy comprometer su trabajo una vez hecho:

git checkout --ours .  # checkout our local version of all files
git add -u             # mark all conflicted files as merged
git commit             # commit the merge

Tenga .en cuenta el en el git checkoutcomando. Eso es muy importante y fácil de perder. git checkouttiene dos modos; uno en el que cambia las ramas y otro en el que extrae los archivos del índice a la copia de trabajo (a veces, primero los saca al índice de otra revisión). La forma en que se distingue es si ha pasado un nombre de archivo; si no ha pasado un nombre de archivo, intenta cambiar de rama (aunque si no pasa tampoco, solo intentará volver a revisar la rama actual), pero se niega a hacerlo si hay archivos modificados que eso afectaría. Entonces, si desea un comportamiento que sobrescribirá los archivos existentes, debe pasar .o un nombre de archivo para obtener el segundo comportamiento git checkout.

También es un buen hábito tener, al pasar un nombre de archivo, para compensarlo con --, como git checkout --ours -- <filename>. Si no hace esto, y el nombre de archivo coincide con el nombre de una rama o etiqueta, Git pensará que desea verificar esa revisión, en lugar de verificar ese nombre de archivo, y así usar la primera forma del checkoutcomando .

Expandiré un poco sobre cómo funcionan los conflictos y la fusión en Git. Cuando se fusiona en el código de otra persona (que también ocurre durante una extracción; una extracción es esencialmente una búsqueda seguida de una fusión), hay pocas situaciones posibles.

Lo más simple es que estás en la misma revisión. En este caso, ya está "actualizado" y no sucede nada.

Otra posibilidad es que su revisión sea simplemente un descendiente suyo, en cuyo caso, de forma predeterminada, tendrá una "fusión de avance rápido", en la que HEADsimplemente se actualiza a su confirmación, sin que ocurra la fusión (esto puede desactivarse si usted realmente quiero grabar una fusión, usando--no-ff ).

Luego entras en las situaciones en las que realmente necesitas fusionar dos revisiones. En este caso, hay dos resultados posibles. Una es que la fusión ocurre limpiamente; Todos los cambios están en archivos diferentes, o están en los mismos archivos pero lo suficientemente separados como para que ambos conjuntos de cambios puedan aplicarse sin problemas. Por defecto, cuando una fusión limpia sucede, se compromete de forma automática, aunque se puede desactivar esto con --no-commitsi usted necesita para editar antemano (por ejemplo, si cambia el nombre de función fooa bar, y otra persona añade un nuevo código que llama foo, que se fusionarán limpiamente , pero produzca un árbol roto, por lo que es posible que desee limpiarlo como parte de la confirmación de fusión para evitar tener confirmaciones dañadas).

La posibilidad final es que haya una fusión real y haya conflictos. En este caso, Git va a hacer la mayor cantidad de la fusión, ya que puede, y producen archivos con marcas de conflicto ( <<<<<<<, =======y >>>>>>>) en su copia de trabajo. En el índice (también conocido como "área de preparación"; el lugar donde se almacenan los archivos git addantes de confirmarlos), tendrá 3 versiones de cada archivo con conflictos; existe la versión original del archivo del antepasado de las dos ramas que está fusionando, la versión de HEAD(su lado de la fusión) y la versión de la rama remota.

Para resolver el conflicto, puede editar el archivo que está en su copia de trabajo, eliminando los marcadores de conflicto y arreglando el código para que funcione. O bien, puede consultar la versión desde uno u otro lado de la fusión, usando git checkout --ourso git checkout --theirs. Una vez que haya colocado el archivo en el estado que desea, indica que ha terminado de fusionar el archivo y que está listo para comprometerse a usarlo git add, y luego puede hacerlo git commit.

Brian Campbell
fuente
77
Probablemente debería tener en cuenta que git add --allagrega todos los archivos al repositorio, por lo que puede agregar más archivos de los previstos a menos que sus .gitignorepatrones estén en perfecto estado. git add -uprobablemente sea más adecuado para esta situación, es menos probable que tenga modificaciones en los archivos rastreados que no desea agregar al resolver una fusión.
CB Bailey
Ups, lo siento. A eso me refería. Corregido ahora.
Brian Campbell
1
Gracias por tu respuesta detallada. De hecho, intenté git checkout --ours y recibí un mensaje de error (que no recuerdo ahora). Los archivos en cuestión son dll (tenemos algunos que ocultamos, referencias de terceros en su mayoría) y solo quería decir 'ok, mi copia es la que quiero, pero el error fue algo así como' no puedo pagar al fusionar ' ..... Mantendré este artículo como referencia y la próxima vez que ocurra, inténtelo nuevamente y vea si funciona o si puedo publicar ese mensaje. Gracias de nuevo
Tom DeMille
pero su explicación me aclara mucho sobre el proceso, gracias de nuevo ... Pregunta de seguimiento: ¿Alguna forma de obtener git para eliminar los archivos .orig una vez que se haya solucionado la fusión?
Tom DeMille
2
Que tiene que hacer git checkout --ours .. El .es importante; pasar un nombre de archivo (en este caso, el directorio completo) selecciona entre dos modos diferentes de operación checkout, uno que cambia las ramas y otro que mueve los archivos desde el índice a la copia de trabajo. Estoy de acuerdo, es muy confuso. También puede hacer git checkout --ours -- <filename>para revisar un archivo individual a la vez.
Brian Campbell el