Estoy usando git en un nuevo proyecto que tiene dos ramas de desarrollo paralelas, pero actualmente experimentales:
master
: importación de la base de código existente más algunas modificaciones de las que generalmente estoy seguroexp1
: rama experimental # 1exp2
: rama experimental # 2
exp1
y exp2
representan dos enfoques arquitectónicos muy diferentes. Hasta que avance, no tengo forma de saber cuál (si alguno) funcionará. A medida que avanzo en una rama, a veces tengo ediciones que serían útiles en la otra rama y me gustaría fusionar solo esas.
¿Cuál es la mejor manera de fusionar cambios selectivos de una rama de desarrollo a otra dejando atrás todo lo demás?
Enfoques que he considerado:
git merge --no-commit
seguido de la eliminación manual de una gran cantidad de ediciones que no quiero hacer comunes entre las ramas.Copia manual de archivos comunes en un directorio temporal seguido de
git checkout
para pasar a la otra rama y luego copia más manual del directorio temporal en el árbol de trabajo.Una variación de lo anterior. Abandone las
exp
sucursales por ahora y use dos repositorios locales adicionales para la experimentación. Esto hace que la copia manual de archivos sea mucho más sencilla.
Los tres enfoques parecen tediosos y propensos a errores. Espero que haya un mejor enfoque; algo parecido a un parámetro de ruta de filtro que lo haría git-merge
más selectivo.
fuente
git merge -s ours --no-commit
seguido por algunos nogit read-tree
sería una buena solución para esto? Ver stackoverflow.com/questions/1214906/…Respuestas:
Utiliza el comando cherry-pick para obtener confirmaciones individuales de una rama.
Si los cambios que desea no están en confirmaciones individuales, utilice el método que se muestra aquí para dividir la confirmación en confirmaciones individuales . Hablando en términos generales, se usa
git rebase -i
para que el compromiso original se edite, luegogit reset HEAD^
para revertir selectivamente los cambios, luegogit commit
para confirmar ese bit como un nuevo compromiso en el historial.Hay otro buen método aquí en Red Hat Magazine, donde lo usan
git add --patch
o posiblemente logit add --interactive
que le permite agregar solo partes de un trozo, si desea dividir diferentes cambios en un archivo individual (busque en esa página "dividir").Después de dividir los cambios, ahora puede elegir los que desee.
fuente
Tuve exactamente el mismo problema mencionado anteriormente. Pero encontré esto más claro al explicar la respuesta.
Resumen:
Verifique las rutas desde la rama que desea fusionar,
Sugerencia: también funciona sin lo
--
visto en la publicación vinculada.o para fusionar selectivamente trozos
Alternativamente, use reset y luego agregue con la opción
-p
,Finalmente cometer
fuente
foo.c
,git reset HEAD foo.c
puede desestabilizar ese archivo y luego puede diferenciarlo. Descubrí esto después de intentarlo y volver aquí para buscar una respuesta a estogit diff --cached
git checkout -p <revision> -- <path>
, será lo mismo que emitir los primeros tres comandos que describió :)Para fusionar selectivamente archivos de una rama a otra rama, ejecute
¿De dónde
branchX
es la rama que desea fusionar en la rama actual?La
--no-commit
opción organizará los archivos que Git ha fusionado sin comprometerlos realmente. Esto le dará la oportunidad de modificar los archivos combinados como desee y luego confirmarlos usted mismo.Dependiendo de cómo desee fusionar archivos, hay cuatro casos:
1) Quieres una verdadera fusión.
En este caso, acepta los archivos combinados de la forma en que Git los fusionó automáticamente y luego los confirma.
2) Hay algunos archivos que no desea fusionar.
Por ejemplo, desea conservar la versión en la rama actual e ignorar la versión en la rama de la que se está fusionando.
Para seleccionar la versión en la rama actual, ejecute:
Esto recuperará la versión de
file1
en la rama actual y sobrescribirá lafile1
automatizada por Git.3) Si desea la versión en branchX (y no una verdadera fusión).
Correr:
Esto recuperará la versión de
file1
inbranchX
y sobrescribiráfile1
automáticamente fusionada por Git.4) El último caso es si desea seleccionar solo fusiones específicas
file1
.En este caso, puede editar el modificado
file1
directamente, actualizarlo a lo que quiera que sea la versiónfile1
y luego confirmar.Si Git no puede fusionar un archivo de forma automática, se reportará el archivo como " sin combinar " y producir una copia en la que deberá resolver los conflictos de forma manual.
Para explicar más a fondo con un ejemplo, supongamos que desea fusionarse
branchX
en la rama actual:Luego ejecuta el
git status
comando para ver el estado de los archivos modificados.Por ejemplo:
Donde
file1
,file2
yfile3
son los archivos que git se han fusionado automáticamente con éxito.Lo que esto significa es que los cambios en
master
ybranchX
para todos esos tres archivos se han combinado sin ningún conflicto.Puede inspeccionar cómo se realizó la fusión ejecutando
git diff --cached
;Si encuentra alguna fusión indeseable, entonces puede
git commit
Si no desea fusionar
file1
y desea conservar la versión en la rama actualcorrer
Si no desea fusionar
file2
y solo desea la versión enbranchX
correr
Si desea
file3
fusionarse automáticamente, no haga nada.Git ya lo ha fusionado en este punto.
file4
arriba es una fusión fallida por Git. Esto significa que hay cambios en ambas ramas que ocurren en la misma línea. Aquí es donde deberá resolver los conflictos manualmente. Puede descartar la fusión realizada editando el archivo directamente o ejecutando el comando de pago para la versión en la rama en la que deseafile4
convertirse.Finalmente, no te olvides
git commit
.fuente
git merge --no-commit branchX
tenga cuidado: si el es solo un avance rápido, el puntero se actualizará y, por lo tanto, el --no-commit se ignora silenciosamente--no-ff
para prevenir ese comportamiento?No me gustan los enfoques anteriores. Usar cherry-pick es excelente para elegir un solo cambio, pero es una molestia si desea incorporar todos los cambios, excepto algunos malos. Aquí está mi enfoque.
No hay
--interactive
argumento que pueda pasar para git merge.Aquí está la alternativa:
Tiene algunos cambios en la 'función' de la rama y desea llevar algunos, pero no todos, a 'dominar' de una manera no descuidada (es decir, no quiere elegir y comprometer cada uno)
Así que simplemente envuelva eso en un script de shell, cambie master a $ to y cambie la función a $ from y estará listo:
fuente
git rebase -i $to
agit rebase -i $to || $SHELL
, para que el usuario pueda llamargit --skip
, etc., según sea necesario si falla la nueva versión. También vale la pena encadenar las líneas en&&
lugar de las nuevas líneas.Hay otra forma de hacerlo:
Es una mezcla entre
git checkout
ygit add -p
podría ser exactamente lo que estás buscando:fuente
Si bien algunas de estas respuestas son bastante buenas, siento que ninguna realmente respondió la restricción original de OP: seleccionar archivos particulares de ramas particulares. Esta solución hace eso, pero puede ser tedioso si hay muchos archivos.
Digamos que tiene las
master
,exp1
yexp2
las ramas. Desea fusionar un archivo de cada una de las ramas experimentales en maestro. Haría algo como esto:Esto le dará diferencias en el archivo para cada uno de los archivos que desee. Nada mas. Nada menos. Es útil que tenga cambios de archivo radicalmente diferentes entre versiones, en mi caso, cambiar una aplicación de Rails 2 a Rails 3.
EDITAR : esto fusionará archivos, pero hace una combinación inteligente. No pude averiguar cómo usar este método para obtener información de diferencias en el archivo (tal vez aún lo hará por diferencias extremas. Pequeñas cosas molestas como los espacios en blanco se fusionan de nuevo a menos que use la
-s recursive -X ignore-all-space
opción)fuente
git checkout exp1 path/to/file_a path/to/file_x
git checkout feature <path>/*
para obtener grupos de archivos.La respuesta de 1800 INFORMACIÓN es completamente correcta. Sin embargo, como git noob, "usar git cherry-pick" no fue suficiente para que me diera cuenta sin investigar un poco más en Internet, así que pensé en publicar una guía más detallada en caso de que alguien más esté en un barco similar
Mi caso de uso era querer tirar selectivamente los cambios de la rama github de otra persona a la mía. Si ya tiene una sucursal local con los cambios, solo necesita realizar los pasos 2 y 5-7.
Cree (si no se creó) una sucursal local con los cambios que desea incorporar.
$ git branch mybranch <base branch>
Cambia a eso.
$ git checkout mybranch
Despliegue los cambios que desee de la cuenta de la otra persona. Si aún no lo ha hecho, querrá agregarlos como control remoto.
$ git remote add repos-w-changes <git url>
Tire hacia abajo todo de su rama.
$ git pull repos-w-changes branch-i-want
Vea los registros de confirmación para ver qué cambios desea:
$ git log
Vuelva a la rama en la que desea extraer los cambios.
$ git checkout originalbranch
Cherry elige tus commits, uno por uno, con los hash.
$ git cherry-pick -x hash-of-commit
Punta de sombrero: http://www.sourcemage.org/Git_Guide
fuente
git cherry
comando (consulte el manual primero) para identificar confirmaciones que aún no ha fusionado.Aquí es cómo puede reemplazar el
Myclass.java
archivo enmaster
rama conMyclass.java
enfeature1
rama. Funcionará incluso siMyclass.java
no existemaster
.Tenga en cuenta que esto sobrescribirá, no fusionará, e ignorará los cambios locales en la rama maestra.
fuente
theirs
sobrescribirours
=> +1 Cheers;)2. Manual copying of common files into a temp directory followed by ...copying out of the temp directory into the working tree.
La manera simple, para fusionar archivos específicos de dos ramas, no solo reemplazar archivos específicos con los de otra rama.
Paso uno: difunde las ramas
git diff branch_b > my_patch_file.patch
Crea un archivo de parche de la diferencia entre la rama actual y branch_b
Paso dos: aplique el parche en archivos que coincidan con un patrón
git apply -p1 --include=pattern/matching/the/path/to/file/or/folder my_patch_file.patch
notas útiles sobre las opciones
Puede usarlo
*
como comodín en el patrón de inclusión.Las barras no necesitan ser escapadas.
Además, puede usar --excluir en su lugar y aplicarlo a todo excepto a los archivos que coinciden con el patrón, o revertir el parche con -R
La opción -p1 es un remanente del comando de parche * unix y el hecho de que el contenido del archivo de parche antepone cada nombre de archivo con
a/
ob/
(o más, dependiendo de cómo se generó el archivo de parche) que debe eliminar para que pueda descubrir el archivo real a la ruta al archivo al que se debe aplicar el parche.Consulte la página del manual de git-apply para obtener más opciones.
Paso tres: no hay paso tres
Obviamente, querrá confirmar sus cambios, pero quién puede decir que no tiene otros ajustes relacionados que desea hacer antes de realizar su confirmación.
fuente
Así es como puede obtener el historial para seguir solo un par de archivos de otra rama con un mínimo de alboroto, incluso si una fusión más "simple" hubiera traído muchos más cambios que no desea.
Primero, darás el paso inusual de declarar de antemano que lo que estás a punto de cometer es una fusión, sin que git haga nada en absoluto a los archivos en tu directorio de trabajo:
. . . donde "nombre de sucursal" es lo que usted dice que está fusionando. Si tuviera que comprometerse de inmediato, no haría cambios, pero aún mostraría ascendencia de la otra rama. Puede agregar más ramas / etiquetas / etc. a la línea de comando si es necesario, también. Sin embargo, en este punto, no hay cambios para confirmar, así que obtenga los archivos de las otras revisiones, a continuación.
Si se estaba fusionando desde más de otra rama, repita según sea necesario.
Ahora los archivos de la otra rama están en el índice, listos para ser confirmados, con historial.
y tendrás muchas explicaciones que hacer en ese mensaje de confirmación.
Sin embargo, tenga en cuenta, en caso de que no esté claro, que esto es algo desordenado que hacer. No está en el espíritu de lo que es una "rama", y la selección de cerezas es una forma más honesta de hacer lo que estaría haciendo aquí. Si desea hacer otra "fusión" para otros archivos en la misma rama que no trajo la última vez, se detendrá con un mensaje "ya actualizado". Es un síntoma de no ramificarse cuando deberíamos haberlo hecho, en la rama "desde" debería haber más de una rama diferente.
fuente
git merge --no-ff --no-commit -s outs branchname1
) es exactamente lo que estaba buscando! ¡Gracias!Sé que llego un poco tarde, pero este es mi flujo de trabajo para fusionar archivos selectivos.
fuente
La forma más fácil es establecer su repositorio en la rama con la que desea fusionar y luego ejecutar,
Si tu corres
verá el archivo ya organizado ...
Entonces corre
Simple.
fuente
Encontré esta publicación para contener la respuesta más simple. Simplemente hacer:
Ejemplo:
Vea la publicación para más información.
fuente
Es extraño que git todavía no tenga una herramienta tan conveniente "lista para usar". Lo uso mucho cuando actualizo alguna rama de la versión anterior (que todavía tiene muchos usuarios de software) con solo algunas correcciones de errores de la rama de la versión actual. En este caso, a menudo es necesario obtener rápidamente algunas líneas de código del archivo en el tronco, ignorando muchos otros cambios (que no se supone que entren en la versión anterior) ... Y, por supuesto , la combinación tripartita interactiva es necesario en este caso,
git checkout --patch <branch> <file path>
no es utilizable para este propósito de fusión selectiva.Puedes hacerlo fácilmente:
Simplemente agregue esta línea a la
[alias]
sección en su archivo global.gitconfig
o local.git/config
:Implica que usas Beyond Compare. Simplemente cambie al software de su elección si es necesario. O puede cambiarlo a fusión automática de tres vías si no necesita la fusión selectiva interactiva:
Luego use así:
Esto le dará la verdadera oportunidad de fusión selectiva en forma de árbol de cualquier archivo en otra rama.
fuente
No es exactamente lo que estabas buscando, pero me fue útil:
Es una mezcla de algunas respuestas.
fuente
git checkout HEAD file1
para mantener la versión actual y separar el archivofile1
, se puede usar la-p
opción para seleccionar parte del archivo a fusionar. gracias por el truco!Yo haría un
De esta manera, puede limitar el rango de confirmaciones para un patrón de archivos desde una rama.
Robado de: http://www.gelato.unsw.edu.au/archives/git/0701/37964.html
fuente
Tuve exactamente el mismo problema mencionado anteriormente. Pero encontré este blog git más claro al explicar la respuesta.
Comando desde el enlace de arriba:
fuente
Me gusta la respuesta 'git-interactive-merge', arriba, pero hay una más fácil. Deje que git haga esto por usted usando una combinación de rebase de interactivo y en:
Entonces, el caso es que desea C1 y C2 de la rama 'característica' (punto de rama 'A'), pero ninguno de los demás por ahora.
Lo cual, como arriba, te lleva al editor interactivo donde seleccionas las líneas 'pick' para C1 y C2 (como arriba). Guarde y salga, y luego procederá con el rebase y le dará la rama 'temp' y también HEAD en master + C1 + C2:
Luego puede actualizar master a HEAD y eliminar la rama temporal y listo:
fuente
¿Qué hay de
git reset --soft branch
? Me sorprende que nadie lo haya mencionado todavía.Para mí, es la forma más fácil de seleccionar selectivamente los cambios de otra rama, ya que este comando pone en mi árbol de trabajo todos los cambios de diferencias y puedo elegir o revertir fácilmente cuál necesito. De esta manera, tengo control total sobre los archivos comprometidos.
fuente
Sé que esta pregunta es antigua y hay muchas otras respuestas, pero escribí mi propio script llamado 'pmerge' para fusionar parcialmente los directorios. Es un trabajo en progreso y todavía estoy aprendiendo las secuencias de comandos git y bash.
Este comando usa
git merge --no-commit
y luego no aplica los cambios que no coinciden con la ruta provista.Uso:
git pmerge branch path
Ejemplo:
git merge develop src/
No lo he probado exhaustivamente. El directorio de trabajo debe estar libre de cambios no confirmados y archivos sin seguimiento.
fuente
Puede usar
read-tree
para leer o fusionar un árbol remoto dado en el índice actual, por ejemplo:Para realizar la fusión, use
-m
en su lugar.Ver también: ¿Cómo fusiono un subdirectorio en git?
fuente
Un enfoque simple para la fusión / confirmación selectiva por archivo:
git checkout dstBranch git merge srcBranch // make changes, including resolving conflicts to single files git add singleFile1 singleFile2 git commit -m "message specific to a few files" git reset --hard # blow away uncommitted changes
fuente
Si no tiene demasiados archivos que han cambiado, esto lo dejará sin compromisos adicionales.
1. Duplicar la rama temporalmente
$ git checkout -b temp_branch
2. Restablezca la última confirmación deseada
$ git reset --hard HEAD~n
, ¿dónden
está la cantidad de confirmaciones que necesita para volver?3. Verifique cada archivo de la rama original
$ git checkout origin/original_branch filename.ext
Ahora puede comprometer y forzar el empuje (para sobrescribir el control remoto), si es necesario.
fuente
Si solo necesita fusionar un directorio en particular y dejar todo lo demás intacto y al mismo tiempo preservar el historial, posiblemente podría intentar esto ... crear un nuevo
target-branch
fuera delmaster
antes de experimentar.Los pasos a continuación suponen que tiene dos ramas
target-branch
y quesource-branch
el directoriodir-to-merge
que desea fusionar está ensource-branch
. También suponga que tiene otros directorios comodir-to-retain
en el destino que no desea cambiar y retener el historial. Además, se supone que hay conflictos de fusión en eldir-to-merge
.fuente
Cuando solo unos pocos archivos han cambiado entre las confirmaciones actuales de las dos ramas, combino manualmente los cambios revisando los diferentes archivos.
git difftoll <branch-1>..<branch-2>
fuente