¿Hay una opción git-merge --dry-run?

725

Me estoy fusionando en una rama remota que puede tener muchos conflictos. ¿Cómo puedo saber si tendrá conflictos o no?

No veo nada como un --dry-runencendido git-merge.

Otón
fuente
55
Dado que la ramificación es barata con Git, ¿por qué no pagar una copia y luego no necesita hacer una ejecución en seco? Puedes tirar la copia después.
Alexander Mills

Respuestas:

812

Como se señaló anteriormente, pase la --no-commitbandera, pero para evitar una confirmación de avance rápido, también pase --no-ff, así:

$ git merge --no-commit --no-ff $BRANCH

Para examinar los cambios organizados:

$ git diff --cached

Y puede deshacer la fusión, incluso si es una fusión de avance rápido:

$ git merge --abort
mipadi
fuente
51
Esto es genial, pero aún modificará su copia de trabajo. Si tu repositorio es un servidor web en vivo, entonces usted podría estar sirviendo archivos con conflictos en.
dave1010
21
Realmente no puede hacer una fusión sin afectar la copia de trabajo.
mipadi
55
Es cierto, pero algo como git merge --only-if-there-wont-be-any-conflictso git diff --show-conflicts <commit>sería realmente útil. Es una pena que todavía no sea posible, o me estoy perdiendo algo
dave1010
344
@ dave1010 ¡Nunca deberías manejar fusiones en un servidor web en vivo! ¡Para eso está tu caja de desarrollo! Arregle la rama "prod" y luego empújela al servidor web real.
jpswain
52
Si trabaja en un servidor en vivo / producción, ¡nunca querrá hacer otra cosa que no sea git pull --ff-only!
ThiefMaster
237

Simplemente tuve que implementar un método que encuentra automáticamente conflictos entre un repositorio y su control remoto. Esta solución se fusiona en la memoria para que no toque el índice ni el árbol de trabajo. Creo que esta es la forma más segura posible de resolver este problema. Así es como funciona:

  1. Obtenga el control remoto en su repositorio. Por ejemplo: git fetch origin master
  2. Ejecute git merge-base: git merge-base FETCH_HEAD master
  3. Ejecute git merge-tree: git merge-tree mergebase master FETCH_HEAD( mergebase es la identificación hexadecimal que merge-base imprimió en el paso anterior)

Ahora suponga que desea fusionar el maestro remoto con su maestro local, pero puede usar cualquier rama. git merge-treeejecutará la fusión en la memoria e imprimirá el resultado en la salida estándar. Grep para el patrón <<o >>. O puede imprimir el resultado en un archivo y verificarlo. Si encuentra una línea que comienza con 'cambiado en ambos', lo más probable es que haya un conflicto.

akostajti
fuente
41
Esta respuesta está subestimada, en mi humilde opinión, ya que es una solución limpia sin tocar la copia de trabajo o el índice.
sschuberth
23
Por cierto, los pasos 2 y 3 se pueden combinar en un solo paso, utilizando el operador de backtick de la consola de Linux, que evalúa en su lugar su contenido:git merge-tree `git merge-base FETCH_HEAD master` FETCH_HEAD master
jakub.g
15
Agregue a [alias] en .gitconfig: dry = "! F () {git merge-tree` git merge-base $ 2 $ 1` $ 2 $ 1;}; f "# verifique cómo irá la fusión de dev en master: git dry maestro de desarrollo
Noel
8
Mi nueva línea GIT favorita: ¡ git merge-tree `git merge-base clieop master` clieop master | grep -A3 "changed in both"simplemente increíble! +100
Rudie
44
Al probar esto, encontré grepping para combinaciones de banderas 'cambiadas en ambas' donde ambas ramas modifican el mismo archivo, incluso si no dan lugar a un conflicto de fusión. Para identificar solo conflictos reales, me pareció necesario buscar grep para el marcado de conflicto que comienza así: +<<<<<<< .ourpor lo tanto, uso una expresión grep comogrep -q '^+<* \.our$'
Guy
55

Mi solución simple de fuerza bruta para esto es:

  1. Crear una rama "pre-master" (del maestro, por supuesto)

  2. Combina todas las cosas que quieras en este pre-master.
    Entonces puedes ver cómo ocurrió la fusión sin tocar al maestro.

    • Fusionar pre-master en master O
    • Fusiona todas las ramas liberadas de wannabe en master

De todos modos, seguiría el consejo de @ orange80.

infierno
fuente
55
Me gusta la solución @akostajti, pero esta es otra opción subestimada. De hecho, prefiero estar a la defensiva y crear una nueva rama temporal (por supuesto, solo cuando espero conflictos, de lo contrario será una exageración), y si algo sale mal, simplemente elimínelo.
jakub.g
1
No sé si esta es una solución "sucia" o no, pero realmente hace el trabajo. ¡Me gusta! (Y)
Sara
3
Esta debería ser la solución aceptada, imo. Es rápido, fácil, seguro, reversible, intuitivo, y mientras no haya cambios no comprometidos antes de comenzar, no tendrá efectos secundarios.
Bob Ray
3
Esta solución te dice que no entiendes cómo funciona git. Las ramas son solo punteros y solo está creando un puntero redundante. Tiene el mal presentimiento de que de alguna manera puede dañar la fusión de su rama, pero no puede. Siempre puede hacerlo git merge --abortsi hay conflictos, git reset --hard HEAD~1si hubo una fusión o git reset --hard origin/master. Crear otra rama te da una sensación de seguridad, pero si aprendes cómo funciona git, entenderás que es un miedo fuera de lugar. Cuando la preocupación es por no cambiar la copia de trabajo, esto no ofrece solución.
Thibault D.
@ thibault-d Piensa en lo compleja que es la solución cuando no comienzas con una rama limpia. git merge --no-commitno abortará una fusión si se puede reenviar rápidamente. git merge --abortno funciona si se fusionó. Si desea escribir esto como un script, es incómodo, ya git mergeque no responde con códigos de error lo suficientemente buenos como para explicar los diferentes tipos de conflictos. Trabajar con una rama nueva evita que un script roto deje su repositorio en un estado que requiera intervención manual. Claro que no puedes perder nada. Pero es más fácil construir de otra manera.
Erik Aronesty
47

Deshacer una fusión con git es tan fácil que ni siquiera debería preocuparse por la ejecución en seco:

$ git pull $REMOTE $BRANCH
# uh oh, that wasn't right
$ git reset --hard ORIG_HEAD
# all is right with the world

EDITAR: Como se señala en los comentarios a continuación, si tiene cambios en su directorio de trabajo o área de preparación, probablemente desee guardarlos antes de hacer lo anterior (de lo contrario, desaparecerán después de lo git resetanterior)

Brian Phillips
fuente
77
Simplemente verificar si una fusión será un avance rápido (FF) es una cuestión de verificar la lista git branch --contains HEADo incluso más directamente, solo usegit merge --ff-only
Brian Phillips el
77
git reset --hard es uno de los pocos comandos de eliminación de información sin retroceso que tiene git, por lo que debe usarse con extrema precaución. Como tal, -1
Kzqai
8
@Tchalvak todavía hay reflog.
Kissaki
3
--dry-runno "simplemente comprobaría si una fusión se adelantará". Devolvería el resultado exacto que haría una fusión: archivos, conflictos, etc. Si will ff no es realmente interesante, ¿verdad?
Rudie
3
¿qué tal git stash; git reset --hard? @BrianPhillips
Code Whisperer
41

Hice un alias para hacer esto y funciona de maravilla, hago esto:

 git config --global alias.mergetest '!f(){ git merge --no-commit --no-ff "$1"; git merge --abort; echo "Merge aborted"; };f '

Ahora solo llamo

git mergetest <branchname>

Para averiguar si hay conflictos.

Okonomiyaki3000
fuente
¡Brillante! Me quedo con esto.
qbert65536
28

Simplemente diferencie su rama actual contra la rama remota, esto le dirá qué va a cambiar cuando haga una extracción / fusión.

#see diff between current master and remote branch
git diff master origin/master
timh
fuente
1
Idea interesante. ¿Cómo vería ese resultado y determinaría si la fusión funcionará o no?
MatrixFrog
66
Esto no le dirá si ocurrirán conflictos ... pero le dará una idea general de lo que sucederá si hiciera una extracción / fusión.
Timh
10
Esto solo le dirá la diferencia entre las dos ramas, no le dirá cuál será el resultado de la fusión. Esta es una distinción importante ya que la fusión en algunos casos tomará automáticamente los cambios de diferentes ramas dependiendo de cuándo se comprometieron. Entonces, en esencia, hacer una diferencia podría hacerte pensar que algunos de tus cambios se revertirán cuando, en realidad, el proceso de fusión tomará automáticamente cambios más nuevos que los anteriores. Espero que tenga sentido.
markquezada
3
Para construir sobre el comentario de @ mirthlab, habrá una diferencia significativa entre diff y merge si alguien realizó previamente una fusión con la estrategia de fusión "nuestra" (o alguna otra reparación manual de fusión); el diff también le mostrará las diferencias que ya se cuentan como "fusionadas".
Tao
21

Yo uso el comando request-pull git para hacerlo. Le permite ver cada cambio que sucedería al fusionar, pero sin hacer nada en sus repositorios locales o remotos .

Por ejemplo, imagine que desea fusionar una rama llamada "feature-x" en su rama maestra

git request-pull master origin feature-x

le mostrará un resumen de lo que sucedería (sin hacer nada):

The following changes since commit fc01dde318:
    Layout updates (2015-06-25 11:00:47 +0200)
are available in the git repository at:
    http://fakeurl.com/myrepo.git/ feature-x
for you to fetch changes up to 841d3b41ad:
----------------------------------------------------------------
john (2):
    Adding some layout
    Refactoring
ioserver.js            |   8 +++---
package.json           |   7 +++++-
server.js              |   4 +--
layout/ldkdsd.js       | 277 +++++++++++++++++++++++++++++++++++++
4 files changed, 289 insertions(+), 7 deletions(-)
create mode 100644 layout/ldkdsd.js

Si agrega el -pparámetro, también obtendrá el texto completo del parche, exactamente como si estuviera haciendo un git diff en cada archivo modificado.

ArnaudR
fuente
3
Podría aclarar esto un poco agregando qué mastery originhacer en las opciones de línea de comandos, y ¿qué pasa si estoy, por ejemplo, en un local branch1y quiero hacer un request-pullen una rama de característica local branch2? ¿Aún lo necesito origin? Por supuesto, uno siempre puede leer la documentación.
Ela782
Lamentablemente, este comando solo funciona si Rev # 2 es un nombre de rama, no funciona para los hashes: /
Jared Grubb
20

Me sorprende que nadie haya sugerido usar parches todavía.

Digamos que usted desea probar una combinación de your_brancha master(estoy suponiendo que haya mastercomprobado):

$ git diff master your_branch > your_branch.patch
$ git apply --check your_branch.patch
$ rm your_branch.patch

Eso debería hacer el truco.

Si obtienes errores como

error: patch failed: test.txt:1
error: test.txt: patch does not apply

eso significa que el parche no tuvo éxito y una fusión produciría conflictos. Sin salida significa que el parche está limpio y podrá fusionar fácilmente la rama


Tenga en cuenta que esto realmente no cambiará su árbol de trabajo (aparte de crear el archivo de parche, por supuesto, pero puede eliminarlo de forma segura después). De la documentación de git-apply:

--check
    Instead of applying the patch, see if the patch is applicable to the
    current working tree and/or the index file and detects errors. Turns
    off "apply".

Nota para cualquiera que sea más inteligente / más experimentado con git que yo: avíseme si me equivoco aquí y este método muestra un comportamiento diferente al de una fusión regular. Parece extraño que en los más de 8 años que ha existido esta pregunta nadie sugiera esta solución aparentemente obvia.

Christoph Böhmwalder
fuente
Este método es la respuesta aceptada para esta pregunta y hay algunas advertencias en los comentarios como "git no pudo usar la estrategia de fusión 'recursiva'" y "el archivo de parche da error para los archivos nuevos". De lo contrario, parece genial.
neno
1
Un camino más corto sin crear un archivo de parche temporal: git diff master your_branch | git apply --check.
ks1322
9

Esto puede ser interesante: de la documentación:

Si intentó una fusión que resultó en conflictos complejos y desea comenzar de nuevo, puede recuperarse con git merge --abort .

Pero también puedes hacerlo de la manera ingenua (pero lenta):

rm -Rf /tmp/repository
cp -r repository /tmp/
cd /tmp/repository
git merge ...
...if successful, do the real merge. :)

(Nota: no funcionará simplemente clonando a / tmp, necesitará una copia para asegurarse de que los cambios no confirmados no entren en conflicto).


fuente
2
Si todo lo que necesitas es un martillo ... :) +1
kaiser
Copia limpia se puede obtener con cp -r repository/.git /tmp/repository/.git, cd /tmp/repository, git reset --hard, git add --all, git reset --hard(por si acaso), git status(para comprobar que está limpio).
ADTC
8

Soy consciente de que esta es una pregunta antigua, pero es la primera en aparecer en una búsqueda de Google.

Git introdujo una opción --ff-only al fusionar.

De: http://git-scm.com/docs/git-merge


--ff-only

Negarse a fusionar y salir con un estado distinto de cero a menos que el HEAD actual ya esté actualizado o la fusión se pueda resolver como un avance rápido.

Hacer esto intentará fusionarse y avanzar rápidamente, y si no puede, aborta y le indica que no se pudo realizar el avance rápido, pero deja intacta su rama de trabajo. Si puede avanzar rápidamente, realizará la fusión en su rama de trabajo. Esta opción también está disponible en git pull. Por lo tanto, puede hacer lo siguiente:

git pull --ff-only origin branchA #See if you can pull down and merge branchA

git merge --ff-only branchA branchB #See if you can merge branchA into branchB
Jason McKindly
fuente
1
Eso hará la fusión si se puede hacer con avance rápido, que no es lo que quería en la pregunta original. Creo que la respuesta aceptada tiene la otra mitad que la arregla.
Otto
Realmente, sin embargo, los avisos de git sofisticados obvian la necesidad que tengo de este tipo de cosas.
Otto
2
No es realmente lo mismo. Salir con un estado distinto de cero porque la fusión no se puede resolver ya que el avance rápido no significa que haya conflictos . Simplemente significa que la historia ha divergido y que es necesario un compromiso de fusión.
ADTC
7

Uso git log para ver qué ha cambiado en una rama de características desde la rama maestra

git log does_this_branch..contain_this_branch_changes

por ejemplo, para ver qué confirmaciones hay en una rama de características que se ha / no se ha fusionado para dominar:

git log master..feature_branch
nelsonenzo
fuente
3

Si desea avanzar rápidamente de B a A, debe asegurarse de que git log B..A no muestre nada, es decir, A no tiene nada que B no tenga. Pero incluso si B..A tiene algo, es posible que pueda fusionarse sin conflictos, por lo que lo anterior muestra dos cosas: que habrá un avance rápido y, por lo tanto, no obtendrá un conflicto.

Erik Kaplun
fuente
2

Mi solución es fusionarme al revés.

En lugar de fusionar su rama en la rama "objetivo" remota, combine esa rama con la suya.

git checkout my-branch
git merge origin/target-branch

Verá si hay conflictos y puede planificar cómo resolverlos.

Después de eso, puede abortar la fusión a través de git merge --aborto (si no hubo conflictos y se ha producido la fusión) retroceder a la confirmación anterior a través degit reset --hard HEAD~1

Ubeogesh
fuente
-2

Haga una copia temporal de su copia de trabajo, luego combínela y difunda las dos.

vanboom
fuente