origin force example español git git-merge

force - ¿Existe una versión "suya" de "git merge-s ours"?



git merge squash (18)

Al fusionar la rama de tema "B" en "A" utilizando git merge , obtengo algunos conflictos. Sé que todos los conflictos se pueden resolver utilizando la versión en "B".

Soy consciente de git merge -s ours . Pero lo que quiero es algo como git merge -s theirs .

¿Por qué no existe? ¿Cómo puedo lograr el mismo resultado después de la fusión conflictiva con los comandos git existentes? ( git checkout todos los archivos sin combinar de B)

ACTUALIZACIÓN: La "solución" de simplemente descartar cualquier cosa de la rama A (el punto de confirmación de fusión a la versión B del árbol) no es lo que estoy buscando.


¿Por qué no existe?

Si bien menciono en "el comando git para hacer una rama como otra " cómo simular las de git merge -s theirs , tenga en cuenta que Git 2.15 (Q4 2017) ahora es más claro:

La documentación para '' -X<option> '' para fusiones fue escrita de manera engañosa para sugerir que existe " -s theirs ", lo cual no es el caso.

Ver commit c25d98b (25 de septiembre de 2017) por Junio ​​C Hamano ( gitster ) .
(Fusionada por Junio ​​C Hamano - gitster - in commit 4da3e23 , 28 sep 2017)

fusionar-estrategias: evite implicar que " -s theirs " existe

La descripción de la opción de combinación -Xours tiene una nota entre paréntesis que le dice a los lectores que es muy diferente de la -s ours , que es correcta, pero la descripción de -Xtheirs que la sigue descuidadamente dice "esto es lo contrario de la ours ", dando una falsa impresión de que los lectores también deben ser advertidos de que es muy diferente de los -s theirs , que en realidad ni siquiera existe.

-Xtheirs es una opción de estrategia aplicada a la estrategia recursiva. Esto significa que la estrategia recursiva aún combinará todo lo que pueda, y solo recurrirá a la lógica " theirs " en caso de conflictos.

Ese debate sobre la pertinencia o no de una estrategia de fusión de theirs se recuperó recientemente en este hilo de septiembre de 2017 .
Reconoce hilos antiguos (2008)

En resumen, la discusión anterior se puede resumir como "no queremos '' -s theirs '', ya que fomenta el flujo de trabajo incorrecto".

Menciona el alias:

mtheirs = !sh -c ''git merge -s ours --no-commit $1 && git read-tree -m -u $1'' -

Yaroslav Halchenko intenta abogar una vez más por esa estrategia, pero Junio ​​C. Hamano agrega :

La razón por la que los nuestros y los suyos no son simétricos es porque usted es usted y no ellos: el control y la propiedad de nuestra historia y su historia no es simétrica.

Una vez que decida que su historial es la línea principal, preferirá tratar su línea de desarrollo como una rama lateral y hacer una fusión en esa dirección, es decir, el primer padre de la combinación resultante es un compromiso en su historial y el segundo El padre es el último malo de tu historia. Por lo tanto, terminaría usando " checkout their-history && merge -s ours your-history " para que la primera paternidad sea sensata.

Y en ese punto, el uso de " -s ours " ya no es una solución alternativa por falta de " -s theirs ".
Es una parte apropiada de la semántica deseada, es decir, desde el punto de vista de la línea de la historia canónica sobreviviente, usted desea preservar lo que hizo, anulando lo que hizo la otra línea de la historia .


Al fusionar la rama de tema "B" en "A" utilizando git merge, obtengo algunos conflictos. Sé que todos los conflictos se pueden resolver usando la versión en "B".

Soy consciente de git merge -s el nuestro. Pero lo que quiero es algo como git merge> -s his.

Supongo que creaste una rama fuera del maestro y ahora quieres volver a unirte al maestro, anulando cualquiera de las cosas antiguas en el maestro. Eso es exactamente lo que quería hacer cuando me topé con esta publicación.

Haga exactamente lo que quiere hacer, excepto fusionar una rama en la otra primero. Acabo de hacer esto, y funcionó muy bien.

git checkout Branch git merge master -s ours

Luego, extraiga el maestro y fusione su rama en él (ahora irá sin problemas):

git checkout master git merge Branch


ACTUALIZAR

Mientras que la segunda respuesta responde a la pregunta original del OP, no refleja la intención actualizada de la pregunta del OP.

Lo que estás buscando no es lo contrario del comando git merge -s ours que estás buscando, lo contrario del comando git merge -s recursive -X ours , que es git merge -s recursive -X theirs

Respuesta original

ramas originales dadas

* 0123456 (HEAD->A, origin/A) | * 1234556 (origin/B, B) |/ * ??????? (common root)

para fusionar la rama B en A mientras se ignora el estado de la rama A, primero haga una combinación regular

git merge -s ours B (this is the opposite of what we want)

esto resulta en

* 2345678 (HEAD->A) Merge branch ''B'' into A (all wrong) |/ * | 0123456 (origin/A) | * 1234567 (origin/B, B) |/ * ??????? (common root)

No presione esta combinación ya que la ID de compromiso cambiará (y está mal de cualquier manera) ahora podemos cambiar, después del hecho, la estrategia ours en una estrategia theirs

no olvide anotar el ID de confirmación de la fusión, ya que no estará disponible después del próximo restablecimiento completo. (Si olvida que no se hará ningún daño, tendrá que hacer un restablecimiento completo en A y comenzar de nuevo).

git reset --hard B (this is what we want the merge to look like (the merge can now only be referenced by the commit id `2345678`)) git reset --soft 2345678 (without changing any files go back to the merge) git commit --amend (branch B is now the final version of the merge)

ahora tenemos

* 3456789 (HEAD->A) Merge branch ''B'' into A (correctly ignores changes from 0123456) |/ * | 0123456 (origin/A) | * 1234567 (origin/B, B) |/ * ??????? (common root) $ diff HEAD B [... no changes ...] git push

hecho

Necesitaba hacer esto cuando un compañero de trabajo aplicó mis cambios A a su sucursal independiente B sin fusionar, esto me permite aceptar sus modificaciones en mi sucursal.


Añade la opción -X a la de theirs . Por ejemplo:

git checkout branchA git merge -X theirs branchB

Todo se fusionará de la forma deseada.

Lo único que he visto que causa problemas es si los archivos se eliminaron de branchB. Se muestran como conflictos si algo más que git hizo la eliminación.

La solución es fácil. Simplemente ejecute git rm con el nombre de los archivos que se eliminaron:

git rm {DELETED-FILE-NAME}

Después de eso, los -X theirs deberían funcionar como se espera.

Por supuesto, hacer la eliminación real con el comando git rm evitará que el conflicto ocurra en primer lugar.

Nota : También existe una opción de formulario más largo. Para usarlo, reemplaza:

-X theirs

con:

--strategy-option=theirs


Consulte la respuesta ampliamente citada de Junio ​​Hamano : si va a descartar el contenido comprometido, simplemente descarte los compromisos o, en todo caso, manténgalo fuera de la historia principal. ¿Por qué molestar a todos en el futuro leyendo mensajes de confirmación que no tienen nada que ofrecer?

Pero a veces hay requisitos administrativos, o quizás alguna otra razón. Para aquellas situaciones en las que realmente tiene que grabar confirmaciones que no aportan nada, desea:

(Edit: wow, me las arreglé para hacerlo mal antes. Este funciona.)

git update-ref HEAD $( git commit-tree -m ''completely superseding with branchB content'' / -p HEAD -p branchB branchB: ) git reset --hard


Creo que lo que realmente quieres es:

git checkout -B mergeBranch branchB git merge -s ours branchA git checkout branchA git merge mergeBranch git branch -D mergeBranch

Esto parece torpe, pero debería funcionar. Lo único que realmente me disgusta de esta solución es que el historial de git será confuso ... Pero al menos el historial se conservará por completo y no tendrá que hacer nada especial para los archivos eliminados.


El equivalente (que mantiene el orden principal) a ''git merge -s theirs branchB''

Antes de fusionar:

!!! Asegúrese de que está en estado limpio!

Hacer la fusión

git commit-tree -m "take theirs" -p HEAD -p branchB ''branchB^{tree}'' git reset --hard 36daf519952 # is the output of the prev command

Lo que hicimos ? Creamos un nuevo compromiso, el cual dos padres, el nuestro y el suyo, y la red de contacto del compromiso es branchB - thes

Después de fusionar:

Más precisamente:

git commit-tree -m "take theirs" -p HEAD -p ''SOURCE^{commit}'' ''SOURCE^{tree}''


Este utiliza un comando de git plumbing read-tree, pero permite un flujo de trabajo general más corto.

git checkout <base-branch> git merge --no-commit -s ours <their-branch> git read-tree -u --reset <their-branch> git commit # Check your work! git diff <their-branch>


Esto fusionará su newBranch en baseBranch existente

git checkout <baseBranch> // this will checkout baseBranch git merge -s ours <newBranch> // this will simple merge newBranch in baseBranch git rm -rf . // this will remove all non references files from baseBranch (deleted in newBranch) git checkout newBranch -- . //this will replace all conflicted files in baseBranch


Hace poco necesité hacer esto para dos repositorios separados que comparten un historial común. Comencé con:

  • Org/repository1 master
  • Org/repository2 master

Quería que todos los cambios del repository2 master se aplicaran al repository1 master , aceptando todos los cambios que el repository2 haría. En términos de git, esta debe ser una estrategia llamada -s theirs PERO no existe. Tenga cuidado porque -X theirs nombre se llama como si fuera lo que usted quiere, pero NO es lo mismo (incluso lo dice en la página del manual).

La forma en que resolví esto fue ir al repository2 y hacer una nueva rama repo1-merge . En esa rama, corrí git pull [email protected]:Org/repository1 -s ours y se fusiona bien sin problemas. Luego lo empujo hacia el control remoto.

Luego vuelvo al repository1 y hago una nueva rama repo2-merge . En esa rama, ejecuto git pull [email protected]:Org/repository2 repo1-merge que se completará con los problemas.

Finalmente, deberías emitir una solicitud de combinación en el repository1 para convertirlo en el nuevo maestro, o simplemente mantenerlo como una rama.


Las versiones anteriores de git le permitieron usar la estrategia de fusión "ellos":

git pull --strategy=theirs remote_branch

Pero esto ya ha sido eliminado, como lo explica Junio ​​Hamano (el mantenedor de Git) en este mensaje. Como se señaló en el enlace, en su lugar, haría esto:

git fetch origin git reset --hard origin

Tenga en cuenta, sin embargo, que esto es diferente de una fusión real. Su solución es probablemente la opción que realmente está buscando.


No está del todo claro cuál es el resultado deseado, por lo que existe cierta confusión sobre la forma "correcta" de hacerlo en las respuestas y sus comentarios. Intento dar una visión general y ver las siguientes tres opciones:

Intenta unir y usar B para conflictos

Esta no es la "versión de ellos para git merge -s ours " sino la "versión de ellos para git merge -X ours " (que es la abreviatura de git merge -s recursive -X ours ):

git checkout branchA # also uses -s recursive implicitly git merge -X theirs branchB

Esto es lo que hace, por ejemplo, la respuesta de Alan W. Smith .

Usa contenido de B solamente

Esto crea una confirmación de fusión para ambas ramas, pero descarta todos los cambios de la branchA y solo mantiene el contenido de la branchB

# Get the content you want to keep. # If you want to keep branchB at the current commit, you can add --detached, # else it will be advanced to the merge commit in the next step. git checkout branchB # Do the merge an keep current (our) content from branchB we just checked out. git merge -s ours branchA # Set branchA to current commit and check it out. git checkout -B branchA

Tenga en cuenta que la combinación confirma que el primer padre ahora es el de branchB y solo el segundo es de branchA . Esto es lo que hace, por ejemplo, la respuesta de Gandalf458 .

Use el contenido de B solamente y mantenga el orden de los padres correcto

Esta es la verdadera "versión de ellos para git merge -s ours ". Tiene el mismo contenido que en la opción anterior (es decir, solo el de branchB ) pero el orden de los padres es correcto, es decir, el primer padre proviene de branchA y el segundo de branchB .

git checkout branchA # Do a merge commit. The content of this commit does not matter, # so use a strategy that never fails. # Note: This advances branchA. git merge -s ours branchB # Change working tree and index to desired content. # --detach ensures branchB will not move when doing the reset in the next step. git checkout --detach branchB # Move HEAD to branchA without changing contents of working tree and index. git reset --soft branchA # ''attach'' HEAD to branchA. # This ensures branchA will move when doing ''commit --amend''. git checkout branchA # Change content of merge commit to current index (i.e. content of branchB). git commit --amend -C HEAD

Esto es lo que hace la respuesta de Paul Pladijs (sin requerir una sucursal temporal).


Para realizar realmente una combinación que solo toma la entrada de la rama que está fusionando, puede hacer

git merge --strategy=ours ref-to-be-merged

git diff --binary ref-to-be-merged | git apply --reverse --index

git commit --amend

No habrá conflictos en ningún escenario que conozca, no tiene que crear sucursales adicionales, y actúa como una confirmación de fusión normal.

Sin embargo, esto no funciona bien con los submódulos.


Resolví mi problema usando

git checkout -m old git checkout -b new B git merge -s ours old


Si estás en la rama A haz:

git merge -s recursive -X theirs B

Probado en git versión 1.7.8


Una forma simple e intuitiva (en mi opinión) de hacerlo en dos pasos es

git checkout branchB . git commit -m "Picked up the content from branchB"

seguido por

git merge -s ours branchB

(que marca las dos ramas como fusionadas)

La única desventaja es que no elimina los archivos que se han eliminado en branchB de su rama actual. Una simple diferencia entre las dos ramas más adelante mostrará si existen tales archivos.

Este enfoque también deja claro, a partir del registro de revisiones, lo que se hizo y lo que se pretendía.


Una solución posible y probada para fusionar branchB en nuestra sucursal desprotegida A:

# in case branchA is not our current branch git checkout branchA # make merge commit but without conflicts!! # the contents of ''ours'' will be discarded later git merge -s ours branchB # make temporary branch to merged commit git branch branchTEMP # get contents of working tree and index to the one of branchB git reset --hard branchB # reset to our merged commit but # keep contents of working tree and index git reset --soft branchTEMP # change the contents of the merged commit # with the contents of branchB git commit --amend # get rid off our temporary branch git branch -D branchTEMP # verify that the merge commit contains only contents of branchB git diff HEAD branchB

Para automatizarlo, puede envolverlo en un script utilizando branchA y branchB como argumentos.

Esta solución conserva el primer y segundo padre de la confirmación de fusión, tal como se esperaría de git merge -s theirs branchB .


Usé la respuesta de Paul Pladijs desde ahora. Descubrí que puede hacer una fusión "normal", se producen conflictos, por lo que hace

git checkout --theirs <file>

para resolver el conflicto usando la revisión de la otra rama. Si hace esto para cada archivo, tiene el mismo comportamiento que esperaría de

git merge <branch> -s theirs

De todos modos, el esfuerzo es más de lo que sería con la estrategia de fusión. (Esto fue probado con la versión git 1.8.0)