Convertir la rama actual de Git en una rama maestra

1657

Tengo un repositorio en Git. Hice una rama, luego hice algunos cambios tanto en el maestro como en la rama.

Luego, decenas de confirmaciones más tarde, me di cuenta de que la rama está en un estado mucho mejor que el maestro, así que quiero que la rama se "convierta" en el maestro y no tenga en cuenta los cambios en el maestro.

No puedo fusionarlo, porque no quiero mantener los cambios en master. ¿Qué tengo que hacer?

Extra : en este caso, el maestro 'viejo' ya ha sido pushenviado a otro repositorio como GitHub. ¿Cómo cambia esto las cosas?

Karel Bílek
fuente
2
Compruebe las respuestas a la pregunta muy similar stackoverflow.com/q/2862590/151641
mloskot
44
Tuve el mismo problema, sin embargo, simplemente eliminé el maestro y
cambié el
10
@jayarjo, debe evitar esto si es posible, porque reescribirá el historial y causará problemas a todos los demás la próxima vez que intenten obtener el master.
joelittlejohn
3
Por eso me encanta la respuesta de @Jefromi. No hay deconstrucción de la historia del archivo.
froggythefrog

Respuestas:

2134

El problema con las otras dos respuestas es que el nuevo maestro no tiene al viejo maestro como antepasado, por lo que cuando lo presionas, todos los demás se equivocarán. Esto es lo que quieres hacer:

git checkout better_branch
git merge --strategy=ours master    # keep the content of this branch, but record a merge
git checkout master
git merge better_branch             # fast-forward master up to the merge

Si desea que su historial sea un poco más claro, le recomiendo agregar información al mensaje de confirmación de fusión para que quede claro lo que ha hecho. Cambia la segunda línea a:

git merge --strategy=ours --no-commit master
git commit          # add information to the template merge message
Cascabel
fuente
25
Nota sobre las "estrategias" de fusión de git: --strategy=ourses diferente de --strategy=recursive -Xours. Es decir, "la nuestra" puede ser una estrategia en sí misma (el resultado será la rama actual, pase lo que pase), o pasar como una opción a la estrategia "recursiva" (incorporar los cambios de otra rama y preferir automáticamente los cambios de la rama actual cuando hay un conflicto) )
Kelvin
55
Tuve que hacer la segunda línea git merge --strategy=ours master -m "new master"para que funcione.
incandescentman
55
@Johsm Eso es exactamente de lo que habla la primera oración de mi respuesta. Si haces eso, el nuevo maestro no tendrá el mismo historial que el viejo maestro, lo cual es muy malo si quieres empujar / tirar. Necesitas haber compartido ascendencia para que funcione correctamente; si, en cambio, haces lo que dices, cuando intentes presionarlo, simplemente fallará a menos que lo fuerces (porque esto es malo y está tratando de detenerte), y si lo haces, cualquier persona que posteriormente tire intentará fusionar el viejo maestro y el nuevo maestro, lo que probablemente será un choque de trenes.
Cascabel
44
Si aparece el editor vi durante la fusión, escriba: w (para guardar): q (para salir de vi)
Tomas Kubes
99
Esta respuesta funciona muy bien. Solo quería agregar (para las personas que pueden ser nuevas o inseguras) que tendrá que hacer un git pushderecho después de esto si desea que su código se transfiera al control remoto. Es posible que vea una advertencia como Your branch is ahead of 'origin/master' by 50 commits.Se espera esto. ¡Solo empújalo! : D
chapeljuice
388

Asegúrese de que todo esté en su repositorio remoto (GitHub):

git checkout master

Sobrescriba "master" con "better_branch":

git reset --hard better_branch

Fuerce el empuje a su repositorio remoto:

git push -f origin master
Brandon Howard
fuente
81
Esta es probablemente la respuesta que la mayoría de la gente está buscando. Todas las otras respuestas con la combinación de estrategia BS no reemplazan la rama por completo. Esto hizo todo lo que quería, simplemente sobrescribir la rama y empujarla hacia arriba.
Gubatron
31
Aunque esto es lo que muchos están buscando, debe tenerse en cuenta que cualquier otra copia local del repositorio necesitará la git reset --hard origin/masterpróxima vez que quieran obtenerla, de lo contrario, git intentará fusionar los cambios en su (ahora) local divergente. Los peligros de esto se explican más en esta respuesta
7yl4r
3
Tenga en cuenta también que es necesario que se le permitiera fuerza de empuje al repositorio - por ejemplo, en un entorno empresarial este no funcionará
inetphantom
La ventaja aquí también puede ser una desventaja dependiendo de lo que la gente quiera. Si desea ir tan lejos como reemplazar la historia del maestro con la historia de la otra rama, esta es su respuesta.
b15
75

Editar: ¡No dijiste que había empujado a un repositorio público! Eso hace un mundo de diferencia.

Hay dos formas, la "sucia" y la "limpia". Supongamos que su rama se llama new-master. Esta es la forma limpia:

git checkout new-master
git branch -m master old-master
git branch -m new-master master
# And don't do this part.  Just don't.  But if you want to...
# git branch -d --force old-master

Esto hará que los archivos de configuración cambien para que coincidan con las ramas renombradas.

También puede hacerlo de la manera sucia, lo que no actualizará los archivos de configuración. Esto es lo que sucede bajo el capó de lo anterior ...

mv -i .git/refs/new-master .git/refs/master
git checkout master
Dietrich Epp
fuente
2
Gracias. Una pregunta más. Lo estoy empujando a github. ¿Qué pasará allí si hago esto?
Karel Bílek
3
@Karel: creará un poco de desorden para otros usuarios; Tendrán que restablecer su maestro al maestro Github. Si quieres evitar causarles problemas, mira mi respuesta.
Cascabel
66
@Dietrick Epp: no estoy seguro de si es una buena idea incluso sugerir el camino sucio. Va a estropear el seguimiento remoto, los reflogs ... no se me ocurre ninguna razón por la que alguna vez lo harías.
Cascabel
2
Ah, ese es un buen punto. Puede tener las dos cosas, sin embargo: git branch old-master master; git branch -f master new-master. Cree la rama de copia de seguridad nueva, luego mueva directamente maestro a maestro nuevo. (Y perdón por escribir mal su nombre, acabo de notar eso)
Cascabel
2
@FakeName No concluí que no había razón para hacerlo, solo que no hay razón para hacerlo de la manera sucia . Puede hacerlo usando comandos normales (como en mi comentario anterior) y obtener el mismo resultado, excepto con los registros intactos y sin posibilidad de descifrar las cosas. Y está garantizado que funcionará, ya que no te estás burlando de los detalles de implementación.
Cascabel
46

Cambie el nombre de la rama masterpor:

git branch -M branch_name master
Alan Haggai Alavi
fuente
11
Desafortunadamente, git no rastrea los cambios de rama, por lo que si ya ha llevado su repositorio a un control remoto y otros tienen cambios locales en su antigua rama maestra local, estarán en problemas.
Jueves
¿Hay alguna diferencia entre esto y git checkout master&&git reset --hard better_branch?
wotanii
26

Por lo que entiendo, puede ramificar la rama actual en una rama existente. En esencia, esto sobrescribirá mastercon lo que tenga en la rama actual:

git branch -f master HEAD

Una vez que haya hecho eso, normalmente puede empujar su masterrama local , posiblemente requiriendo el parámetro de fuerza aquí también:

git push -f origin master

Sin fusiones, sin comandos largos. Simplemente branchy push, pero sí, esto reescribirá el historial de la mastersucursal, por lo que si trabaja en un equipo debe saber lo que está haciendo.




Alternativamente, descubrí que puede empujar cualquier rama a cualquier rama remota, así que

# This will force push the current branch to the remote master
git push -f origin HEAD:master

# Switch current branch to master
git checkout master

# Reset the local master branch to what's on the remote
git reset --hard origin/master
fregante
fuente
Muy simple y funcionó perfectamente! Dos comandos git simples y fáciles de entender. Mi repositorio de git está guardado y ahora se ve súper limpio. ¡Gracias!
thehelix el
16

Encontré la respuesta que quería en la publicación del blog Reemplace la rama maestra con otra rama en git :

git checkout feature_branch
git merge -s ours --no-commit master
git commit      # Add a message regarding the replacement that you just did
git checkout master
git merge feature_branch

Es esencialmente lo mismo que la respuesta de Cascabel . Excepto que la "opción" que agregó a continuación su solución ya está incrustada en mi bloque de código principal.

Es más fácil encontrarlo de esta manera.

Estoy agregando esto como una nueva respuesta, porque si necesito esta solución más adelante, quiero tener todo el código que voy a usar en un bloque de código.

De lo contrario, puedo copiar y pegar, luego leer los detalles a continuación para ver la línea que debería haber cambiado, después de haberlo ejecutado.

SherylHohman
fuente
14

Las soluciones dadas aquí (renombrando la rama en 'maestro') no insisten en las consecuencias para el repositorio remoto (GitHub):

    -F
    --fuerza

Por lo general, el comando se niega a actualizar una referencia remota que no sea un antecesor de la referencia local utilizada para sobrescribirla. Esta bandera deshabilita el cheque. Esto puede hacer que el repositorio remoto pierda confirmaciones; úsalo con cuidado.

Si otros ya han retirado su repositorio, no podrán extraer ese nuevo historial maestro sin reemplazar su propio maestro con esa nueva rama maestra de GitHub (o tratar con muchas fusiones).
Hay alternativas a un git push --force para repos públicos .
La respuesta de Jefromi (fusionar los cambios correctos con el maestro original) es una de ellas.

VonC
fuente
14

Encontré este método simple para trabajar mejor. No reescribe el historial y todos los registros anteriores de la sucursal se agregarán al maestro. No se pierde nada y puede ver claramente lo que ocurrió en el registro de confirmación.

Objetivo: Convertir el estado actual de "rama" en "maestro"

Al trabajar en una sucursal, confirme y envíe sus cambios para asegurarse de que sus repositorios locales y remotos estén actualizados:

git checkout master      # Set local repository to master
git reset --hard branch  # Force working tree and index to branch
git push origin master    # Update remote repository

Después de esto, su maestro será el estado exacto de su última confirmación de rama y su registro de confirmación maestra mostrará todos los registros de la rama.

Mark Dietel
fuente
10

También se puede retirar todos los archivos de la otra rama al maestro:

git checkout master
git checkout better_branch -- .

y luego cometer todos los cambios.

usuario2064284
fuente
5

Para agregar a la respuesta de Jefromi, si no desea colocar una fusión sin sentido en el historial de la sourcerama, puede crear una rama temporal para la oursfusión y luego tirarla:

git checkout <source>
git checkout -b temp            # temporary branch for merge
git merge -s ours <target>      # create merge commit with contents of <source>
git checkout <target>           # fast forward <target> to merge commit
git merge temp                  # ...
git branch -d temp              # throw temporary branch away

De esa forma, la confirmación de fusión solo existirá en la historia de la target rama.

Alternativamente, si no desea crear una fusión, simplemente puede tomar el contenido sourcey usarlos para una nueva confirmación en target:

git checkout <source>                          # fill index with contents of <source>
git symbolic-ref HEAD <target>                 # tell git we're committing on <target>
git commit -m "Setting contents to <source>"   # make an ordinary commit with the contents of <source>
staafl
fuente
3

Para mí, quería que mi devl volviera al maestro después de que estuviera por delante.

Mientras está en desarrollo:

git checkout master
git pull

git checkout develop
git pull

git reset --hard origin/master
git push -f
Braden Borman
fuente
2

Mi forma de hacer las cosas es la siguiente

#Backup branch
git checkout -b master_backup
git push origin master_backup
git checkout master
#Hard Reset master branch to the last common commit
git reset --hard e8c8597
#Merge
git merge develop
ar-g
fuente
2

Si está utilizando eGit en Eclipse :

  • Haga clic derecho en el nodo del proyecto.
  • Elija Equipo → luego Avanzado → luego Cambiar nombre de rama
  • Luego expanda la carpeta de seguimiento remoto .
  • Elija la rama con el nombre incorrecto, luego haga clic en el botón Cambiar nombre, cambie el nombre a cualquier nombre nuevo.
  • Elija el nuevo maestro, luego cámbiele el nombre a maestro.
Junchen Liu
fuente
Lo hice pero no estoy seguro de si funcionó. En github, nada cambió, pero en las extensiones de git puedo ver que se cambió el nombre de la rama.
Pramod el
0

Los siguientes pasos se realizan en el navegador Git con tecnología de Atlassian (servidor Bitbucket)

Haciendo {current-branch} como master

  1. Crea una rama mastery nómbrala "master-duplicate".
  2. Haga una rama de {current-branch} y asígnele el nombre "{current-branch} -copy".
  3. En la configuración del repositorio (Bitbucket) cambie "Rama predeterminada" para que apunte a "duplicado maestro" (sin este paso, no podrá eliminar el maestro - "En el siguiente paso").
  4. Eliminar la rama "maestra": hice este paso desde el árbol de origen (puede hacerlo desde la CLI o el navegador Git)
  5. Cambie el nombre de "{current-branch}" a "master" y presione al repositorio (esto creará una nueva rama "master" aún existirá "{current-branch}").
  6. En la configuración del repositorio, cambie "Rama predeterminada" para que apunte a "maestro".
Purushothaman
fuente