Git fusionar maestro en rama de características

1017

Digamos que tenemos la siguiente situación en Git:

  1. Un repositorio creado:

    mkdir GitTest2
    cd GitTest2
    git init
    
  2. Algunas modificaciones en el maestro tienen lugar y se comprometen:

    echo "On Master" > file
    git commit -a -m "Initial commit"
    
  3. Feature1 se bifurcó del master y se realizó algún trabajo:

    git branch feature1
    git checkout feature1
    echo "Feature1" > featureFile
    git commit -a -m "Commit for feature1"
    
  4. Mientras tanto, se descubre un error en el código maestro y se establece una rama de revisión:

    git checkout master
    git branch hotfix1
    git checkout hotfix1
    
  5. El error se corrigió en la rama de revisión y se fusionó nuevamente en el maestro (tal vez después de una solicitud de extracción / revisión de código):

    echo "Bugfix" > bugfixFile
    git commit -a -m "Bugfix Commit"
    git checkout master
    git merge --no-ff hotfix1
    
  6. El desarrollo en feature1 continúa:

    git checkout feature1
    

Digamos que necesito la revisión en mi rama de características, tal vez porque el error también ocurre allí. ¿Cómo puedo lograr esto sin duplicar las confirmaciones en mi rama de características?

Quiero evitar obtener dos nuevos commits en mi rama de características que no tienen relación con la implementación de características. Esto me parece especialmente importante si utilizo solicitudes de extracción: todas estas confirmaciones también se incluirán en la solicitud de extracción y deben revisarse aunque esto ya se haya hecho (ya que la revisión ya está en el maestro).

No puedo hacer un git merge master --ff-only: "fatal: no es posible avanzar rápidamente, abortar", pero no estoy seguro de si esto me ayudó.

theomega
fuente
8
Si la sucursal feature1es completamente local, échale un vistazo git rebase.
Jokester
19
Gracias, como principiante de git, me git rebaseparece magia negra ...
theomega
13
si la rama es característica, solo la corrección del error no debería ocurrir allí (al menos si no es un error de bloqueo) ya que el objetivo de esta rama es mostrar una nueva característica. El error se solucionará cuando se fusione con el maestro donde está presente la confirmación con la corrección.
gipi
21
Probablemente valga la pena señalar para los principiantes que en 3. git branch feature1y git checkout feature1podrían combinarse en git checkout -b feature1y 4. podrían reducirse por completo agit checkout -b hotfix1 master
Naruto Sempai
3
¿Estaría dispuesto a regresar y cambiar la respuesta aceptada, porque la respuesta aceptada actual es horrible?
Omnifarious

Respuestas:

1219

¿Cómo fusionamos la rama maestra en la rama característica? Fácil:

git checkout feature1
git merge master

No tiene sentido forzar una fusión de avance rápido aquí, ya que no se puede hacer. Te comprometiste tanto en la rama de características como en la rama maestra. Avance rápido es imposible ahora.

Echa un vistazo a GitFlow . Es un modelo de ramificación para git que puede seguirse, e inconscientemente ya lo hizo. También es una extensión de Git que agrega algunos comandos para los nuevos pasos del flujo de trabajo que hacen las cosas automáticamente, que de lo contrario necesitaría hacer manualmente.

Entonces, ¿qué hiciste bien en tu flujo de trabajo? Tiene dos ramas para trabajar, su rama feature1 es básicamente la rama "desarrollo" en el modelo GitFlow.

Creó una rama de revisión de master y la fusionó de nuevo. Y ahora estás atrapado.

El modelo GitFlow le pide que combine la revisión también con la rama de desarrollo, que es "característica1" en su caso.

Entonces la verdadera respuesta sería:

git checkout feature1
git merge --no-ff hotfix1

Esto agrega todos los cambios que se realizaron dentro de la revisión a la rama de características, pero solo esos cambios. Pueden entrar en conflicto con otros cambios de desarrollo en la rama, pero no entrarán en conflicto con la rama maestra si finalmente fusiona la rama característica con la rama maestra.

Ten mucho cuidado con el rebase. Solo vuelva a redactar si los cambios que realizó permanecieron locales en su repositorio, por ejemplo, no empujó ninguna rama a otro repositorio. Rebasar es una gran herramienta para que usted organice sus compromisos locales en un orden útil antes de lanzarlo al mundo, pero el rebase posterior arruinará las cosas para los principiantes como usted.

Sven
fuente
77
No. La confirmación que corrige el error aparece solo una vez en la rama de revisión, aunque el nombre de la rama se elimina una vez que se fusionó con las ramas maestra y de desarrollo. La confirmación de fusión solo muestra los cambios introducidos por la fusión, que parece una confirmación duplicada. Pero así es como funciona git: bifurca y fusiona. El trabajo de desarrollo real solo se lleva a cabo en confirmaciones que no son de fusión, y la fusión solo se acepta si el resultado es un software que funciona.
Sven
42
Esta debería ser la respuesta aceptada. Funciona bien con la función de solicitud de extracción de GitHub también.
Nostalg.io
125
Creo que vale la pena señalar que git merge masterse fusionará a partir de su copia local de master, por lo que incluso si ha hecho una git pullen su rama de características después de que otra persona fusionó una rama diferente en master, deberá hacerlo git checkout master, luego git pull, git checkout feature1nuevamente y ENTONCES git merge master.
Damick
50
@damick Or just git fetchandgit merge origin/master
Yngvar Kristiansen
20
@damick @ yngvar-kristiansen git pull origin masterse fusionará automáticamente orgin/mastercon la rama actual
L422Y
614

Debería poder volver a basar su rama en master:

git checkout feature1
git rebase master

Gestiona todos los conflictos que surjan. Cuando llegues a los commits con las correcciones de errores (ya en master), Git dirá que no hubo cambios y que tal vez ya se aplicaron. Luego continúa el rebase (mientras omite los commits ya en master) con

git rebase --skip

Si realiza una git logen su rama de características, verá que la confirmación de corrección de errores aparece solo una vez, y en la parte maestra.

Para una discusión más detallada, eche un vistazo a la documentación del libro Git en git rebase( https://git-scm.com/docs/git-rebase ) que cubre este caso de uso exacto.

================ Editar para contexto adicional ====================

Esta respuesta se proporcionó específicamente para la pregunta formulada por @theomega, teniendo en cuenta su situación particular. Tenga en cuenta esta parte:

Quiero evitar [...] confirmaciones en mi rama de características que no tienen relación con la implementación de características.

Rebasar su rama privada en master es exactamente lo que dará ese resultado. Por el contrario, fusionar master en su rama haría precisamente lo que él específicamente no quiere que suceda : agregar una confirmación que no esté relacionada con la implementación de la función en la que está trabajando a través de su rama.

Para dirigirse a los usuarios que leen el título de la pregunta, omita el contenido real y el contexto de la pregunta, y luego solo lea la respuesta superior a ciegas, suponiendo que siempre se aplique a su (diferente) caso de uso, permítame explicar:

  • solo rebase las ramas privadas (es decir, que solo existen en su repositorio local y no se han compartido con otros). Rebasar las ramas compartidas "rompería" las copias que otras personas puedan tener.
  • si desea integrar los cambios de una rama (ya sea maestra u otra rama) en una rama que es pública (por ejemplo, presionó la rama para abrir una solicitud de extracción, pero ahora hay conflictos con la maestra y necesita actualizar su rama para resolver esos conflictos) necesitará fusionarlos (por ejemplo, con git merge masterla respuesta de @ Sven).
  • también puede fusionar sucursales en sus sucursales privadas locales si así lo prefiere, pero tenga en cuenta que dará como resultado compromisos "extranjeros" en su sucursal.

Finalmente, si no está satisfecho con el hecho de que esta respuesta no es la más adecuada para su situación a pesar de que fue para @theomega, agregar un comentario a continuación no será particularmente útil: no controlo qué respuesta está seleccionada, solo @theomega lo hace.

David Sulc
fuente
136
No, no es seguro: si cambias de base, estás cambiando el historial de la rama, lo que afectará a los desarrolladores que retiraron la rama. inf act, git no le permitirá empujar una rama con rebase por defecto: debe forzar la actualización -fcuando presiona para sobrescribir la rama con la versión con rebase. ¡Ten cuidado!
David Sulc
17
¿Cómo manejan este problema los equipos profesionales que usan git? ¿Prestan atención, piensan cuidadosamente y luego hacen un -f? ¿O mi flujo de trabajo completo es defectuoso porque necesito un -f?
theomega
30
Bueno, me atrevería a decir que la regla "sagrada" es que no rebase (o cambie el historial de confirmación) en el código que se ha compartido: es solo para su código local. Básicamente, debe volver a basar sus cambios para "limpiar" antes de compartirlo. En su caso, puede empujar una nueva rama rebaseada (con un nombre diferente) y pedir a sus colegas que basen sus cambios en esa rama (es decir, rebase su rama local de la nueva, como se indicó anteriormente). Luego, elimine feature1de Github.
David Sulc
19
La mayoría de los equipos profesionales en los que he trabajado casi nunca usan rebase, simplemente combinan todo por defecto, para que nunca ocurra ninguna modificación en el historial. Esta es mi forma preferida de trabajar. Por otro lado, algunos equipos usan rebase para 'limpiar' los compromisos antes de presionarlos (pero nunca después de presionar)
Jonathan Hartley
11
Sí, NUNCA deberías rebajar las ramas públicas. Sin embargo, la pregunta de OP parecía estar relacionada con la integración de nuevos compromisos realizados masteren una rama privada (menciona "su" rama local). En ese caso, rebaseestá bien y es el mismo caso de uso que la "limpieza" que menciona.
David Sulc
69

Según este artículo , debe:

  • crear una nueva rama que se basa en la nueva versión del maestro

    git branch -b newmaster

  • fusionar su antigua rama de características en una nueva

    git checkout newmaster

  • resolver conflictos en la nueva rama de características

Los dos primeros comandos se pueden combinar con git checkout -b newmaster.

De esta manera, su historial permanece claro porque no necesita fusiones anteriores. Y no necesita ser tan cauteloso ya que no necesita hacer un cambio de versión de Git.

zimi
fuente
77
Sería bueno si haces que el comando git relacionado siga cada punto. De lo contrario, me parece que esta es la opción más segura y limpia.
VirgileD
@zimi ¿Qué pasa si tenemos una sucursal remota? ¿Volveremos a crear una nueva rama de características de actualización nuevamente? ¿O podemos simplemente configurar el upstream remoto?
BILL
@VirgileD Acabo de publicar mi propia respuesta con más detalles, incluidos los comandos git relacionados.
jkdev
29

git merge

puedes seguir los siguientes pasos

1. fusionar origin/masterrama a featurerama

# step1: change branch to master, and pull to update all commits
$ git checkout master
$ git pull

# step2: change branch to target, and pull to update commits
$ git checkout feature
$ git pull

# step3: merge master to feature(⚠️ current is feature branch)
$ git merge master

2. fusionar featurerama a origin/masterrama

origin/master es la rama maestra remota, mientras master es la rama maestra local

$ git checkout master
$ git pull origin/master

$ git merge feature
$ git push origin/master
xgqfrms
fuente
Se siente como rebase es promocionado! Buena fusión antigua :)!
Foreever
27

La respuesta de Zimi describe este proceso en general. Aquí están los detalles:

  1. Crea y cambia a una nueva sucursal. Asegúrese de que la nueva rama se base masterpara que incluya las revisiones recientes.

    git checkout master
    git branch feature1_new
    git checkout feature1_new
    
    # Or, combined into one command:
    git checkout -b feature1_new master
    
  2. Después de cambiar a la nueva rama, combine los cambios de su rama de características existente. Esto agregará sus confirmaciones sin duplicar las confirmaciones de revisión.

    git merge feature1
    
  3. En la nueva rama, resuelva cualquier conflicto entre su característica y la rama maestra.

¡Hecho! Ahora use la nueva rama para continuar desarrollando su función.

jkdev
fuente
2
El problema con esto es que un desarrollador desperdicia tiempo constantemente generando nuevas ramas cuando necesitan actualizarse contra el maestro. Estaríamos haciendo muchas y muchas ramas, probablemente 3 veces al día durante el trabajo activo. Debería escribir instrucciones sobre cómo limpiar todas las ramas de basura locales y cómo deshacerse de ellas en forma remota. También necesitamos consejos para nombrar todas estas ramas para que no nos confundamos. Sin ese bit, esto convertirá un sistema de sucursal en caos.
pauljohn32
44
Tienes razón, esto no debe hacerse todo el tiempo. Solo cuando (1) los cambios en master son necesarios para su función, o (2) está a punto de fusionar su rama con master y puede haber conflictos. Y para evitar el desorden, puede eliminar su rama después de que se haya fusionado.
jkdev
11

Aquí hay un script que puede usar para fusionar su rama maestra en su rama actual.

El script hace lo siguiente:

  • Cambia a la rama maestra
  • Tira de la rama maestra
  • Vuelve a su sucursal actual
  • Fusiona la rama maestra en su rama actual

Guarde este código como un archivo por lotes (.bat) y coloque el script en cualquier lugar de su repositorio. Luego haga clic en él para ejecutarlo y listo.

:: This batch file pulls current master and merges into current branch

@echo off

:: Option to use the batch file outside the repo and pass the repo path as an arg
set repoPath=%1
cd %repoPath%

FOR /F "tokens=*" %%g IN ('git rev-parse --abbrev-ref HEAD') do (SET currentBranch=%%g)

echo current branch is %currentBranch%
echo switching to master
git checkout master
echo.
echo pulling origin master
git pull origin master
echo.
echo switching back to %currentBranch%
git checkout %currentBranch%
echo.
echo attemting merge master into %currentBranch%
git merge master
echo.
echo script finished successfully
PAUSE
Aaron M.
fuente
10

Es posible que pueda hacer una "selección de cereza" para extraer exactamente confirmaciones que necesita en su rama de características.

Haga un git checkout hotfix1para llegar a la rama hotfix1. Entonces haz ungit log para obtener el hash SHA-1 (secuencia grande de letras y números aleatorios que identifica de forma exclusiva una confirmación) de la confirmación en cuestión. Copie eso (o los primeros 10 caracteres).

Entonces, git checkout feature1 para volver a su rama de características.

Entonces, git cherry-pick <the SHA-1 hash that you just copied>

Eso tirará de ese compromiso, y solo esa confirmación, a su rama de características. Ese cambio estará en la rama: simplemente lo "seleccionó". Luego, reanude el trabajo, edite, confirme, presione, etc. a su gusto.

Cuando, finalmente, realice otra fusión de una rama en su rama de características (o viceversa), Git reconocerá que ya se ha fusionado en esa confirmación en particular , sabrá que no tiene que volver a hacerlo, y solo "saltearlo".

Bob Gilmore
fuente
No considero que sea una buena idea. Entonces, en mi opinión, la confirmación de revisión realmente se mostrará en el historial de su rama de características, que básicamente no desea.
Martin Pecka
1
"Cuando, eventualmente, realices otra fusión de una rama a tu rama de características (o viceversa), git reconocerá que ya has fusionado [...]" - ¿es así como funciona realmente? No creo que git mergefuncione en esta forma de "confirmaciones de repetición" a la que parece estar insinuando ("y simplemente omítala"). Mezclar la selección y la fusión de cerezas aparentemente puede generar problemas; ver: news.ycombinator.com/item?id=3947950
Guildenstern
0

Estoy en la rama de características e hice refactorizaciones. Quiero fusionar los cambios maestros ahora a mi rama de características. Estoy muy atrasado. Tenga en cuenta que no quiero extraer los cambios maestros a mi local porque mis ramas de características tienen módulos movidos de un lugar a otro. Descubrí que solo realizar a continuación sin tirar no funciona. dice "Ya actualizado".

 //below does not get the latest from remote master to my local feature branch without git pull
    git checkout master 
    git fetch 
    git checkout my-feature-branch 
    git merge master

Esto funciona a continuación, tenga en cuenta el uso de git merge origin / master:

 git checkout master 
    git fetch 
    git checkout my-feature-branch 
    git merge origin/master
Tony
fuente