Estoy intentando una maniobra de fusión git bastante robusta en este momento. Un problema con el que me encuentro es que hice algunos cambios en algún código en mi sucursal, pero mi colega movió ese código a un nuevo archivo en su sucursal. Entonces, cuando lo hice git merge my_branch his_branch
, git no notó que el código en el nuevo archivo era el mismo que el anterior, por lo que ninguno de mis cambios está allí.
¿Cuál es la forma más fácil de aplicar mis cambios nuevamente al código en los nuevos archivos? No tendré demasiados problemas para descubrir qué commits deben volver a aplicarse (solo puedo usar git log --stat
). Pero por lo que puedo decir, no hay forma de que git vuelva a aplicar los cambios en los nuevos archivos. Lo más fácil que estoy viendo en este momento es volver a aplicar manualmente los cambios, lo que no parece una buena idea.
Sé que git reconoce blobs, no archivos, por lo que seguramente debe haber una manera de decirlo, "aplique este cambio de código exacto desde este commit, excepto no dónde estaba sino dónde está ahora en este nuevo archivo".
--rename-threshold
opción para ajustar la cantidad de similitud que se requiere.Respuestas:
Tuve un problema similar y lo resolví modificando mi trabajo para que coincida con la organización del archivo de destino.
Digamos que modificó
original.txt
en su rama (lalocal
rama), pero en la rama maestra,original.txt
se ha copiado a otra, por ejemplocopy.txt
. Esta copia se ha realizado en un commit que llamamos commitCP
.Desea aplicar todos los cambios locales, confirmaciones
A
y aB
continuación, que se realizaron enoriginal.txt
el nuevo archivocopy.txt
.Cree una rama desechable
move
en el punto de partida de sus cambios congit branch move X
. Es decir, ponga lamove
rama en commitX
, la anterior a las commits que desea fusionar; Lo más probable es que este sea el compromiso desde el que se ramificó para implementar sus cambios. Como el usuario @digory doo escribió a continuación, puede hacergit merge-base master local
para encontrarX
.En esta rama, emita el siguiente comando de cambio de nombre:
Esto cambia el nombre del archivo. Tenga en cuenta que
copy.txt
todavía no existía en su árbol en este momento.Compromete tu cambio (llamamos a este compromiso
MV
).Ahora puede cambiar su trabajo por encima de
move
:Esto debería funcionar sin problemas y sus cambios se aplicarán
copy.txt
en su sucursal local.Ahora, no necesariamente desea o necesita comprometerse
MV
en el historial de su sucursal principal, porque la operación de mover puede generar un conflicto con la operación de copia al confirmarCP
en la sucursal principal.Solo tiene que volver a basar su trabajo nuevamente, descartando la operación de movimiento, de la siguiente manera:
... dónde
CP
está el commit dondecopy.txt
se introdujo en la otra rama. Esto reajusta todos los cambioscopy.txt
en la parte superior de laCP
confirmación. Ahora, sulocal
rama es exactamente como si siempre la modificaracopy.txt
y nooriginal.txt
, y puede continuar fusionándose con otros.Es importante que los cambios se apliquen
CP
o de lo contrariocopy.txt
no existirían y los cambios se volverían a aplicaroriginal.txt
.Espero que esto esté claro. Esta respuesta llega tarde, pero puede ser útil para otra persona.
fuente
patch
(que también implica mucho trabajo), y es por eso que pensé que podría ser interesante mostrarlo. Además, tenga en cuenta que me tomó más tiempo escribir la respuesta que aplicar los cambios, en mi caso. ¿En qué paso recomendarías usar una fusión? ¿y por qué? La única diferencia que veo es que al hacer un rebase, hago una confirmación temporal que luego se descarta (commitMV
), lo que no es posible solo con fusiones.Siempre puede usar
git diff
(ogit format-patch
) para generar el parche, luego editar manualmente los nombres de archivo en el parche y aplicarlo congit apply
(ogit am
).Aparte de esto, la única forma en que funcionará automáticamente es si la detección de cambio de nombre de git puede descubrir que los archivos antiguos y nuevos son lo mismo, lo que parece que no son realmente en su caso, solo una parte de ellos. Es cierto que git usa blobs, no archivos, pero un blob es solo el contenido de un archivo completo, sin el nombre de archivo y los metadatos adjuntos. Entonces, si tiene un fragmento de código movido entre dos archivos, no son realmente el mismo blob: el resto del contenido del blob es diferente, solo el fragmento en común.
fuente
git format-patch
trabajo para un compromiso. Si lo hagogit format-patch SHA1
, genera un montón de archivos de parche para toda la historia. Pero supongogit show SHA1 > diff.patch
que funcionará igual de bien.-1
opción. El modo normal de operación para el parche de formato es un rango de revisiónorigin/master..master
, por lo que puede preparar fácilmente una serie de parches.git apply
ygit am
son demasiado exigentes, porque quieren los mismos números de línea. Pero actualmente estoy teniendo éxito con elpatch
comando UNIX .Aquí hay una solución de fusión de encontrar un conflicto de fusión con renombrar y editar y resolverlo con mergetool reconociendo los 3 archivos de origen de fusión correctos.
Después de que una fusión falla debido al 'archivo eliminado' que se da cuenta de que fue renombrado y editado:
Recorrido:
Crea un archivo.txt:
Crea una rama donde editarás más tarde:
Crea el cambio de nombre y edita en master:
Cambia a rama y edita allí también:
Intento de fusionar maestro:
Observe que el conflicto es difícil de resolver y que los archivos fueron renombrados. Abortar, imitar el cambio de nombre:
Intenta fusionar de nuevo:
¡Excelente! La fusión da como resultado un conflicto 'normal' que se puede resolver con mergetool:
fuente
B.txt -> C.txt
yA.txt -> B.txt
con git mv, y git no podía hacer coincidir automáticamente los conflictos de fusión correctamente (estaba obteniendo conflictos de fusión entre lo antiguoB.txt
y lo nuevoB.txt
). Al usar este método, los conflictos de fusión ahora están entre los archivos correctos.