tag - Git fusionarse con forzar sobrescribir
git tag (3)
No estoy realmente relacionado con esta respuesta, pero abandonaría
git pull
, que solo ejecuta
git fetch
seguido de
git merge
.
Estás haciendo tres fusiones, lo que hará que tu Git ejecute tres operaciones de recuperación, cuando una recuperación es todo lo que necesitarás.
Por lo tanto:
git fetch origin # update all our origin/* remote-tracking branches
git checkout demo # if needed -- your example assumes you''re on it
git merge origin/demo # if needed -- see below
git checkout master
git merge origin/master
git merge -X theirs demo # but see below
git push origin master # again, see below
Controlando la fusión más complicada
La parte más interesante aquí es
git merge -X theirs
.
Como
señaló root545
, las opciones
-X
se pasan a la estrategia de fusión, y tanto la estrategia
recursive
predeterminada como la estrategia de
resolve
alternativa toman
-X ours
o
-X theirs
(una u otra, pero no ambas).
Sin embargo, para comprender lo que hacen, debe saber cómo Git encuentra y trata los
conflictos de fusión
.
Un conflicto de fusión puede ocurrir dentro de algún archivo
1
cuando la versión
base
difiere tanto de la versión
actual
(también llamada local, HEAD o
--ours
)
como de
la otra versión (también llamada remota o
--theirs
) de ese mismo archivo.
Es decir, la fusión ha identificado tres revisiones (tres confirmaciones): base, la nuestra y la de ellos.
La versión "base" es de la
base de fusión
entre nuestro compromiso y su compromiso, como se encuentra en el gráfico de compromiso (para obtener más información sobre esto, consulte otras publicaciones de StackOverflow).
Git ha encontrado dos conjuntos de cambios: "lo que hicimos" y "lo que hicieron".
Estos cambios se encuentran (en general) línea por línea,
puramente textual
.
Git no tiene una comprensión real del contenido del archivo;
es simplemente comparar cada línea de texto.
Estos cambios son lo que ves en la salida de
git diff
, y como siempre, también tienen
contexto
.
Es posible que las cosas que cambiamos estén en diferentes líneas de las cosas que cambiaron, por lo que los cambios parecen no chocar, pero el contexto también ha cambiado (por ejemplo, debido a que nuestro cambio está cerca de la parte superior o inferior del archivo, para que el archivo se agote en nuestra versión, pero en la suya, también han agregado más texto en la parte superior o inferior).
Si los cambios ocurren en
diferentes
líneas, por ejemplo, cambiamos de
color
a
colour
en la línea 17 y cambian
fred
a
barney
en la línea 71, entonces no hay conflicto: Git simplemente toma
ambos
cambios.
Si los cambios ocurren en las mismas líneas, pero son cambios
idénticos
, Git toma
una copia
del cambio.
Solo si los cambios están en la misma línea, pero son cambios diferentes, o ese caso especial de contexto interferente, obtiene un conflicto de modificación / modificación.
Las opciones
-X ours
y
-X theirs
dicen a Git cómo resolver este conflicto, eligiendo solo uno de los dos cambios: el nuestro o el de ellos.
Dado que usted dijo que está fusionando la
demo
(la de ellos) en la
master
(la nuestra) y desea los cambios de la
demo
, desearía
-X theirs
.
Aplicar ciegamente
-X
, sin embargo, es peligroso.
El hecho de que nuestros cambios no entren en conflicto línea por línea no significa que nuestros cambios no entren en conflicto.
Un ejemplo clásico ocurre en idiomas con declaraciones variables.
La versión base puede declarar una variable no utilizada:
int i;
En nuestra versión, eliminamos la variable no utilizada para hacer que desaparezca una advertencia del compilador, y en
su
versión, agregan un bucle algunas líneas más tarde, usando
i
como contador de bucle.
Si combinamos los dos cambios, el código resultante ya no se compila.
La opción
-X
no es de ayuda aquí ya que los cambios están en
diferentes líneas
.
Si tiene un conjunto de pruebas automatizadas, lo más importante es ejecutar las pruebas después de la fusión.
Puede hacer esto después de comprometerse y arreglar las cosas más tarde si es necesario;
o puede hacerlo
antes de
comprometerse, agregando
--no-commit
al comando
git merge
.
Dejaremos los detalles de todo esto a otras publicaciones.
1
También puede obtener conflictos con respecto a las operaciones de "todo el archivo", por ejemplo, tal vez arreglemos la ortografía de una palabra en un archivo (para que tengamos un cambio) y
eliminen
todo el archivo (para que tengan un borrar).
Git no resolverá estos conflictos por sí solo, independientemente de los argumentos
-X
.
Hacer menos fusiones y / o fusiones más inteligentes y / o usar rebase
Hay tres fusiones en nuestras dos secuencias de comandos.
El primero es llevar el
origin/demo
a la
demo
local (el suyo usa
git pull
que, si su Git es muy antiguo, no podrá actualizar el
origin/demo
pero producirá el mismo resultado final).
El segundo es traer
origin/master
al
master
.
No me queda claro quién está actualizando la
demo
y / o
master
.
Si escribe su propio código en su propia rama de
demo
,
y
otros escriben código y lo envían a la rama de
demo
en
origin
, entonces esta fusión de primer paso puede tener conflictos o producir una fusión real.
La mayoría de las veces, es mejor usar rebase, en lugar de combinar, para combinar el trabajo (es cierto, esto es una cuestión de gustos y opiniones).
Si es así, es posible que desee utilizar
git rebase
en
git rebase
lugar.
Por otro lado, si nunca realiza ninguna de sus propias confirmaciones en la
demo
, ni siquiera
necesita
una rama de
demo
.
Alternativamente, si desea automatizar mucho de esto, pero puede verificar cuidadosamente cuando hay confirmaciones que usted y otros hicieron, es posible que desee usar
git merge --ff-only origin/demo
: esto será rápido- reenvíe su
demo
para que coincida con el
origin/demo
actualizado si es posible, y simplemente falle si no (en ese momento puede inspeccionar los dos conjuntos de cambios y elegir una fusión real o una nueva versión según corresponda).
Esta misma lógica se aplica a
master
, aunque está haciendo la fusión
en
master
, por lo que definitivamente necesita un
master
.
Sin embargo, es aún más probable que desee que la fusión falle si no se puede hacer como un avance rápido sin fusión, por lo que esto probablemente también debería ser
git merge --ff-only origin/master
.
Digamos que nunca haces tus propios commits en la
demo
.
En este caso podemos deshacernos por completo de la
demo
del nombre:
git fetch origin # update origin/*
git checkout master
git merge --ff-only origin/master || die "cannot fast-forward our master"
git merge -X theirs origin/demo || die "complex merge conflict"
git push origin master
Si
está
haciendo sus propias confirmaciones de la rama de
demo
, esto no es útil;
también podría mantener la fusión existente (pero tal vez agregar
--ff-only
según el comportamiento que desee), o cambiarlo a un rebase.
Tenga en cuenta que los tres métodos pueden fallar: la fusión puede fallar con un conflicto, la fusión con
--ff-only
puede no ser capaz de avanzar rápidamente, y el rebase puede fallar con un conflicto (el rebase funciona, en esencia,
mediante
compromisos de
selección de cereza
, que utiliza la maquinaria de combinación y, por lo tanto, puede generar un conflicto de combinación).
Tengo una rama llamada
demo
que necesito fusionar con la rama
master
.
Puedo obtener el resultado deseado con los siguientes comandos:
git pull origin demo
git checkout master
git pull origin master
git merge demo
git push origin master
Mi única preocupación es,
si hay algún problema de fusión
, quiero decirle a
git
que sobrescriba los cambios en la rama
master
sin darme un aviso de fusión.
Entonces, básicamente, los cambios en la rama de
demo
deberían sobrescribir automáticamente los cambios en la rama
master
.
Miré a mi alrededor, hay varias opciones, pero no quiero arriesgarme con la fusión.
Puedes probar la opción "nuestra" en git merge,
git merge branch -X nuestro
Esta opción obliga a los trozos en conflicto a que se resuelvan automáticamente limpiamente al favorecer nuestra versión. Los cambios del otro árbol que no entran en conflicto con nuestro lado se reflejan en el resultado de la fusión. Para un archivo binario, todo el contenido se toma de nuestro lado.
Tuve un problema similar, donde necesitaba reemplazar efectivamente cualquier archivo que tuviera cambios / conflictos con una rama diferente.
La solución que encontré fue usar
git merge -s ours branch
.
Tenga en cuenta que la opción es
-s
y no
-X
.
-s
denota el uso del
ours
como una estrategia de fusión de nivel superior,
-X
estaría aplicando la opción
ours
a la estrategia de fusión
recursive
, que no es lo que yo (o nosotros) queremos en este caso.
Pasos, donde
oldbranch
es la rama que desea sobrescribir con
newbranch
.
-
git checkout newbranch
comprueba la rama que desea mantener -
git merge -s ours oldbranch
fusiona en la rama anterior, pero conserva todos nuestros archivos. -
git checkout oldbranch
comprueba la rama que desea sobrescribir -
get merge newbranch
fusiona en la nueva sucursal, sobrescribiendo la antigua sucursal