¿Cuál es la mejor (y más segura) forma de fusionar una rama de Git en master?

2104

Se mastercrea una nueva rama de , la llamamos test.

Hay varios desarrolladores que se comprometen mastero crean otras ramas y luego se fusionan master.

Digamos que el trabajo testlleva varios días y desea mantenerse testactualizado continuamente con los compromisos dentro master.

Lo haría git pull origin masterdesde test.

Pregunta 1: ¿Es este el enfoque correcto? Otros desarrolladores podrían haber trabajado fácilmente en los mismos archivos que yo he trabajado por cierto.


Mi trabajo testestá terminado y estoy listo para fusionarlo nuevamente master. Estas son las dos formas en que puedo pensar:

UNA:

git checkout test
git pull origin master
git push origin test
git checkout master
git pull origin test 

SI:

git checkout test
git pull origin master
git checkout master
git merge test

No estoy usando --rebaseporque, según tengo entendido, rebase obtendrá los cambios mastery apilará los míos además de eso, podría sobrescribir los cambios que otras personas hicieron.

Pregunta 2: ¿Cuál de estos dos métodos es el correcto? ¿Cuál es la diferencia allí?

El objetivo de todo esto es mantener mi testrama actualizada con las cosas que suceden mastery luego podría fusionarlas nuevamente con la masteresperanza de mantener la línea de tiempo lo más lineal posible.

moe
fuente
18
no ... rebase nunca sobrescribe, solo trata de lograr un historial más limpio. por volver a unir (o falsificar) la historia hasta el punto final del maestro
Junchen Liu
77
rebase no sobrescribe sus confirmaciones. Deshace sus confirmaciones, aplica las confirmaciones en la rama maestra a su rama de prueba, luego aplica sus confirmaciones nuevamente a la prueba.
zundi

Respuestas:

2994

Cómo haría esto

git checkout master
git pull origin master
git merge test
git push origin master

Si tengo una sucursal local desde una remota, no me siento cómodo fusionando otras sucursales que esta con el remoto. Además, no empujaría mis cambios, hasta que esté contento con lo que quiero empujar y tampoco empujaría las cosas, que son solo para mí y mi repositorio local. En tu descripción parece, ¿eso testes solo para ti? Entonces no hay razón para publicarlo.

git siempre trata de respetar los cambios tuyos y de los demás, y así lo hará --rebase. No creo que pueda explicarlo apropiadamente, así que eche un vistazo al libro de Git - Rebasando o listo para git: Introducción a rebase para una pequeña descripción. Es una característica genial

KingCrunch
fuente
2
git merge testme da fatal: 'test' does not point to a commit. Tengo que buscar git logel punto de confirmación en la rama de prueba, volver a la rama maestra y luego hacerlo git merge 0f37d3154abbf52a4cbbbb5109f08af6a7567234.
Duncanmoo
17
@Duncanmoo Bueno, por supuesto, la rama testdebe existir. Claro, puede usar el hash commit en su lugar, pero generalmente es más fácil usar el nombre de la rama. Internamente solo recupera el hash HEADde la rama.
KingCrunch
44
@shanyangqu Para obtener los últimos cambios desde el control remoto. Si trabaja solo y con un solo sistema, no hay problema. Pero cuando hay cambios impulsados ​​desde un sistema diferente (probablemente de un desarrollador diferente) verá un conflicto tan pronto como intente retrasar su fusión (el cuarto paso). La única solución ahora es fusionar su maestro local en el maestro de control remoto, lo que termina en un compromiso de fusión bastante feo "maestro combinado en origen / maestro". Por lo tanto, siempre es una buena idea hacer un tirón antes de la fusión
KingCrunch
77
"En su descripción parece, ¿esa prueba es solo para usted? Entonces no hay razón para publicarla". Es posible que desee llevar su sucursal local a un servidor si, por ejemplo, ese servidor proporciona una copia de seguridad contra el fallo de su unidad local o si no tiene otro medio para hacer una copia de seguridad.
Eric
55
"... Además, no presionaría mis cambios, hasta que esté contento con lo que quiero empujar ..." ¿por qué no presionar por tener una copia de seguridad de su código, en caso de que sus máquinas locales mueran y días de esfuerzos? ¿se fueron?
Rich Stone
400

Esta es una pregunta muy práctica, pero todas las respuestas anteriores no son prácticas.

Me gusta

git checkout master
git pull origin master
git merge test
git push origin master

Este enfoque tiene dos problemas :

  1. No es seguro, porque no sabemos si hay conflictos entre la rama de prueba y la rama maestra.

  2. "Exprimiría" todos los commits de prueba en un commit de fusión en master; es decir, en la rama maestra, no podemos ver todos los registros de cambios de la rama de prueba.

Entonces, cuando sospechamos que habría algunos conflictos, podemos tener las siguientes operaciones de git:

git checkout test
git pull 
git checkout master
git pull
git merge --no-ff --no-commit test

Pruebe mergeantes commit, evite un compromiso de avance rápido por --no-ff,

Si se encuentra un conflicto, podemos ejecutar git statuspara verificar los detalles sobre los conflictos e intentar resolver

git status

Una vez que resolvemos los conflictos, o si no hay conflicto, nosotros commity pushellos

git commit -m 'merge test branch'
git push

Pero de esta manera perderá el historial de cambios registrado en la rama de prueba, y haría que la rama maestra sea difícil para que otros desarrolladores entiendan la historia del proyecto.

Entonces, el mejor método es que tenemos que usar en rebaselugar demerge (supongamos que, en este momento, hemos resuelto los conflictos de las ramas).

La siguiente es una muestra simple, para operaciones avanzadas, consulte http://git-scm.com/book/en/v2/Git-Branching-Rebasing

git checkout master
git pull
git checkout test
git pull
git rebase -i master
git checkout master
git merge test

Sí, cuando haya terminado, todas las confirmaciones de la rama de prueba se moverán a la cabeza de la rama maestra. El principal beneficio de rebase es que obtienes un historial de proyecto lineal y mucho más limpio.

Lo único que debe evitar es: nunca use rebase en una rama pública, como la rama maestra.

Nunca haga operaciones como las siguientes:

git checkout master
git rebase -i test

Detalles para https://www.atlassian.com/git/tutorials/merging-vs-rebasing/the-golden-rule-of-rebasing

apéndice:

John Yin
fuente
44
Estoy de acuerdo en cambiar la rama de prueba para luego fusionarla en master es el camino a seguir. Incluso las otras respuestas son correctas, esto mantendrá el historial de cambios de la prueba de ramificación en la cabeza del maestro, ya que la autora menciona "obtienes un proyecto de línea y mucho más limpio", que es el propósito del sistema de control de versiones.
le0diaz
16
La afirmación "no es una forma de seguridad, porque no sabemos si hay conflictos entre la rama de prueba y la rama maestra" no es cierta: siempre se puede abortar la fusión. E incluso si no hay conflictos, siempre puede deshacer la última confirmación local siempre que no se presione. Sin una comprensión correcta de git, algunas cosas pueden parecer un poco aterradoras o poco claras, pero "inseguro" es incorrecto de alguna manera. Tenga cuidado de no confundir a otros con información incorrecta.
Paul van Leeuwen
44
de acuerdo con @PaulvanLeeuwen, cuando fusiones la rama de prueba en maestra, recibirás una notificación sobre los conflictos, y ahí es donde intervendrás y fusionarás los cambios. Una vez que hayas terminado, comprometerás la fusión y retrocederás. Si te arrepientes o parece que no puedes fusionarlo correctamente, siempre puedes descartar tu trabajo y retirarlo del master nuevamente. Así que definitivamente no es inseguro ..
Juan
3
¿Por qué rebase -i?
MushyPeas
8
Rebasar es inherentemente más inseguro que fusionar. Proponer rebase como una opción más segura para fusionarse es incorrecto. Rebasar es una estrategia válida, pero viene con más advertencias de las que el usuario debe tener cuidado.
Ikke
90

Ni un rebase ni una fusión deben sobrescribir los cambios de nadie (a menos que elija hacerlo al resolver un conflicto).

El enfoque habitual durante el desarrollo es

git checkout master
git pull
git checkout test
git log master.. # if you're curious
git merge origin/test # to update your local test from the fetch in the pull earlier

Cuando estés listo para fusionarte nuevamente con el maestro,

git checkout master
git log ..test # if you're curious
git merge test
git push

Si te preocupa romper algo en la fusión, git merge --abortestá ahí para ti.

Usar empujar y luego tirar como medio de fusión es una tontería. Tampoco estoy seguro de por qué estás empujando la prueba al origen.

raylu
fuente
1
Este proceso aumentará el número de confirmaciones, cada vez que cambie entre sucursales, debe confirmar su sucursal.
iBug
2
¿Qué? ¿Está diciendo que aumentará el número de confirmaciones cada vez que cambie de sucursales? ¿O está diciendo que cada vez que cambia de sucursal, tiene que "comprometer su sucursal"? El primero es falso y no estoy seguro de lo que significa el segundo.
raylu
Antes de finalizar la compra, debe confirmar la sucursal. eso es lo que estoy diciendo
iBug
11
No lo haces: esa es una de las cosas git stash.
msanford
1
O podría enmendar su último compromiso (en la sucursal local) y hacerlo perfecto antes de presionar.
whihathac
42

Primero haría que la rama a fusionar fuera lo más limpia posible. Ejecute sus pruebas, asegúrese de que el estado sea el que desea. Limpia los nuevos commits con git squash .

Además de la respuesta de KingCrunches , sugiero usar

git checkout master
git pull origin master
git merge --squash test
git commit
git push origin master

Es posible que haya realizado muchas confirmaciones en la otra rama, que solo debería ser una confirmación en la rama maestra. Para mantener el historial de confirmaciones lo más limpio posible, es posible que desee aplastar todas sus confirmaciones desde la rama de prueba en una confirmación en la rama maestra (consulte también: Git: ¿Aplastar o no a aplastar? ). Luego, también puede volver a escribir el mensaje de confirmación en algo muy expresivo. Algo que es fácil de leer y comprender, sin profundizar en el código.

editar: te puede interesar

Entonces, en GitHub, termino haciendo lo siguiente para una rama de características mybranch:

Obtén lo último del origen

$ git checkout master
$ git pull origin master

Encuentra el hash base de fusión:

$ git merge-base mybranch master
c193ea5e11f5699ae1f58b5b7029d1097395196f

$ git checkout mybranch
$ git rebase -i c193ea5e11f5699ae1f58b5b7029d1097395196f

Ahora asegúrese de que solo el primero sea pick, el resto es s:

pick 00f1e76 Add first draft of the Pflichtenheft
s d1c84b6 Update to two class problem
s 7486cd8 Explain steps better

A continuación, elija un mensaje de confirmación muy bueno y empuje a GitHub. Haga la solicitud de extracción entonces.

Después de la fusión de la solicitud de extracción, puede eliminarla localmente:

$ git branch -d mybranch

y en GitHub

$ git push origin :mybranch
Martin Thoma
fuente
" que debería ser solo un commit en la rama maestra ", bueno, no necesariamente; quizás quieras mantener la historia
Cocowalla
Por supuesto. Pero entonces simplemente no aplastar a los commits
Martin Thoma
Creo que el primer padre parece ser la mejor solución. davidchudzicki.com/posts/first-parent
bkribbs
7

Hilo antiguo, pero no he encontrado mi manera de hacerlo. Puede ser valioso para alguien que trabaja con rebase y quiere fusionar todos los commits de una rama (característica) en la parte superior del master. Si hay un conflicto en el camino, puede resolverlos para cada confirmación. Mantiene el control total durante el proceso y puede abortar en cualquier momento.

Obtenga Master y Branch actualizados:

git checkout master
git pull --rebase origin master
git checkout <branch_name>
git pull --rebase origin <branch_name>

Fusionar rama encima del maestro:

git checkout <branch_name>
git rebase master

Opcional: si se encuentra con conflictos durante la rebase:

Primero, resuelva el conflicto en el archivo. Entonces:

git add .
git rebase --continue

Empuje su rama rebasada:

git push origin <branch_name>

Ahora tienes dos opciones:

  • A) Cree un PR (por ejemplo, en GitHub) y fusione allí a través de la IU
  • B) Regrese a la línea de comando y combine la rama en maestra
git checkout master
git merge --no-ff <branch_name>
git push origin master

Hecho.

Robin Wieruch
fuente
6

Este es el flujo de trabajo que uso en mi trabajo con el equipo. El escenario es como lo describiste. Primero, cuando testtermino de trabajar en Rebasar con master para obtener todo lo que se ha agregado a master durante el tiempo que he estado trabajando en la testrama.

git pull -r upstream master

Esto extraerá los cambios al maestro ya que bifurcó la testrama y los aplicó, y luego aplicará los cambios que ha realizado para probar "encima" del estado actual del maestro. Puede haber conflictos aquí, si las otras personas han realizado cambios en los mismos archivos que ha editado en la prueba. Si los hay, deberá corregirlos manualmente y confirmar. Una vez que haya hecho eso, será bueno cambiar a la rama maestra y fusionarse testsin problemas.

djheru
fuente
3
git checkout master
git pull origin master
# Merge branch test into master
git merge test

Después de fusionar, si se cambia el archivo, cuando lo fusione se producirá un error de "Resolver conflicto"

Entonces, primero debe resolver todos sus conflictos, luego debe confirmar nuevamente todos sus cambios y luego presionar

git push origin master

Es mejor hacer quién ha hecho cambios en la rama de prueba, porque sabía qué cambios había hecho.

Vinay Sikarwar
fuente
3

Usaría el método de rebase. Principalmente porque refleja perfectamente su caso semánticamente, es decir. lo que desea hacer es actualizar el estado de su sucursal actual y "simular" como si se basara en la última.

Entonces, sin siquiera revisar master, yo haría:

git fetch origin
git rebase -i origin/master
# ...solve possible conflicts here

Por supuesto, solo buscar desde el origen no actualiza el estado local de su master(ya que no realiza una fusión), pero está perfectamente bien para nuestro propósito: queremos evitar cambiar, en aras de ahorrar tiempo.

usuario776686
fuente
2

La respuesta de @ KingCrunch debería funcionar en muchos casos. Un problema que puede surgir es que puede estar en una máquina diferente que necesita extraer lo último de la prueba. Por lo tanto, recomiendo hacer la prueba primero. La revisión se ve así:

git checkout test
git pull
git checkout master
git pull origin master
git merge test
git push origin master
cgnorthcutt
fuente
0

Debe extraer la rama para extraer, ya que extraer significa fusionarse con el maestro, y necesita un árbol de trabajo para fusionarse.

git checkout master
git pull

No es necesario verificar primero; rebase hace lo correcto con dos argumentos

git rebase master test  

git checkout master
git merge test

git push por defecto empuja todas las ramas que existen aquí y en el control remoto

git push
git checkout test
Masoud Mokhtari
fuente
0

Como el título dice "Mejor manera", creo que es una buena idea considerar la estrategia de fusión de paciencia .

De: https://git-scm.com/docs/merge-strategies

Con esta opción, 'fusionar-recursivo' pasa un poco más de tiempo para evitar errores de combinación que a veces ocurren debido a líneas de coincidencia no importantes (por ejemplo, llaves de funciones distintas). Use esto cuando las ramas que se fusionarán hayan divergido salvajemente. Ver también git-diff [1] --patience.

Uso:

git fetch
git merge -s recursive -X patience origin/master

Git Alias

Siempre uso un alias para esto, por ejemplo, ejecutar una vez:

 git config --global alias.pmerge 'merge -s recursive -X patience'

Ahora puedes hacer:

git fetch
git pmerge origin/master
Julian
fuente
0

Esto es de GitLab: solo siga las instrucciones:

ingrese la descripción de la imagen aquí

shdr
fuente
0

Contestaré según desarrollar y presentar ramas,

si está en la rama de características y necesita actualizarlo con el desarrollo, use los siguientes comandos: git checkout desarrollo git pull git checkout característica / xyz git merge desarrollo

Ahora que su característica se actualiza con desarrollo, puede impulsar sus cambios.

omkar
fuente